FFmpeg
Loading...
Searching...
No Matches
hwcontext_vulkan.c
Go to the documentation of this file.
1/*
2 * Copyright (c) Lynne
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#define VK_NO_PROTOTYPES
22#define VK_ENABLE_BETA_EXTENSIONS
23
24#ifdef _WIN32
25#include <windows.h> /* Included to prevent conflicts with CreateSemaphore */
26#include <versionhelpers.h>
27#include "compat/w32dlfcn.h"
28#else
29#include <dlfcn.h>
30#include <unistd.h>
31#endif
32
33#include "thread.h"
34
35#include "config.h"
36#include "pixdesc.h"
37#include "avstring.h"
38#include "imgutils.h"
39#include "hwcontext.h"
40#include "hwcontext_internal.h"
41#include "hwcontext_vulkan.h"
42#include "mem.h"
43
44#include "vulkan.h"
45#include "vulkan_loader.h"
46
47#if CONFIG_VAAPI
48#include "hwcontext_vaapi.h"
49#endif
50
51#if CONFIG_LIBDRM
52#if CONFIG_VAAPI
53#include <va/va_drmcommon.h>
54#endif
55#ifdef __linux__
56#include <sys/sysmacros.h>
57#endif
58#include <sys/stat.h>
59#include <xf86drm.h>
60#include <drm_fourcc.h>
61#include "hwcontext_drm.h"
62#endif
63
64#if HAVE_LINUX_DMA_BUF_H
65#include <sys/ioctl.h>
66#include <linux/dma-buf.h>
67#endif
68
69#if CONFIG_CUDA
71#include "cuda_check.h"
72#define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x)
73#endif
74
75typedef struct VulkanDeviceFeatures {
76 VkPhysicalDeviceFeatures2 device;
77
78 VkPhysicalDeviceVulkan11Features vulkan_1_1;
79 VkPhysicalDeviceVulkan12Features vulkan_1_2;
80 VkPhysicalDeviceVulkan13Features vulkan_1_3;
81 VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore;
82 VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR subgroup_rotate;
83 VkPhysicalDeviceHostImageCopyFeaturesEXT host_image_copy;
84 VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR explicit_mem_layout;
85
86#ifdef VK_EXT_shader_long_vector
87 VkPhysicalDeviceShaderLongVectorFeaturesEXT long_vector;
88#endif
89
90#ifdef VK_EXT_shader_replicated_composites
91 VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT replicated_composites;
92#endif
93
94#ifdef VK_EXT_zero_initialize_device_memory
95 VkPhysicalDeviceZeroInitializeDeviceMemoryFeaturesEXT zero_initialize;
96#endif
97
98#ifdef VK_KHR_shader_expect_assume
99 VkPhysicalDeviceShaderExpectAssumeFeaturesKHR expect_assume;
100#endif
101
102#ifdef VK_KHR_shader_maximal_reconvergence
103 VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR maximal_reconvergence;
104#endif
105
106#ifdef VK_KHR_maintenance9
107 VkPhysicalDeviceMaintenance9FeaturesKHR maintenance_9;
108#endif
109#ifdef VK_KHR_unified_image_layouts
110 VkPhysicalDeviceUnifiedImageLayoutsFeaturesKHR unified_layouts;
111#endif
112
113 VkPhysicalDeviceVideoMaintenance1FeaturesKHR video_maintenance_1;
114#ifdef VK_KHR_video_maintenance2
115 VkPhysicalDeviceVideoMaintenance2FeaturesKHR video_maintenance_2;
116#endif
117#ifdef VK_KHR_video_decode_vp9
118 VkPhysicalDeviceVideoDecodeVP9FeaturesKHR vp9_decode;
119#endif
120#ifdef VK_KHR_video_encode_av1
121 VkPhysicalDeviceVideoEncodeAV1FeaturesKHR av1_encode;
122#endif
123
124 VkPhysicalDeviceShaderObjectFeaturesEXT shader_object;
125 VkPhysicalDeviceCooperativeMatrixFeaturesKHR cooperative_matrix;
126 VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float;
127
128#ifdef VK_KHR_shader_relaxed_extended_instruction
129 VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR relaxed_extended_instruction;
130#endif
131
132#ifdef VK_KHR_internally_synchronized_queues
133 VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR internal_queue_sync;
134#endif
136
137typedef struct VulkanDevicePriv {
138 /**
139 * The public AVVulkanDeviceContext. See hwcontext_vulkan.h for it.
140 */
142
143 /* Vulkan library and loader functions */
145
149
150 /* Properties */
151 VkPhysicalDeviceProperties2 props;
152 VkPhysicalDeviceMemoryProperties mprops;
153 VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops;
154 VkPhysicalDeviceDriverProperties dprops;
155
156 /* Opaque FD external semaphore properties */
157 VkExternalSemaphoreProperties ext_sem_props_opaque;
158
159 /* Enabled features */
161
162 /* Queues */
164 uint32_t nb_tot_qfs;
165 uint32_t img_qfs[64];
166 uint32_t nb_img_qfs;
167
168 /* Debug callback */
169 VkDebugUtilsMessengerEXT debug_ctx;
170
171 /* Settings */
173
174 /* Option to allocate all image planes in a single allocation */
176
177 /* Disable multiplane images */
179
180 /* Prefer memcpy over dynamic host pointer imports */
182
183 /* Maximum queues */
186
187typedef struct VulkanFramesPriv {
188 /**
189 * The public AVVulkanFramesContext. See hwcontext_vulkan.h for it.
190 */
192
193 /* Image conversions */
195
196 /* Image transfers */
199
200 /* Temporary buffer pools */
202
203 /* Modifier info list to free at uninit */
204 VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
205
206 /* Properties for DRM modifier for each plane in the image */
207 VkDrmFormatModifierPropertiesEXT drm_format_modifier_properties[5];
208
209 /* Set when physical device reports DEDICATED_ONLY for DMA-BUF export (try_export_flags) */
212
213typedef struct AVVkFrameInternal {
215
216 /* Binary semaphore for SYNC_FD export at DRM map time. Created once lazily,
217 * re-signaled each time via a submit in vulkan_map_to_drm. */
218 VkSemaphore drm_sync_sem;
219
220#if CONFIG_CUDA
221 /* Importing external memory into cuda is really expensive so we keep the
222 * memory imported all the time */
223 AVBufferRef *cuda_fc_ref; /* Need to keep it around for uninit */
224 CUexternalMemory ext_mem[AV_NUM_DATA_POINTERS];
225 CUmipmappedArray cu_mma[AV_NUM_DATA_POINTERS];
226 CUarray cu_array[AV_NUM_DATA_POINTERS];
227 CUexternalSemaphore cu_sem[AV_NUM_DATA_POINTERS];
228#ifdef _WIN32
229 HANDLE ext_mem_handle[AV_NUM_DATA_POINTERS];
230 HANDLE ext_sem_handle[AV_NUM_DATA_POINTERS];
231#endif
232#endif
234
235/* Initialize all structs in VulkanDeviceFeatures */
237{
238 VulkanDevicePriv *p = ctx->hwctx;
239 FFVulkanContext *s = &p->vkctx;
240
241 feats->device = (VkPhysicalDeviceFeatures2) {
242 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
243 };
244
246 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES);
248 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES);
250 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES);
251
253 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES);
255 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR);
257 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT);
258
259#ifdef VK_EXT_shader_long_vector
260 FF_VK_STRUCT_EXT(s, &feats->device, &feats->long_vector, FF_VK_EXT_LONG_VECTOR,
261 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_FEATURES_EXT);
262#endif
263
264#ifdef VK_EXT_shader_replicated_composites
265 FF_VK_STRUCT_EXT(s, &feats->device, &feats->replicated_composites, FF_VK_EXT_REPLICATED_COMPOSITES,
266 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_REPLICATED_COMPOSITES_FEATURES_EXT);
267#endif
268
269#ifdef VK_EXT_zero_initialize_device_memory
270 FF_VK_STRUCT_EXT(s, &feats->device, &feats->zero_initialize, FF_VK_EXT_ZERO_INITIALIZE,
271 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_DEVICE_MEMORY_FEATURES_EXT);
272#endif
273
274#ifdef VK_KHR_shader_expect_assume
275 FF_VK_STRUCT_EXT(s, &feats->device, &feats->expect_assume, FF_VK_EXT_EXPECT_ASSUME,
276 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR);
277#endif
278
279#ifdef VK_KHR_shader_maximal_reconvergence
280 FF_VK_STRUCT_EXT(s, &feats->device, &feats->maximal_reconvergence, FF_VK_EXT_MAXIMAL_RECONVERGENCE,
281 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MAXIMAL_RECONVERGENCE_FEATURES_KHR);
282#endif
283
284#ifdef VK_KHR_maintenance9
285 FF_VK_STRUCT_EXT(s, &feats->device, &feats->maintenance_9, FF_VK_EXT_MAINTENANCE_9,
286 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_FEATURES_KHR);
287#endif
288#ifdef VK_KHR_unified_image_layouts
289 FF_VK_STRUCT_EXT(s, &feats->device, &feats->unified_layouts, FF_VK_EXT_UNIFIED_IMAGE_LAYOUTS,
290 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFIED_IMAGE_LAYOUTS_FEATURES_KHR);
291#endif
292
294 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR);
295#ifdef VK_KHR_video_maintenance2
296 FF_VK_STRUCT_EXT(s, &feats->device, &feats->video_maintenance_2, FF_VK_EXT_VIDEO_MAINTENANCE_2,
297 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR);
298#endif
299#ifdef VK_KHR_video_decode_vp9
300 FF_VK_STRUCT_EXT(s, &feats->device, &feats->vp9_decode, FF_VK_EXT_VIDEO_DECODE_VP9,
301 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR);
302#endif
303#ifdef VK_KHR_video_encode_av1
304 FF_VK_STRUCT_EXT(s, &feats->device, &feats->av1_encode, FF_VK_EXT_VIDEO_ENCODE_AV1,
305 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_AV1_FEATURES_KHR);
306#endif
307
309 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT);
311 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR);
313 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT);
315 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR);
316
317#ifdef VK_KHR_shader_relaxed_extended_instruction
318 FF_VK_STRUCT_EXT(s, &feats->device, &feats->relaxed_extended_instruction, FF_VK_EXT_RELAXED_EXTENDED_INSTR,
319 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR);
320#endif
321
322#ifdef VK_KHR_internally_synchronized_queues
323 FF_VK_STRUCT_EXT(s, &feats->device, &feats->internal_queue_sync, FF_VK_EXT_INTERNAL_QUEUE_SYNC,
324 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INTERNALLY_SYNCHRONIZED_QUEUES_FEATURES_KHR);
325#endif
326}
327
328/* Copy all needed device features */
330{
331#define COPY_VAL(VAL) \
332 do { \
333 dst->VAL = src->VAL; \
334 } while (0) \
335
336 COPY_VAL(device.features.shaderImageGatherExtended);
337 COPY_VAL(device.features.shaderStorageImageReadWithoutFormat);
338 COPY_VAL(device.features.shaderStorageImageWriteWithoutFormat);
339 COPY_VAL(device.features.fragmentStoresAndAtomics);
340 COPY_VAL(device.features.vertexPipelineStoresAndAtomics);
341 COPY_VAL(device.features.shaderInt64);
342 COPY_VAL(device.features.shaderInt16);
343 COPY_VAL(device.features.shaderFloat64);
344 COPY_VAL(device.features.shaderStorageImageReadWithoutFormat);
345 COPY_VAL(device.features.shaderStorageImageWriteWithoutFormat);
346
347 COPY_VAL(vulkan_1_1.samplerYcbcrConversion);
348 COPY_VAL(vulkan_1_1.storagePushConstant16);
349 COPY_VAL(vulkan_1_1.storageBuffer16BitAccess);
350 COPY_VAL(vulkan_1_1.uniformAndStorageBuffer16BitAccess);
351
352 COPY_VAL(vulkan_1_2.timelineSemaphore);
353 COPY_VAL(vulkan_1_2.scalarBlockLayout);
354 COPY_VAL(vulkan_1_2.bufferDeviceAddress);
355 COPY_VAL(vulkan_1_2.hostQueryReset);
356 COPY_VAL(vulkan_1_2.storagePushConstant8);
357 COPY_VAL(vulkan_1_2.shaderInt8);
358 COPY_VAL(vulkan_1_2.storageBuffer8BitAccess);
359 COPY_VAL(vulkan_1_2.uniformAndStorageBuffer8BitAccess);
360 COPY_VAL(vulkan_1_2.shaderFloat16);
361 COPY_VAL(vulkan_1_2.shaderBufferInt64Atomics);
362 COPY_VAL(vulkan_1_2.shaderSharedInt64Atomics);
363 COPY_VAL(vulkan_1_2.vulkanMemoryModel);
364 COPY_VAL(vulkan_1_2.vulkanMemoryModelDeviceScope);
365 COPY_VAL(vulkan_1_2.vulkanMemoryModelAvailabilityVisibilityChains);
366 COPY_VAL(vulkan_1_2.uniformBufferStandardLayout);
367 COPY_VAL(vulkan_1_2.runtimeDescriptorArray);
368 COPY_VAL(vulkan_1_2.shaderSubgroupExtendedTypes);
369 COPY_VAL(vulkan_1_2.shaderUniformBufferArrayNonUniformIndexing);
370 COPY_VAL(vulkan_1_2.shaderSampledImageArrayNonUniformIndexing);
371 COPY_VAL(vulkan_1_2.shaderStorageBufferArrayNonUniformIndexing);
372 COPY_VAL(vulkan_1_2.shaderStorageImageArrayNonUniformIndexing);
373
374 COPY_VAL(vulkan_1_3.dynamicRendering);
375 COPY_VAL(vulkan_1_3.maintenance4);
376 COPY_VAL(vulkan_1_3.synchronization2);
377 COPY_VAL(vulkan_1_3.computeFullSubgroups);
378 COPY_VAL(vulkan_1_3.subgroupSizeControl);
379 COPY_VAL(vulkan_1_3.shaderZeroInitializeWorkgroupMemory);
380 COPY_VAL(vulkan_1_3.dynamicRendering);
381
382 COPY_VAL(timeline_semaphore.timelineSemaphore);
383 COPY_VAL(subgroup_rotate.shaderSubgroupRotate);
384 COPY_VAL(host_image_copy.hostImageCopy);
385
386#ifdef VK_EXT_shader_long_vector
387 COPY_VAL(long_vector.longVector);
388#endif
389
390#ifdef VK_EXT_shader_replicated_composites
391 COPY_VAL(replicated_composites.shaderReplicatedComposites);
392#endif
393
394#ifdef VK_EXT_zero_initialize_device_memory
395 COPY_VAL(zero_initialize.zeroInitializeDeviceMemory);
396#endif
397
398 COPY_VAL(video_maintenance_1.videoMaintenance1);
399#ifdef VK_KHR_video_maintenance2
400 COPY_VAL(video_maintenance_2.videoMaintenance2);
401#endif
402
403#ifdef VK_KHR_video_decode_vp9
404 COPY_VAL(vp9_decode.videoDecodeVP9);
405#endif
406
407#ifdef VK_KHR_video_encode_av1
408 COPY_VAL(av1_encode.videoEncodeAV1);
409#endif
410
411 COPY_VAL(shader_object.shaderObject);
412
413 COPY_VAL(cooperative_matrix.cooperativeMatrix);
414
415 COPY_VAL(atomic_float.shaderBufferFloat32Atomics);
416 COPY_VAL(atomic_float.shaderBufferFloat32AtomicAdd);
417
418 COPY_VAL(explicit_mem_layout.workgroupMemoryExplicitLayout);
419 COPY_VAL(explicit_mem_layout.workgroupMemoryExplicitLayoutScalarBlockLayout);
420 COPY_VAL(explicit_mem_layout.workgroupMemoryExplicitLayout8BitAccess);
421 COPY_VAL(explicit_mem_layout.workgroupMemoryExplicitLayout16BitAccess);
422
423#ifdef VK_KHR_shader_relaxed_extended_instruction
424 COPY_VAL(relaxed_extended_instruction.shaderRelaxedExtendedInstruction);
425#endif
426
427#ifdef VK_KHR_shader_expect_assume
428 COPY_VAL(expect_assume.shaderExpectAssume);
429#endif
430
431#ifdef VK_KHR_shader_maximal_reconvergence
432 COPY_VAL(maximal_reconvergence.shaderMaximalReconvergence);
433#endif
434
435#ifdef VK_KHR_maintenance9
436 COPY_VAL(maintenance_9.maintenance9);
437#endif
438#ifdef VK_KHR_unified_image_layouts
439 COPY_VAL(unified_layouts.unifiedImageLayouts);
440 COPY_VAL(unified_layouts.unifiedImageLayoutsVideo);
441#endif
442
443#ifdef VK_KHR_internally_synchronized_queues
444 COPY_VAL(internal_queue_sync.internallySynchronizedQueues);
445#endif
446
447#undef COPY_VAL
448}
449
450#define ASPECT_2PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT)
451#define ASPECT_3PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)
452
462 /* Gray formats */
463 { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GRAY8, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8_UNORM } },
464 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GRAY10, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16_UNORM } },
465 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GRAY12, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16_UNORM } },
466 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GRAY14, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16_UNORM } },
467 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GRAY16, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16_UNORM } },
468 { VK_FORMAT_R32_UINT, AV_PIX_FMT_GRAY32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32_UINT } },
469 { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GRAYF32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32_SFLOAT } },
470
471 /* RGB formats */
472 { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_BGRA, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
473 { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGBA, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
474 { VK_FORMAT_R8G8B8_UNORM, AV_PIX_FMT_RGB24, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8_UNORM } },
475 { VK_FORMAT_B8G8R8_UNORM, AV_PIX_FMT_BGR24, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_B8G8R8_UNORM } },
476 { VK_FORMAT_R16G16B16_UNORM, AV_PIX_FMT_RGB48, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16_UNORM } },
477 { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_RGBA64, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
478 { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_BGR0, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
479 { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGB0, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
480 { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_X2RGB10, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 } },
481 { VK_FORMAT_A2B10G10R10_UNORM_PACK32, AV_PIX_FMT_X2BGR10, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_A2B10G10R10_UNORM_PACK32 } },
482 { VK_FORMAT_R32G32B32_SFLOAT, AV_PIX_FMT_RGBF32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32G32B32_SFLOAT } },
483 { VK_FORMAT_R16G16B16A16_SFLOAT, AV_PIX_FMT_RGBAF16, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_SFLOAT } },
484 { VK_FORMAT_R32G32B32A32_SFLOAT, AV_PIX_FMT_RGBAF32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32G32B32A32_SFLOAT } },
485 { VK_FORMAT_R32G32B32_UINT, AV_PIX_FMT_RGB96, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32G32B32_UINT } },
486 { VK_FORMAT_R32G32B32A32_UINT, AV_PIX_FMT_RGBA128, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32G32B32A32_UINT } },
487
488 /* Planar RGB */
489 { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GBRP, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
490 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRP10, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
491 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRP12, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
492 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRP14, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
493 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRP16, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
494 { VK_FORMAT_R16_SFLOAT, AV_PIX_FMT_GBRPF16, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R16_SFLOAT, VK_FORMAT_R16_SFLOAT, VK_FORMAT_R16_SFLOAT } },
495 { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GBRPF32, VK_IMAGE_ASPECT_COLOR_BIT, 3, 3, 3, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
496
497 /* Planar RGB + Alpha */
498 { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GBRAP, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
499 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAP10, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
500 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAP12, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
501 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAP14, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
502 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAP16, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
503 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAPF16, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
504 { VK_FORMAT_R32_UINT, AV_PIX_FMT_GBRAP32, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R32_UINT, VK_FORMAT_R32_UINT, VK_FORMAT_R32_UINT, VK_FORMAT_R32_UINT } },
505 { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GBRAPF32, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
506
507 /* Bayer */
508 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_BAYER_RGGB16, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16_UNORM } },
509
510 /* Two-plane 420 YUV at 8, 10, 12 and 16 bits */
511 { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, AV_PIX_FMT_NV12, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
512 { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, AV_PIX_FMT_P010, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
513 { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, AV_PIX_FMT_P012, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
514 { VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, AV_PIX_FMT_P016, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
515
516 /* Two-plane 422 YUV at 8, 10 and 16 bits */
517 { VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, AV_PIX_FMT_NV16, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
518 { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, AV_PIX_FMT_P210, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
519 { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, AV_PIX_FMT_P212, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
520 { VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, AV_PIX_FMT_P216, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
521
522 /* Two-plane 444 YUV at 8, 10 and 16 bits */
523 { VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, AV_PIX_FMT_NV24, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
524 { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, AV_PIX_FMT_P410, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
525 { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, AV_PIX_FMT_P412, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
526 { VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, AV_PIX_FMT_P416, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
527
528 /* Three-plane 420, 422, 444 at 8, 10, 12 and 16 bits */
529 { VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
530 { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P10, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
531 { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P12, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
532 { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P16, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
533 { VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
534 { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P10, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
535 { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P12, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
536 { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P16, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
537 { VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
538 { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P10, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
539 { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P12, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
540 { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P16, ASPECT_3PLANE, 3, 1, 3, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
541
542 /* Single plane 422 at 8, 10, 12 and 16 bits */
543 { VK_FORMAT_G8B8G8R8_422_UNORM, AV_PIX_FMT_YUYV422, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
544 { VK_FORMAT_B8G8R8G8_422_UNORM, AV_PIX_FMT_UYVY422, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
545 { VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, AV_PIX_FMT_Y210, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
546 { VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, AV_PIX_FMT_Y212, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
547 { VK_FORMAT_G16B16G16R16_422_UNORM, AV_PIX_FMT_Y216, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
548
549 /* Planar YUVA 420 at 8, 10 and 16 bits */
550 { VK_FORMAT_R8_UNORM, AV_PIX_FMT_YUVA420P, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
551 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA420P10, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
552 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA420P16, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
553
554 /* Planar YUVA 422 at 8, 10, 12 and 16 bits */
555 { VK_FORMAT_R8_UNORM, AV_PIX_FMT_YUVA422P, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
556 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA422P10, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
557 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA422P12, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
558 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA422P16, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
559
560 /* Planar YUVA 444 at 8, 10, 12 and 16 bits */
561 { VK_FORMAT_R8_UNORM, AV_PIX_FMT_YUVA444P, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
562 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA444P10, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
563 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA444P12, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
564 { VK_FORMAT_R16_UNORM, AV_PIX_FMT_YUVA444P16, VK_IMAGE_ASPECT_COLOR_BIT, 4, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
565
566 /* Single plane 444 at 8, 10, 12 and 16 bits */
567 { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_XV30, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 } },
568 { VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
569 { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_XV48, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
572
574{
575 for (int i = 0; i < nb_vk_formats_list; i++)
576 if (vk_formats_list[i].pixfmt == p)
577 return vk_formats_list[i].fallback;
578 return NULL;
579}
580
582{
583 for (int i = 0; i < nb_vk_formats_list; i++)
584 if (vk_formats_list[i].pixfmt == p)
585 return &vk_formats_list[i];
586 return NULL;
587}
588
590 VkImageTiling tiling,
591 VkFormat fmts[AV_NUM_DATA_POINTERS], /* Output format list */
592 int *nb_images, /* Output number of images */
593 VkImageAspectFlags *aspect, /* Output aspect */
594 VkImageUsageFlags *supported_usage, /* Output supported usage */
595 int disable_multiplane, int need_storage)
596{
597 VulkanDevicePriv *priv = dev_ctx->hwctx;
598 AVVulkanDeviceContext *hwctx = &priv->p;
599 FFVulkanFunctions *vk = &priv->vkctx.vkfn;
600
601 const VkFormatFeatureFlagBits2 basic_flags = VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT |
602 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
603 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT;
604
605 for (int i = 0; i < nb_vk_formats_list; i++) {
606 if (vk_formats_list[i].pixfmt == p) {
607 VkFormatProperties3 fprops = {
608 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3,
609 };
610 VkFormatProperties2 prop = {
611 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
612 .pNext = &fprops,
613 };
614 VkFormatFeatureFlagBits2 feats_primary, feats_secondary;
615 int basics_primary = 0, basics_secondary = 0;
616 int storage_primary = 0, storage_secondary = 0;
617
618 vk->GetPhysicalDeviceFormatProperties2(hwctx->phys_dev,
619 vk_formats_list[i].vkf,
620 &prop);
621
622 feats_primary = tiling == VK_IMAGE_TILING_LINEAR ?
623 fprops.linearTilingFeatures : fprops.optimalTilingFeatures;
624 basics_primary = (feats_primary & basic_flags) == basic_flags;
625 storage_primary = !!(feats_primary & VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
626
628 vk->GetPhysicalDeviceFormatProperties2(hwctx->phys_dev,
629 vk_formats_list[i].fallback[0],
630 &prop);
631 feats_secondary = tiling == VK_IMAGE_TILING_LINEAR ?
632 fprops.linearTilingFeatures : fprops.optimalTilingFeatures;
633 basics_secondary = (feats_secondary & basic_flags) == basic_flags;
634 storage_secondary = !!(feats_secondary & VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
635 } else {
636 basics_secondary = basics_primary;
637 storage_secondary = storage_primary;
638 }
639
640 if (basics_primary &&
641 !(disable_multiplane && vk_formats_list[i].vk_planes > 1) &&
642 (!need_storage || (need_storage && (storage_primary | storage_secondary)))) {
643 if (fmts) {
644 if (vk_formats_list[i].nb_images > 1) {
645 for (int j = 0; j < vk_formats_list[i].nb_images_fallback; j++)
646 fmts[j] = vk_formats_list[i].fallback[j];
647 } else {
648 fmts[0] = vk_formats_list[i].vkf;
649 }
650 }
651 if (nb_images)
652 *nb_images = 1;
653 if (aspect)
654 *aspect = vk_formats_list[i].aspect;
655 if (supported_usage)
656 *supported_usage = ff_vk_map_feats_to_usage(feats_primary) |
657 ((need_storage && (storage_primary | storage_secondary)) ?
658 VK_IMAGE_USAGE_STORAGE_BIT : 0);
659 return 0;
660 } else if (basics_secondary &&
661 (!need_storage || (need_storage && storage_secondary))) {
662 if (fmts) {
663 for (int j = 0; j < vk_formats_list[i].nb_images_fallback; j++)
664 fmts[j] = vk_formats_list[i].fallback[j];
665 }
666 if (nb_images)
667 *nb_images = vk_formats_list[i].nb_images_fallback;
668 if (aspect)
669 *aspect = vk_formats_list[i].aspect;
670 if (supported_usage)
671 *supported_usage = ff_vk_map_feats_to_usage(feats_secondary);
672 return 0;
673 } else {
674 return AVERROR(ENOTSUP);
675 }
676 }
677 }
678
679 return AVERROR(EINVAL);
680}
681
682#if CONFIG_VULKAN_STATIC
683VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,
684 const char *pName);
685#endif
686
688{
689 VulkanDevicePriv *p = ctx->hwctx;
690 AVVulkanDeviceContext *hwctx = &p->p;
691
692#if CONFIG_VULKAN_STATIC
693 hwctx->get_proc_addr = vkGetInstanceProcAddr;
694#else
695 static const char *lib_names[] = {
696#if defined(_WIN32)
697 "vulkan-1.dll",
698#elif defined(__APPLE__)
699 "libvulkan.dylib",
700 "libvulkan.1.dylib",
701 "libMoltenVK.dylib",
702#else
703 "libvulkan.so.1",
704 "libvulkan.so",
705#endif
706 };
707
708 for (int i = 0; i < FF_ARRAY_ELEMS(lib_names); i++) {
709 p->libvulkan = dlopen(lib_names[i], RTLD_NOW | RTLD_LOCAL);
710 if (p->libvulkan)
711 break;
712 }
713
714 if (!p->libvulkan) {
715 av_log(ctx, AV_LOG_ERROR, "Unable to open the libvulkan library!\n");
716 return AVERROR_UNKNOWN;
717 }
718
719 hwctx->get_proc_addr = (PFN_vkGetInstanceProcAddr)dlsym(p->libvulkan, "vkGetInstanceProcAddr");
720#endif /* CONFIG_VULKAN_STATIC */
721
722 return 0;
723}
724
729
731#ifdef __APPLE__
732 { VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
733#endif
734 { 0 },
735};
736
738 /* Misc or required by other extensions */
739 { VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, FF_VK_EXT_PORTABILITY_SUBSET },
740 { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_PUSH_DESCRIPTOR },
741 { VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, FF_VK_EXT_DEVICE_DRM },
742 { VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, FF_VK_EXT_ATOMIC_FLOAT },
743 { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, FF_VK_EXT_COOP_MATRIX },
744 { VK_EXT_SHADER_OBJECT_EXTENSION_NAME, FF_VK_EXT_SHADER_OBJECT },
745 { VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME, FF_VK_EXT_SUBGROUP_ROTATE },
746 { VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME, FF_VK_EXT_HOST_IMAGE_COPY },
747 { VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, FF_VK_EXT_EXPLICIT_MEM_LAYOUT },
748#ifdef VK_KHR_shader_relaxed_extended_instruction
749 { VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_EXTENSION_NAME, FF_VK_EXT_RELAXED_EXTENDED_INSTR },
750#endif
751#ifdef VK_EXT_shader_long_vector
752 { VK_EXT_SHADER_LONG_VECTOR_EXTENSION_NAME, FF_VK_EXT_LONG_VECTOR },
753#endif
754#ifdef VK_EXT_shader_replicated_composites
755 { VK_EXT_SHADER_REPLICATED_COMPOSITES_EXTENSION_NAME, FF_VK_EXT_REPLICATED_COMPOSITES },
756#endif
757#ifdef VK_EXT_zero_initialize_device_memory
758 { VK_EXT_ZERO_INITIALIZE_DEVICE_MEMORY_EXTENSION_NAME, FF_VK_EXT_ZERO_INITIALIZE },
759#endif
760#ifdef VK_KHR_shader_expect_assume
761 { VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME, FF_VK_EXT_EXPECT_ASSUME },
762#endif
763#ifdef VK_KHR_shader_maximal_reconvergence
764 { VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME, FF_VK_EXT_MAXIMAL_RECONVERGENCE },
765#endif
766#ifdef VK_KHR_maintenance9
767 { VK_KHR_MAINTENANCE_9_EXTENSION_NAME, FF_VK_EXT_MAINTENANCE_9 },
768#endif
769#ifdef VK_KHR_unified_image_layouts
770 { VK_KHR_UNIFIED_IMAGE_LAYOUTS_EXTENSION_NAME, FF_VK_EXT_UNIFIED_IMAGE_LAYOUTS },
771#endif
772 { VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_1 },
773#ifdef VK_KHR_video_maintenance2
774 { VK_KHR_VIDEO_MAINTENANCE_2_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_2 },
775#endif
776#ifdef VK_KHR_internally_synchronized_queues
777 { VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME, FF_VK_EXT_INTERNAL_QUEUE_SYNC },
778#endif
779
780 /* Imports/exports */
781 { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_MEMORY },
782 { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_DMABUF_MEMORY },
783 { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS },
784 { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_SEM },
785 { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_HOST_MEMORY },
786#ifdef _WIN32
787 { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY },
788 { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM },
789#endif
790
791 /* Video encoding/decoding */
792 { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_QUEUE },
793 { VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_QUEUE },
794 { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_QUEUE },
795 { VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H264 },
796 { VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H264 },
797 { VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H265 },
798 { VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H265 },
799#ifdef VK_KHR_video_decode_vp9
800 { VK_KHR_VIDEO_DECODE_VP9_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_VP9 },
801#endif
802#ifdef VK_KHR_video_encode_av1
803 { VK_KHR_VIDEO_ENCODE_AV1_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_AV1 },
804#endif
805 { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_AV1 },
806};
807
809{
810 const char **exts = av_malloc_array(sizeof(*exts),
812 if (!exts)
813 return NULL;
814
815 for (int i = 0; i < (int)FF_ARRAY_ELEMS(optional_instance_exts) - 1; i++)
817
819 return exts;
820}
821
823{
824 const char **exts = av_malloc_array(sizeof(*exts),
826 if (!exts)
827 return NULL;
828
829 for (int i = 0; i < FF_ARRAY_ELEMS(optional_device_exts); i++)
830 exts[i] = optional_device_exts[i].name;
831
833 return exts;
834}
835
836static VKAPI_ATTR
837VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
838 VkDebugUtilsMessageTypeFlagsEXT messageType,
839 const VkDebugUtilsMessengerCallbackDataEXT *data,
840 void *priv)
841{
842 int l;
843 AVHWDeviceContext *ctx = priv;
844
845 /* Ignore false positives */
846 switch (data->messageIdNumber) {
847 case 0x086974c1: /* BestPractices-vkCreateCommandPool-command-buffer-reset */
848 case 0xfd92477a: /* BestPractices-vkAllocateMemory-small-allocation */
849 return VK_FALSE;
850 default:
851 break;
852 }
853
854 switch (severity) {
855 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: l = AV_LOG_VERBOSE; break;
856 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: l = AV_LOG_INFO; break;
857 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: l = AV_LOG_WARNING; break;
858 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: l = AV_LOG_ERROR; break;
859 default: l = AV_LOG_DEBUG; break;
860 }
861
862 av_log(ctx, l, "%s\n", data->pMessage);
863 for (int i = 0; i < data->cmdBufLabelCount; i++)
864 av_log(ctx, l, "\t%i: %s\n", i, data->pCmdBufLabels[i].pLabelName);
865
866 return VK_FALSE;
867}
868
869#define ADD_VAL_TO_LIST(list, count, val) \
870 do { \
871 list = av_realloc_array(list, ++count, sizeof(*list)); \
872 if (!list) { \
873 err = AVERROR(ENOMEM); \
874 goto fail; \
875 } \
876 list[count - 1] = av_strdup(val); \
877 if (!list[count - 1]) { \
878 err = AVERROR(ENOMEM); \
879 goto fail; \
880 } \
881 } while(0)
882
883#define RELEASE_PROPS(props, count) \
884 if (props) { \
885 for (int i = 0; i < count; i++) \
886 av_free((void *)((props)[i])); \
887 av_free((void *)props); \
888 }
889
891{
892 VulkanDevicePriv *p = ctx->hwctx;
893 VkDeviceSize max_vram = 0, max_visible_vram = 0;
894
895 /* Get device memory properties */
896 av_assert0(p->mprops.memoryTypeCount);
897 for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
898 const VkMemoryType type = p->mprops.memoryTypes[i];
899 const VkMemoryHeap heap = p->mprops.memoryHeaps[type.heapIndex];
900 if (!(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
901 continue;
902 max_vram = FFMAX(max_vram, heap.size);
903 if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
904 max_visible_vram = FFMAX(max_visible_vram, heap.size);
905 }
906
907 return max_vram - max_visible_vram < 1024; /* 1 kB tolerance */
908}
909
912 /* Standard GPU-assisted validation */
914 /* Passes printfs in shaders to the debug callback */
916 /* Enables extra printouts */
918
920};
921
923 const char * const **dst, uint32_t *num,
924 enum FFVulkanDebugMode debug_mode)
925{
926 const char *tstr;
927 const char **extension_names = NULL;
928 VulkanDevicePriv *p = ctx->hwctx;
929 AVVulkanDeviceContext *hwctx = &p->p;
930 FFVulkanFunctions *vk = &p->vkctx.vkfn;
931 int err = 0, found, extensions_found = 0;
932
933 const char *mod;
934 int optional_exts_num;
935 uint32_t sup_ext_count;
936 char *user_exts_str = NULL;
937 AVDictionaryEntry *user_exts;
938 VkExtensionProperties *sup_ext;
939 const VulkanOptExtension *optional_exts;
940
941 if (!dev) {
942 mod = "instance";
943 optional_exts = optional_instance_exts;
944 optional_exts_num = FF_ARRAY_ELEMS(optional_instance_exts) - 1;
945 user_exts = av_dict_get(opts, "instance_extensions", NULL, 0);
946 if (user_exts) {
947 user_exts_str = av_strdup(user_exts->value);
948 if (!user_exts_str) {
949 err = AVERROR(ENOMEM);
950 goto fail;
951 }
952 }
953 vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL);
954 sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
955 if (!sup_ext)
956 return AVERROR(ENOMEM);
957 vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, sup_ext);
958 } else {
959 mod = "device";
960 optional_exts = optional_device_exts;
961 optional_exts_num = FF_ARRAY_ELEMS(optional_device_exts);
962 user_exts = av_dict_get(opts, "device_extensions", NULL, 0);
963 if (user_exts) {
964 user_exts_str = av_strdup(user_exts->value);
965 if (!user_exts_str) {
966 err = AVERROR(ENOMEM);
967 goto fail;
968 }
969 }
970 vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
971 &sup_ext_count, NULL);
972 sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
973 if (!sup_ext)
974 return AVERROR(ENOMEM);
975 vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
976 &sup_ext_count, sup_ext);
977 }
978
979 for (int i = 0; i < optional_exts_num; i++) {
980 tstr = optional_exts[i].name;
981 found = 0;
982
983 /* Check if the device has ReBAR for host image copies */
984 if (!strcmp(tstr, VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME) &&
986 continue;
987
988 if (dev &&
989 ((debug_mode == FF_VULKAN_DEBUG_VALIDATE) ||
990 (debug_mode == FF_VULKAN_DEBUG_PRINTF) ||
991 (debug_mode == FF_VULKAN_DEBUG_PRACTICES)) &&
992 (!strcmp(tstr, VK_EXT_SHADER_OBJECT_EXTENSION_NAME))) {
993 continue;
994 }
995
996 for (int j = 0; j < sup_ext_count; j++) {
997 if (!strcmp(tstr, sup_ext[j].extensionName)) {
998 found = 1;
999 break;
1000 }
1001 }
1002 if (!found)
1003 continue;
1004
1005 av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr);
1006 p->vkctx.extensions |= optional_exts[i].flag;
1007 ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
1008 }
1009
1010 if (!dev &&
1011 ((debug_mode == FF_VULKAN_DEBUG_VALIDATE) ||
1012 (debug_mode == FF_VULKAN_DEBUG_PRINTF) ||
1013 (debug_mode == FF_VULKAN_DEBUG_PRACTICES))) {
1014 tstr = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
1015 found = 0;
1016 for (int j = 0; j < sup_ext_count; j++) {
1017 if (!strcmp(tstr, sup_ext[j].extensionName)) {
1018 found = 1;
1019 break;
1020 }
1021 }
1022 if (found) {
1023 av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr);
1024 ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
1025 } else {
1026 av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n",
1027 tstr);
1028 err = AVERROR(EINVAL);
1029 goto fail;
1030 }
1031 }
1032
1033#ifdef VK_KHR_shader_relaxed_extended_instruction
1034 if ((debug_mode == FF_VULKAN_DEBUG_PRINTF) && dev) {
1035 tstr = VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_EXTENSION_NAME;
1036 found = 0;
1037 for (int j = 0; j < sup_ext_count; j++) {
1038 if (!strcmp(tstr, sup_ext[j].extensionName)) {
1039 found = 1;
1040 break;
1041 }
1042 }
1043 if (!found) {
1044 av_log(ctx, AV_LOG_ERROR, "Debug_printf/profile enabled, but extension \"%s\" not found!\n",
1045 tstr);
1046 err = AVERROR(EINVAL);
1047 goto fail;
1048 }
1049 }
1050#endif
1051
1052 if (user_exts_str) {
1053 char *save, *token = av_strtok(user_exts_str, "+", &save);
1054 while (token) {
1055 found = 0;
1056 for (int j = 0; j < sup_ext_count; j++) {
1057 if (!strcmp(token, sup_ext[j].extensionName)) {
1058 found = 1;
1059 break;
1060 }
1061 }
1062 if (found) {
1063 av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, token);
1064 ADD_VAL_TO_LIST(extension_names, extensions_found, token);
1065 } else {
1066 av_log(ctx, AV_LOG_WARNING, "%s extension \"%s\" not found, excluding.\n",
1067 mod, token);
1068 }
1069 token = av_strtok(NULL, "+", &save);
1070 }
1071 }
1072
1073 *dst = extension_names;
1074 *num = extensions_found;
1075
1076 av_free(user_exts_str);
1077 av_free(sup_ext);
1078 return 0;
1079
1080fail:
1081 RELEASE_PROPS(extension_names, extensions_found);
1082 av_free(user_exts_str);
1083 av_free(sup_ext);
1084 return err;
1085}
1086
1088 const char * const **dst, uint32_t *num,
1089 enum FFVulkanDebugMode *debug_mode)
1090{
1091 int err = 0;
1092 VulkanDevicePriv *priv = ctx->hwctx;
1093 FFVulkanFunctions *vk = &priv->vkctx.vkfn;
1094
1095 static const char layer_standard_validation[] = { "VK_LAYER_KHRONOS_validation" };
1096 int layer_standard_validation_found = 0;
1097
1098 uint32_t sup_layer_count;
1099 VkLayerProperties *sup_layers;
1100
1101 AVDictionaryEntry *user_layers = av_dict_get(opts, "layers", NULL, 0);
1102 char *user_layers_str = NULL;
1103 char *save, *token;
1104
1105 const char **enabled_layers = NULL;
1106 uint32_t enabled_layers_count = 0;
1107
1108 AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
1110
1111 *debug_mode = mode = FF_VULKAN_DEBUG_NONE;
1112
1113 /* Get a list of all layers */
1114 vk->EnumerateInstanceLayerProperties(&sup_layer_count, NULL);
1115 sup_layers = av_malloc_array(sup_layer_count, sizeof(VkLayerProperties));
1116 if (!sup_layers)
1117 return AVERROR(ENOMEM);
1118 vk->EnumerateInstanceLayerProperties(&sup_layer_count, sup_layers);
1119
1120 av_log(ctx, AV_LOG_VERBOSE, "Supported layers:\n");
1121 for (int i = 0; i < sup_layer_count; i++)
1122 av_log(ctx, AV_LOG_VERBOSE, "\t%s\n", sup_layers[i].layerName);
1123
1124 /* If no user layers or debug layers are given, return */
1125 if (!debug_opt && !user_layers)
1126 goto end;
1127
1128 /* Check for any properly supported validation layer */
1129 if (debug_opt) {
1130 if (!strcmp(debug_opt->value, "printf")) {
1132 } else if (!strcmp(debug_opt->value, "validate")) {
1134 } else if (!strcmp(debug_opt->value, "practices")) {
1136 } else {
1137 char *end_ptr = NULL;
1138 int idx = strtol(debug_opt->value, &end_ptr, 10);
1139 if (end_ptr == debug_opt->value || end_ptr[0] != '\0' ||
1140 idx < 0 || idx >= FF_VULKAN_DEBUG_NB) {
1141 av_log(ctx, AV_LOG_ERROR, "Invalid debugging mode \"%s\"\n",
1142 debug_opt->value);
1143 err = AVERROR(EINVAL);
1144 goto end;
1145 }
1146 mode = idx;
1147 }
1148 }
1149
1150 /* If mode is VALIDATE or PRINTF, try to find the standard validation layer extension */
1151 if ((mode == FF_VULKAN_DEBUG_VALIDATE) ||
1154 for (int i = 0; i < sup_layer_count; i++) {
1155 if (!strcmp(layer_standard_validation, sup_layers[i].layerName)) {
1156 av_log(ctx, AV_LOG_VERBOSE, "Standard validation layer %s is enabled\n",
1157 layer_standard_validation);
1158 ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, layer_standard_validation);
1159 *debug_mode = mode;
1160 layer_standard_validation_found = 1;
1161 break;
1162 }
1163 }
1164 if (!layer_standard_validation_found) {
1166 "Validation Layer \"%s\" not supported\n", layer_standard_validation);
1167 err = AVERROR(ENOTSUP);
1168 goto end;
1169 }
1170 }
1171
1172 /* Process any custom layers enabled */
1173 if (user_layers) {
1174 int found;
1175
1176 user_layers_str = av_strdup(user_layers->value);
1177 if (!user_layers_str) {
1178 err = AVERROR(ENOMEM);
1179 goto fail;
1180 }
1181
1182 token = av_strtok(user_layers_str, "+", &save);
1183 while (token) {
1184 found = 0;
1185
1186 /* If debug=1/2 was specified as an option, skip this layer */
1187 if (!strcmp(layer_standard_validation, token) && layer_standard_validation_found) {
1188 token = av_strtok(NULL, "+", &save);
1189 break;
1190 }
1191
1192 /* Try to find the layer in the list of supported layers */
1193 for (int j = 0; j < sup_layer_count; j++) {
1194 if (!strcmp(token, sup_layers[j].layerName)) {
1195 found = 1;
1196 break;
1197 }
1198 }
1199
1200 if (found) {
1201 av_log(ctx, AV_LOG_VERBOSE, "Using layer: %s\n", token);
1202 ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token);
1203
1204 /* If debug was not set as an option, force it */
1205 if (!strcmp(layer_standard_validation, token))
1206 *debug_mode = FF_VULKAN_DEBUG_VALIDATE;
1207 } else {
1209 "Layer \"%s\" not supported\n", token);
1210 err = AVERROR(EINVAL);
1211 goto end;
1212 }
1213
1214 token = av_strtok(NULL, "+", &save);
1215 }
1216 }
1217
1218fail:
1219end:
1220 av_free(sup_layers);
1221 av_free(user_layers_str);
1222
1223 if (err < 0) {
1224 RELEASE_PROPS(enabled_layers, enabled_layers_count);
1225 } else {
1226 *dst = enabled_layers;
1227 *num = enabled_layers_count;
1228 }
1229
1230 return err;
1231}
1232
1233/* Creates a VkInstance */
1235 enum FFVulkanDebugMode *debug_mode)
1236{
1237 int err = 0;
1238 VkResult ret;
1239 VulkanDevicePriv *p = ctx->hwctx;
1240 AVVulkanDeviceContext *hwctx = &p->p;
1241 FFVulkanFunctions *vk = &p->vkctx.vkfn;
1242 VkApplicationInfo application_info = {
1243 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1244 .pApplicationName = "ffmpeg",
1245 .applicationVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR,
1248 .pEngineName = "libavutil",
1249 .apiVersion = VK_API_VERSION_1_3,
1250 .engineVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR,
1253 };
1254 VkValidationFeaturesEXT validation_features = {
1255 .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
1256 };
1257 VkInstanceCreateInfo inst_props = {
1258 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1259 .pApplicationInfo = &application_info,
1260 };
1261
1262 if (!hwctx->get_proc_addr) {
1263 err = load_libvulkan(ctx);
1264 if (err < 0)
1265 return err;
1266 }
1267
1268 err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 0, 0);
1269 if (err < 0) {
1270 av_log(ctx, AV_LOG_ERROR, "Unable to load instance enumeration functions!\n");
1271 return err;
1272 }
1273
1274 err = check_layers(ctx, opts, &inst_props.ppEnabledLayerNames,
1275 &inst_props.enabledLayerCount, debug_mode);
1276 if (err)
1277 goto fail;
1278
1279 /* Check for present/missing extensions */
1280 err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames,
1281 &inst_props.enabledExtensionCount, *debug_mode);
1282 hwctx->enabled_inst_extensions = inst_props.ppEnabledExtensionNames;
1283 hwctx->nb_enabled_inst_extensions = inst_props.enabledExtensionCount;
1284 if (err < 0)
1285 goto fail;
1286
1287 /* Enable debug features if needed */
1288 if (*debug_mode == FF_VULKAN_DEBUG_VALIDATE) {
1289 static const VkValidationFeatureEnableEXT feat_list_validate[] = {
1290 VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
1291 VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
1292 VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
1293 };
1294 validation_features.pEnabledValidationFeatures = feat_list_validate;
1295 validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list_validate);
1296 inst_props.pNext = &validation_features;
1297 } else if (*debug_mode == FF_VULKAN_DEBUG_PRINTF) {
1298 static const VkValidationFeatureEnableEXT feat_list_debug[] = {
1299 VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
1300 VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
1301 VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT,
1302 };
1303 validation_features.pEnabledValidationFeatures = feat_list_debug;
1304 validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list_debug);
1305 inst_props.pNext = &validation_features;
1306 } else if (*debug_mode == FF_VULKAN_DEBUG_PRACTICES) {
1307 static const VkValidationFeatureEnableEXT feat_list_practices[] = {
1308 VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
1309 VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
1310 };
1311 validation_features.pEnabledValidationFeatures = feat_list_practices;
1312 validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list_practices);
1313 inst_props.pNext = &validation_features;
1314 }
1315
1316#ifdef __APPLE__
1317 for (int i = 0; i < inst_props.enabledExtensionCount; i++) {
1318 if (!strcmp(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
1319 inst_props.ppEnabledExtensionNames[i])) {
1320 inst_props.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
1321 break;
1322 }
1323 }
1324#endif
1325
1326 /* Try to create the instance */
1327 ret = vk->CreateInstance(&inst_props, hwctx->alloc, &hwctx->inst);
1328
1329 /* Check for errors */
1330 if (ret != VK_SUCCESS) {
1331 av_log(ctx, AV_LOG_ERROR, "Instance creation failure: %s\n",
1332 ff_vk_ret2str(ret));
1333 err = AVERROR_EXTERNAL;
1334 goto fail;
1335 }
1336
1337 err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 1, 0);
1338 if (err < 0) {
1339 av_log(ctx, AV_LOG_ERROR, "Unable to load instance functions!\n");
1340 goto fail;
1341 }
1342
1343 /* Setup debugging callback if needed */
1344 if ((*debug_mode == FF_VULKAN_DEBUG_VALIDATE) ||
1345 (*debug_mode == FF_VULKAN_DEBUG_PRINTF) ||
1346 (*debug_mode == FF_VULKAN_DEBUG_PRACTICES)) {
1347 VkDebugUtilsMessengerCreateInfoEXT dbg = {
1348 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
1349 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
1350 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
1351 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
1352 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
1353 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
1354 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
1355 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
1356 .pfnUserCallback = vk_dbg_callback,
1357 .pUserData = ctx,
1358 };
1359
1360 vk->CreateDebugUtilsMessengerEXT(hwctx->inst, &dbg,
1361 hwctx->alloc, &p->debug_ctx);
1362 }
1363
1364 err = 0;
1365
1366fail:
1367 RELEASE_PROPS(inst_props.ppEnabledLayerNames, inst_props.enabledLayerCount);
1368 return err;
1369}
1370
1372 uint8_t uuid[VK_UUID_SIZE]; /* Will use this first unless !has_uuid */
1374 uint32_t drm_major; /* Will use this second unless !has_drm */
1375 uint32_t drm_minor; /* Will use this second unless !has_drm */
1376 uint32_t has_drm; /* has drm node info */
1377 const char *name; /* Will use this third unless NULL */
1378 uint32_t pci_device; /* Will use this fourth unless 0x0 */
1379 uint32_t vendor_id; /* Last resort to find something deterministic */
1380 int index; /* Finally fall back to index */
1382
1383static const char *vk_dev_type(enum VkPhysicalDeviceType type)
1384{
1385 switch (type) {
1386 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "integrated";
1387 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "discrete";
1388 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "virtual";
1389 case VK_PHYSICAL_DEVICE_TYPE_CPU: return "software";
1390 default: return "unknown";
1391 }
1392}
1393
1394/* Finds a device */
1396{
1397 int err = 0, choice = -1;
1398 uint32_t num;
1399 VkResult ret;
1400 VulkanDevicePriv *p = ctx->hwctx;
1401 AVVulkanDeviceContext *hwctx = &p->p;
1402 FFVulkanFunctions *vk = &p->vkctx.vkfn;
1403 VkPhysicalDevice *devices = NULL;
1404 VkPhysicalDeviceIDProperties *idp = NULL;
1405 VkPhysicalDeviceProperties2 *prop = NULL;
1406 VkPhysicalDeviceDriverProperties *driver_prop = NULL;
1407 VkPhysicalDeviceDrmPropertiesEXT *drm_prop = NULL;
1408
1409 ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, NULL);
1410 if (ret != VK_SUCCESS || !num) {
1411 av_log(ctx, AV_LOG_ERROR, "No devices found: %s!\n", ff_vk_ret2str(ret));
1412 return AVERROR(ENODEV);
1413 }
1414
1415 devices = av_malloc_array(num, sizeof(VkPhysicalDevice));
1416 if (!devices)
1417 return AVERROR(ENOMEM);
1418
1419 ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, devices);
1420 if (ret != VK_SUCCESS) {
1421 av_log(ctx, AV_LOG_ERROR, "Failed enumerating devices: %s\n",
1422 ff_vk_ret2str(ret));
1423 err = AVERROR(ENODEV);
1424 goto end;
1425 }
1426
1427 prop = av_calloc(num, sizeof(*prop));
1428 if (!prop) {
1429 err = AVERROR(ENOMEM);
1430 goto end;
1431 }
1432
1433 idp = av_calloc(num, sizeof(*idp));
1434 if (!idp) {
1435 err = AVERROR(ENOMEM);
1436 goto end;
1437 }
1438
1439 driver_prop = av_calloc(num, sizeof(*driver_prop));
1440 if (!driver_prop) {
1441 err = AVERROR(ENOMEM);
1442 goto end;
1443 }
1444
1445 if (p->vkctx.extensions & FF_VK_EXT_DEVICE_DRM) {
1446 drm_prop = av_calloc(num, sizeof(*drm_prop));
1447 if (!drm_prop) {
1448 err = AVERROR(ENOMEM);
1449 goto end;
1450 }
1451 }
1452
1453 av_log(ctx, AV_LOG_VERBOSE, "GPU listing:\n");
1454 for (int i = 0; i < num; i++) {
1455 if (p->vkctx.extensions & FF_VK_EXT_DEVICE_DRM) {
1456 drm_prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
1457 driver_prop[i].pNext = &drm_prop[i];
1458 }
1459 driver_prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
1460 idp[i].pNext = &driver_prop[i];
1461 idp[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
1462 prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1463 prop[i].pNext = &idp[i];
1464
1465 vk->GetPhysicalDeviceProperties2(devices[i], &prop[i]);
1466 av_log(ctx, AV_LOG_VERBOSE, " %d: %s (%s) (0x%x)\n", i,
1467 prop[i].properties.deviceName,
1468 vk_dev_type(prop[i].properties.deviceType),
1469 prop[i].properties.deviceID);
1470 }
1471
1472 if (select->has_uuid) {
1473 for (int i = 0; i < num; i++) {
1474 if (!strncmp(idp[i].deviceUUID, select->uuid, VK_UUID_SIZE)) {
1475 choice = i;
1476 goto end;
1477 }
1478 }
1479 av_log(ctx, AV_LOG_ERROR, "Unable to find device by given UUID!\n");
1480 err = AVERROR(ENODEV);
1481 goto end;
1482 } else if ((p->vkctx.extensions & FF_VK_EXT_DEVICE_DRM) && select->has_drm) {
1483 for (int i = 0; i < num; i++) {
1484 if ((select->drm_major == drm_prop[i].primaryMajor &&
1485 select->drm_minor == drm_prop[i].primaryMinor) ||
1486 (select->drm_major == drm_prop[i].renderMajor &&
1487 select->drm_minor == drm_prop[i].renderMinor)) {
1488 choice = i;
1489 goto end;
1490 }
1491 }
1492 av_log(ctx, AV_LOG_ERROR, "Unable to find device by given DRM node numbers %i:%i!\n",
1493 select->drm_major, select->drm_minor);
1494 err = AVERROR(ENODEV);
1495 goto end;
1496 } else if (select->name) {
1497 av_log(ctx, AV_LOG_VERBOSE, "Requested device: %s\n", select->name);
1498 for (int i = 0; i < num; i++) {
1499 if (strstr(prop[i].properties.deviceName, select->name)) {
1500 choice = i;
1501 goto end;
1502 }
1503 }
1504 av_log(ctx, AV_LOG_ERROR, "Unable to find device \"%s\"!\n",
1505 select->name);
1506 err = AVERROR(ENODEV);
1507 goto end;
1508 } else if (select->pci_device) {
1509 av_log(ctx, AV_LOG_VERBOSE, "Requested device: 0x%x\n", select->pci_device);
1510 for (int i = 0; i < num; i++) {
1511 if (select->pci_device == prop[i].properties.deviceID) {
1512 choice = i;
1513 goto end;
1514 }
1515 }
1516 av_log(ctx, AV_LOG_ERROR, "Unable to find device with PCI ID 0x%x!\n",
1517 select->pci_device);
1518 err = AVERROR(EINVAL);
1519 goto end;
1520 } else if (select->vendor_id) {
1521 av_log(ctx, AV_LOG_VERBOSE, "Requested vendor: 0x%x\n", select->vendor_id);
1522 for (int i = 0; i < num; i++) {
1523 if (select->vendor_id == prop[i].properties.vendorID) {
1524 choice = i;
1525 goto end;
1526 }
1527 }
1528 av_log(ctx, AV_LOG_ERROR, "Unable to find device with Vendor ID 0x%x!\n",
1529 select->vendor_id);
1530 err = AVERROR(ENODEV);
1531 goto end;
1532 } else {
1533 if (select->index < num) {
1534 choice = select->index;
1535 goto end;
1536 }
1537 av_log(ctx, AV_LOG_ERROR, "Unable to find device with index %i!\n",
1538 select->index);
1539 err = AVERROR(ENODEV);
1540 goto end;
1541 }
1542
1543end:
1544 if (choice > -1) {
1545 av_log(ctx, AV_LOG_VERBOSE, "Device %d selected: %s (%s) (0x%x)\n",
1546 choice, prop[choice].properties.deviceName,
1547 vk_dev_type(prop[choice].properties.deviceType),
1548 prop[choice].properties.deviceID);
1549 hwctx->phys_dev = devices[choice];
1550 p->props = prop[choice];
1551 p->props.pNext = NULL;
1552 p->dprops = driver_prop[choice];
1553 p->dprops.pNext = NULL;
1554 }
1555
1556 av_free(devices);
1557 av_free(prop);
1558 av_free(idp);
1559 av_free(drm_prop);
1560 av_free(driver_prop);
1561
1562 return err;
1563}
1564
1565/* Picks the least used qf with the fewest unneeded flags, or -1 if none found */
1566static inline int pick_queue_family(VkQueueFamilyProperties2 *qf, uint32_t num_qf,
1567 VkQueueFlagBits flags)
1568{
1569 int index = -1;
1570 uint32_t min_score = UINT32_MAX;
1571
1572 for (int i = 0; i < num_qf; i++) {
1573 VkQueueFlagBits qflags = qf[i].queueFamilyProperties.queueFlags;
1574
1575 /* Per the spec, reporting transfer caps is optional for these 2 types */
1576 if ((flags & VK_QUEUE_TRANSFER_BIT) &&
1577 (qflags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)))
1578 qflags |= VK_QUEUE_TRANSFER_BIT;
1579
1580 if (qflags & flags) {
1581 uint32_t score = av_popcount(qflags) + qf[i].queueFamilyProperties.timestampValidBits;
1582 if (score < min_score) {
1583 index = i;
1584 min_score = score;
1585 }
1586 }
1587 }
1588
1589 if (index > -1)
1590 qf[index].queueFamilyProperties.timestampValidBits++;
1591
1592 return index;
1593}
1594
1595static inline int pick_video_queue_family(VkQueueFamilyProperties2 *qf,
1596 VkQueueFamilyVideoPropertiesKHR *qf_vid, uint32_t num_qf,
1597 VkVideoCodecOperationFlagsKHR flags)
1598{
1599 int index = -1;
1600 uint32_t min_score = UINT32_MAX;
1601
1602 for (int i = 0; i < num_qf; i++) {
1603 const VkQueueFlags qflags = qf[i].queueFamilyProperties.queueFlags;
1604 const VkVideoCodecOperationFlagsKHR vflags = qf_vid[i].videoCodecOperations;
1605
1606 if (!(qflags & (VK_QUEUE_VIDEO_ENCODE_BIT_KHR | VK_QUEUE_VIDEO_DECODE_BIT_KHR)))
1607 continue;
1608
1609 if (vflags & flags) {
1610 uint32_t score = av_popcount(vflags) + qf[i].queueFamilyProperties.timestampValidBits;
1611 if (score < min_score) {
1612 index = i;
1613 min_score = score;
1614 }
1615 }
1616 }
1617
1618 if (index > -1)
1619 qf[index].queueFamilyProperties.timestampValidBits++;
1620
1621 return index;
1622}
1623
1624static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
1625{
1626 uint32_t num;
1627 VulkanDevicePriv *p = ctx->hwctx;
1628 AVVulkanDeviceContext *hwctx = &p->p;
1629 FFVulkanFunctions *vk = &p->vkctx.vkfn;
1630
1631 VkQueueFamilyProperties2 *qf = NULL;
1632 VkQueueFamilyVideoPropertiesKHR *qf_vid = NULL;
1633
1634 /* First get the number of queue families */
1635 vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, NULL);
1636 if (!num) {
1637 av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1638 return AVERROR_EXTERNAL;
1639 }
1640
1641 /* Then allocate memory */
1642 qf = av_malloc_array(num, sizeof(VkQueueFamilyProperties2));
1643 if (!qf)
1644 return AVERROR(ENOMEM);
1645
1646 qf_vid = av_malloc_array(num, sizeof(VkQueueFamilyVideoPropertiesKHR));
1647 if (!qf_vid)
1648 return AVERROR(ENOMEM);
1649
1650 for (uint32_t i = 0; i < num; i++) {
1651 qf_vid[i] = (VkQueueFamilyVideoPropertiesKHR) {
1652 .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR,
1653 };
1654 qf[i] = (VkQueueFamilyProperties2) {
1655 .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2,
1656 .pNext = p->vkctx.extensions & FF_VK_EXT_VIDEO_QUEUE ? &qf_vid[i] : NULL,
1657 };
1658 }
1659
1660 /* Finally retrieve the queue families */
1661 vk->GetPhysicalDeviceQueueFamilyProperties2(hwctx->phys_dev, &num, qf);
1662
1663 av_log(ctx, AV_LOG_VERBOSE, "Queue families:\n");
1664 for (int i = 0; i < num; i++) {
1665 av_log(ctx, AV_LOG_VERBOSE, " %i:%s%s%s%s%s%s%s%s (queues: %i)\n", i,
1666 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? " graphics" : "",
1667 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_COMPUTE_BIT) ? " compute" : "",
1668 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_TRANSFER_BIT) ? " transfer" : "",
1669 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) ? " encode" : "",
1670 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ? " decode" : "",
1671 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? " sparse" : "",
1672 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_OPTICAL_FLOW_BIT_NV) ? " optical_flow" : "",
1673 ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_PROTECTED_BIT) ? " protected" : "",
1674 qf[i].queueFamilyProperties.queueCount);
1675
1676 /* We use this field to keep a score of how many times we've used that
1677 * queue family in order to make better choices. */
1678 qf[i].queueFamilyProperties.timestampValidBits = 0;
1679 }
1680
1681 hwctx->nb_qf = 0;
1682 hwctx->queue_flags = 0;
1683#ifdef VK_KHR_internally_synchronized_queues
1684 if (p->vkctx.extensions & FF_VK_EXT_INTERNAL_QUEUE_SYNC)
1685 hwctx->queue_flags |= VK_DEVICE_QUEUE_CREATE_INTERNALLY_SYNCHRONIZED_BIT_KHR;
1686#endif
1687
1688 /* Pick each queue family to use. */
1689#define PICK_QF(type, vid_op) \
1690 do { \
1691 uint32_t i; \
1692 uint32_t idx; \
1693 \
1694 if (vid_op) \
1695 idx = pick_video_queue_family(qf, qf_vid, num, vid_op); \
1696 else \
1697 idx = pick_queue_family(qf, num, type); \
1698 \
1699 if (idx == -1) \
1700 continue; \
1701 \
1702 for (i = 0; i < hwctx->nb_qf; i++) { \
1703 if (hwctx->qf[i].idx == idx) { \
1704 hwctx->qf[i].flags |= type; \
1705 hwctx->qf[i].video_caps |= vid_op; \
1706 break; \
1707 } \
1708 } \
1709 if (i == hwctx->nb_qf) { \
1710 hwctx->qf[i].idx = idx; \
1711 hwctx->qf[i].num = qf[idx].queueFamilyProperties.queueCount; \
1712 if (p->limit_queues || \
1713 p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) { \
1714 int max = p->limit_queues; \
1715 if (type == VK_QUEUE_GRAPHICS_BIT) \
1716 hwctx->qf[i].num = FFMIN(hwctx->qf[i].num, \
1717 max ? max : 1); \
1718 else if (max) \
1719 hwctx->qf[i].num = FFMIN(hwctx->qf[i].num, max); \
1720 } \
1721 hwctx->qf[i].flags = type; \
1722 hwctx->qf[i].video_caps = vid_op; \
1723 hwctx->nb_qf++; \
1724 } \
1725 } while (0)
1726
1727 PICK_QF(VK_QUEUE_GRAPHICS_BIT, VK_VIDEO_CODEC_OPERATION_NONE_KHR);
1728 PICK_QF(VK_QUEUE_COMPUTE_BIT, VK_VIDEO_CODEC_OPERATION_NONE_KHR);
1729 PICK_QF(VK_QUEUE_TRANSFER_BIT, VK_VIDEO_CODEC_OPERATION_NONE_KHR);
1730
1731 PICK_QF(VK_QUEUE_VIDEO_ENCODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR);
1732 PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR);
1733
1734 PICK_QF(VK_QUEUE_VIDEO_ENCODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR);
1735 PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
1736
1737#ifdef VK_KHR_video_decode_vp9
1738 PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR);
1739#endif
1740
1741#ifdef VK_KHR_video_encode_av1
1742 PICK_QF(VK_QUEUE_VIDEO_ENCODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR);
1743#endif
1744 PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR);
1745
1746 av_free(qf);
1747 av_free(qf_vid);
1748
1749#undef PICK_QF
1750
1751 cd->pQueueCreateInfos = av_malloc_array(hwctx->nb_qf,
1752 sizeof(VkDeviceQueueCreateInfo));
1753 if (!cd->pQueueCreateInfos)
1754 return AVERROR(ENOMEM);
1755
1756 for (uint32_t i = 0; i < hwctx->nb_qf; i++) {
1757 int dup = 0;
1758 float *weights = NULL;
1759 VkDeviceQueueCreateInfo *pc;
1760 for (uint32_t j = 0; j < cd->queueCreateInfoCount; j++) {
1761 if (hwctx->qf[i].idx == cd->pQueueCreateInfos[j].queueFamilyIndex) {
1762 dup = 1;
1763 break;
1764 }
1765 }
1766 if (dup)
1767 continue;
1768
1769 weights = av_malloc_array(hwctx->qf[i].num, sizeof(float));
1770 if (!weights) {
1771 for (uint32_t j = 0; j < cd->queueCreateInfoCount; j++)
1772 av_free((void *)cd->pQueueCreateInfos[i].pQueuePriorities);
1773 av_free((void *)cd->pQueueCreateInfos);
1774 return AVERROR(ENOMEM);
1775 }
1776
1777 for (uint32_t j = 0; j < hwctx->qf[i].num; j++)
1778 weights[j] = 1.0;
1779
1780 pc = (VkDeviceQueueCreateInfo *)cd->pQueueCreateInfos;
1781 pc[cd->queueCreateInfoCount++] = (VkDeviceQueueCreateInfo) {
1782 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
1783 .flags = hwctx->queue_flags,
1784 .queueFamilyIndex = hwctx->qf[i].idx,
1785 .queueCount = hwctx->qf[i].num,
1786 .pQueuePriorities = weights,
1787 };
1788 }
1789
1790 return 0;
1791}
1792
1793/* Only resources created by vulkan_device_create should be released here,
1794 * resources created by vulkan_device_init should be released by
1795 * vulkan_device_uninit, to make sure we don't free user provided resources,
1796 * and there is no leak.
1797 */
1799{
1800 VulkanDevicePriv *p = ctx->hwctx;
1801 AVVulkanDeviceContext *hwctx = &p->p;
1802 FFVulkanFunctions *vk = &p->vkctx.vkfn;
1803
1804 if (hwctx->act_dev)
1805 vk->DestroyDevice(hwctx->act_dev, hwctx->alloc);
1806
1807 if (p->debug_ctx)
1808 vk->DestroyDebugUtilsMessengerEXT(hwctx->inst, p->debug_ctx,
1809 hwctx->alloc);
1810
1811 if (hwctx->inst)
1812 vk->DestroyInstance(hwctx->inst, hwctx->alloc);
1813
1814 if (p->libvulkan)
1815 dlclose(p->libvulkan);
1816
1819}
1820
1822{
1823 VulkanDevicePriv *p = ctx->hwctx;
1824
1825 if (p->qf_mutex) {
1826 for (uint32_t i = 0; i < p->nb_tot_qfs; i++) {
1827 pthread_mutex_destroy(p->qf_mutex[i]);
1828 av_freep(&p->qf_mutex[i]);
1829 }
1830 av_freep(&p->qf_mutex);
1831 }
1832
1833 ff_vk_uninit(&p->vkctx);
1834}
1835
1837 VulkanDeviceSelection *dev_select,
1838 int disable_multiplane,
1839 AVDictionary *opts, int flags)
1840{
1841 int err = 0;
1842 VkResult ret;
1843 AVDictionaryEntry *opt_d;
1844 VulkanDevicePriv *p = ctx->hwctx;
1845 AVVulkanDeviceContext *hwctx = &p->p;
1846 FFVulkanFunctions *vk = &p->vkctx.vkfn;
1847 enum FFVulkanDebugMode debug_mode = FF_VULKAN_DEBUG_NONE;
1848 VulkanDeviceFeatures supported_feats = { 0 };
1849 VkDeviceCreateInfo dev_info = {
1850 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1851 };
1852
1853 /* Create an instance if not given one */
1854 if ((err = create_instance(ctx, opts, &debug_mode)))
1855 goto end;
1856
1857 /* Find a physical device (if not given one) */
1858 if ((err = find_device(ctx, dev_select)))
1859 goto end;
1860
1861 /* Get supported memory types */
1862 vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
1863
1864 /* Find and enable extensions for the physical device */
1865 if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
1866 &dev_info.enabledExtensionCount, debug_mode))) {
1867 for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1868 av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1869 av_free((void *)dev_info.pQueueCreateInfos);
1870 goto end;
1871 }
1872
1873 /* Get all supported features for the physical device */
1874 device_features_init(ctx, &supported_feats);
1875 vk->GetPhysicalDeviceFeatures2(hwctx->phys_dev, &supported_feats.device);
1876
1877 /* Copy all needed features from those supported and activate them */
1878 device_features_init(ctx, &p->feats);
1879 device_features_copy_needed(&p->feats, &supported_feats);
1880 dev_info.pNext = p->feats.device.pNext;
1881 dev_info.pEnabledFeatures = &p->feats.device.features;
1882
1883 /* Limit queues to a given number if needed */
1884 opt_d = av_dict_get(opts, "limit_queues", NULL, 0);
1885 if (opt_d)
1886 p->limit_queues = strtol(opt_d->value, NULL, 10);
1887
1888 /* Setup enabled queue families */
1889 if ((err = setup_queue_families(ctx, &dev_info)))
1890 goto end;
1891
1892 /* Finally create the device */
1893 ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
1894 &hwctx->act_dev);
1895
1896 for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1897 av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1898 av_free((void *)dev_info.pQueueCreateInfos);
1899
1900 if (ret != VK_SUCCESS) {
1901 av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n",
1902 ff_vk_ret2str(ret));
1903 for (int i = 0; i < dev_info.enabledExtensionCount; i++)
1904 av_free((void *)dev_info.ppEnabledExtensionNames[i]);
1905 av_free((void *)dev_info.ppEnabledExtensionNames);
1906 err = AVERROR_EXTERNAL;
1907 goto end;
1908 }
1909
1910 /* Tiled images setting, use them by default */
1911 opt_d = av_dict_get(opts, "linear_images", NULL, 0);
1912 if (opt_d)
1913 p->use_linear_images = strtol(opt_d->value, NULL, 10);
1914
1915 /* The disable_multiplane argument takes precedent over the option */
1916 p->disable_multiplane = disable_multiplane;
1917 if (!p->disable_multiplane) {
1918 opt_d = av_dict_get(opts, "disable_multiplane", NULL, 0);
1919 if (opt_d)
1920 p->disable_multiplane = strtol(opt_d->value, NULL, 10);
1921 }
1922
1923 /* Disable host pointer imports (by default on nvidia) */
1924 p->avoid_host_import = p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
1925 opt_d = av_dict_get(opts, "avoid_host_import", NULL, 0);
1926 if (opt_d)
1927 p->avoid_host_import = strtol(opt_d->value, NULL, 10);
1928
1929 /* Set the public device feature struct and its pNext chain */
1930 hwctx->device_features = p->feats.device;
1931
1932 /* Set the list of all active extensions */
1933 hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames;
1934 hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount;
1935
1936 /* The extension lists need to be freed */
1937 ctx->free = vulkan_device_free;
1938
1939end:
1940 return err;
1941}
1942
1943static void lock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
1944{
1945 VulkanDevicePriv *p = ctx->hwctx;
1946 if (p->qf_mutex)
1947 pthread_mutex_lock(&p->qf_mutex[queue_family][index]);
1948}
1949
1950static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
1951{
1952 VulkanDevicePriv *p = ctx->hwctx;
1953 if (p->qf_mutex)
1954 pthread_mutex_unlock(&p->qf_mutex[queue_family][index]);
1955}
1956
1958{
1959 int err = 0;
1960 uint32_t qf_num;
1961 VulkanDevicePriv *p = ctx->hwctx;
1962 AVVulkanDeviceContext *hwctx = &p->p;
1963 FFVulkanFunctions *vk = &p->vkctx.vkfn;
1964 VkQueueFamilyProperties2 *qf;
1965 VkQueueFamilyVideoPropertiesKHR *qf_vid;
1966 VkPhysicalDeviceExternalSemaphoreInfo ext_sem_props_info;
1967
1968 /* Set device extension flags */
1969 for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) {
1970 for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) {
1971 if (!strcmp(hwctx->enabled_dev_extensions[i],
1972 optional_device_exts[j].name)) {
1973 p->vkctx.extensions |= optional_device_exts[j].flag;
1974 break;
1975 }
1976 }
1977 }
1978
1979 err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 1, 1);
1980 if (err < 0) {
1981 av_log(ctx, AV_LOG_ERROR, "Unable to load functions!\n");
1982 return err;
1983 }
1984
1985 p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1986 p->props.pNext = &p->hprops;
1987 p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
1988 p->hprops.pNext = &p->dprops;
1989 p->dprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
1990
1991 vk->GetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props);
1992 av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n",
1993 p->props.properties.deviceName);
1994 av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n");
1995 av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %"PRIu64"\n",
1996 p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
1997 av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %zu\n",
1998 p->props.properties.limits.minMemoryMapAlignment);
1999 av_log(ctx, AV_LOG_VERBOSE, " nonCoherentAtomSize: %"PRIu64"\n",
2000 p->props.properties.limits.nonCoherentAtomSize);
2001 if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY)
2002 av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %"PRIu64"\n",
2003 p->hprops.minImportedHostPointerAlignment);
2004
2005 vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &qf_num, NULL);
2006 if (!qf_num) {
2007 av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
2008 return AVERROR_EXTERNAL;
2009 }
2010
2011 ext_sem_props_info = (VkPhysicalDeviceExternalSemaphoreInfo) {
2012 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
2013 };
2014
2015 /* Opaque FD semaphore properties */
2016 ext_sem_props_info.handleType =
2017#ifdef _WIN32
2018 IsWindows8OrGreater()
2019 ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2020 : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
2021#else
2022 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2023#endif
2024 p->ext_sem_props_opaque.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES;
2025 vk->GetPhysicalDeviceExternalSemaphoreProperties(hwctx->phys_dev,
2026 &ext_sem_props_info,
2027 &p->ext_sem_props_opaque);
2028
2029 qf = av_malloc_array(qf_num, sizeof(VkQueueFamilyProperties2));
2030 if (!qf)
2031 return AVERROR(ENOMEM);
2032
2033 qf_vid = av_malloc_array(qf_num, sizeof(VkQueueFamilyVideoPropertiesKHR));
2034 if (!qf_vid) {
2035 av_free(qf);
2036 return AVERROR(ENOMEM);
2037 }
2038
2039 for (uint32_t i = 0; i < qf_num; i++) {
2040 qf_vid[i] = (VkQueueFamilyVideoPropertiesKHR) {
2041 .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR,
2042 };
2043 qf[i] = (VkQueueFamilyProperties2) {
2044 .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2,
2045 .pNext = p->vkctx.extensions & FF_VK_EXT_VIDEO_QUEUE ? &qf_vid[i] : NULL,
2046 };
2047 }
2048
2049 vk->GetPhysicalDeviceQueueFamilyProperties2(hwctx->phys_dev, &qf_num, qf);
2050
2051 p->nb_tot_qfs = qf_num;
2052
2053 if (!(p->vkctx.extensions & FF_VK_EXT_INTERNAL_QUEUE_SYNC)) {
2054 p->qf_mutex = av_calloc(qf_num, sizeof(*p->qf_mutex));
2055 if (!p->qf_mutex) {
2056 err = AVERROR(ENOMEM);
2057 goto end;
2058 }
2059
2060 for (uint32_t i = 0; i < qf_num; i++) {
2061 p->qf_mutex[i] = av_calloc(qf[i].queueFamilyProperties.queueCount,
2062 sizeof(**p->qf_mutex));
2063 if (!p->qf_mutex[i]) {
2064 err = AVERROR(ENOMEM);
2065 goto end;
2066 }
2067 for (uint32_t j = 0; j < qf[i].queueFamilyProperties.queueCount; j++) {
2068 err = pthread_mutex_init(&p->qf_mutex[i][j], NULL);
2069 if (err != 0) {
2070 av_log(ctx, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n",
2071 av_err2str(err));
2072 err = AVERROR(err);
2073 goto end;
2074 }
2075 }
2076 }
2077 }
2078
2079 for (int i = 0; i < hwctx->nb_qf; i++) {
2080 if (!hwctx->qf[i].video_caps &&
2081 hwctx->qf[i].flags & (VK_QUEUE_VIDEO_DECODE_BIT_KHR |
2082 VK_QUEUE_VIDEO_ENCODE_BIT_KHR)) {
2083 hwctx->qf[i].video_caps = qf_vid[hwctx->qf[i].idx].videoCodecOperations;
2084 }
2085 }
2086
2087 /* Setup array for pQueueFamilyIndices with used queue families */
2088 p->nb_img_qfs = 0;
2089 for (int i = 0; i < hwctx->nb_qf; i++) {
2090 int seen = 0;
2091 /* Make sure each entry is unique
2092 * (VUID-VkBufferCreateInfo-sharingMode-01419) */
2093 for (int j = (i - 1); j >= 0; j--) {
2094 if (hwctx->qf[i].idx == hwctx->qf[j].idx) {
2095 seen = 1;
2096 break;
2097 }
2098 }
2099 if (!seen)
2100 p->img_qfs[p->nb_img_qfs++] = hwctx->qf[i].idx;
2101 }
2102
2103#if FF_API_VULKAN_SYNC_QUEUES
2105 if (!hwctx->lock_queue)
2106 hwctx->lock_queue = lock_queue;
2107 if (!hwctx->unlock_queue)
2108 hwctx->unlock_queue = unlock_queue;
2110#endif
2111
2112 /* Re-query device capabilities, in case the device was created externally */
2113 vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
2114
2115 p->vkctx.device = ctx;
2116 p->vkctx.hwctx = hwctx;
2117
2118 ff_vk_load_props(&p->vkctx);
2119 p->compute_qf = ff_vk_qf_find(&p->vkctx, VK_QUEUE_COMPUTE_BIT, 0);
2120 p->transfer_qf = ff_vk_qf_find(&p->vkctx, VK_QUEUE_TRANSFER_BIT, 0);
2121
2122 /* Re-query device capabilities, in case the device was created externally */
2123 vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
2124
2125end:
2126 av_free(qf_vid);
2127 av_free(qf);
2128 return err;
2129}
2130
2131static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device,
2132 AVDictionary *opts, int flags)
2133{
2134 VulkanDeviceSelection dev_select = { 0 };
2135 if (device && device[0]) {
2136 char *end = NULL;
2137 dev_select.index = strtol(device, &end, 10);
2138 if (end == device) {
2139 dev_select.index = 0;
2140 dev_select.name = device;
2141 }
2142 }
2143
2144 return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
2145}
2146
2148 AVHWDeviceContext *src_ctx,
2149 AVDictionary *opts, int flags)
2150{
2151 av_unused VulkanDeviceSelection dev_select = { 0 };
2152
2153 /* If there's only one device on the system, then even if its not covered
2154 * by the following checks (e.g. non-PCIe ARM GPU), having an empty
2155 * dev_select will mean it'll get picked. */
2156 switch(src_ctx->type) {
2157#if CONFIG_VAAPI
2159 AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
2160 VADisplay dpy = src_hwctx->display;
2161#if VA_CHECK_VERSION(1, 15, 0)
2162 VAStatus vas;
2163 VADisplayAttribute attr = {
2164 .type = VADisplayPCIID,
2165 };
2166#endif
2167 const char *vendor;
2168
2169#if VA_CHECK_VERSION(1, 15, 0)
2170 vas = vaGetDisplayAttributes(dpy, &attr, 1);
2171 if (vas == VA_STATUS_SUCCESS && attr.flags != VA_DISPLAY_ATTRIB_NOT_SUPPORTED)
2172 dev_select.pci_device = (attr.value & 0xFFFF);
2173#endif
2174
2175 if (!dev_select.pci_device) {
2176 vendor = vaQueryVendorString(dpy);
2177 if (!vendor) {
2178 av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n");
2179 return AVERROR_EXTERNAL;
2180 }
2181
2182 if (strstr(vendor, "AMD"))
2183 dev_select.vendor_id = 0x1002;
2184 }
2185
2186 return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
2187 }
2188#endif
2189#if CONFIG_LIBDRM
2190 case AV_HWDEVICE_TYPE_DRM: {
2191 int err;
2192 struct stat drm_node_info;
2193 drmDevice *drm_dev_info;
2194 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
2195
2196 err = fstat(src_hwctx->fd, &drm_node_info);
2197 if (err) {
2198 av_log(ctx, AV_LOG_ERROR, "Unable to get node info from DRM fd: %s!\n",
2199 av_err2str(AVERROR(errno)));
2200 return AVERROR_EXTERNAL;
2201 }
2202
2203 dev_select.drm_major = major(drm_node_info.st_dev);
2204 dev_select.drm_minor = minor(drm_node_info.st_dev);
2205 dev_select.has_drm = 1;
2206
2207 err = drmGetDevice(src_hwctx->fd, &drm_dev_info);
2208 if (err) {
2209 av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd: %s!\n",
2210 av_err2str(AVERROR(errno)));
2211 return AVERROR_EXTERNAL;
2212 }
2213
2214 if (drm_dev_info->bustype == DRM_BUS_PCI)
2215 dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id;
2216
2217 drmFreeDevice(&drm_dev_info);
2218
2219 return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
2220 }
2221#endif
2222#if CONFIG_CUDA
2223 case AV_HWDEVICE_TYPE_CUDA: {
2224 AVHWDeviceContext *cuda_cu = src_ctx;
2225 AVCUDADeviceContext *src_hwctx = src_ctx->hwctx;
2226 AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal;
2227 CudaFunctions *cu = cu_internal->cuda_dl;
2228
2229 int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid,
2230 cu_internal->cuda_device));
2231 if (ret < 0) {
2232 av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n");
2233 return AVERROR_EXTERNAL;
2234 }
2235
2236 dev_select.has_uuid = 1;
2237
2238 /*
2239 * CUDA is not able to import multiplane images, so always derive a
2240 * Vulkan device with multiplane disabled.
2241 */
2242 return vulkan_device_create_internal(ctx, &dev_select, 1, opts, flags);
2243 }
2244#endif
2245 default:
2246 return AVERROR(ENOSYS);
2247 }
2248}
2249
2251 const void *hwconfig,
2252 AVHWFramesConstraints *constraints)
2253{
2254 int count = 0;
2255 VulkanDevicePriv *p = ctx->hwctx;
2256
2257 for (enum AVPixelFormat i = 0; i < nb_vk_formats_list; i++) {
2259 p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
2260 VK_IMAGE_TILING_OPTIMAL,
2261 NULL, NULL, NULL, NULL, p->disable_multiplane, 1) >= 0;
2262 }
2263
2264 constraints->valid_sw_formats = av_malloc_array(count + 1 + CONFIG_CUDA,
2265 sizeof(enum AVPixelFormat));
2266 if (!constraints->valid_sw_formats)
2267 return AVERROR(ENOMEM);
2268
2269 count = 0;
2270 for (enum AVPixelFormat i = 0; i < nb_vk_formats_list; i++) {
2272 p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
2273 VK_IMAGE_TILING_OPTIMAL,
2274 NULL, NULL, NULL, NULL, p->disable_multiplane, 1) >= 0) {
2275 constraints->valid_sw_formats[count++] = vk_formats_list[i].pixfmt;
2276 }
2277 }
2278
2279#if CONFIG_CUDA
2280 constraints->valid_sw_formats[count++] = AV_PIX_FMT_CUDA;
2281#endif
2282
2283 constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE;
2284
2285 constraints->min_width = 1;
2286 constraints->min_height = 1;
2287 constraints->max_width = p->props.properties.limits.maxImageDimension2D;
2288 constraints->max_height = p->props.properties.limits.maxImageDimension2D;
2289
2290 constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat));
2291 if (!constraints->valid_hw_formats)
2292 return AVERROR(ENOMEM);
2293
2294 constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN;
2295 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
2296
2297 return 0;
2298}
2299
2300static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
2301 VkMemoryPropertyFlagBits req_flags, const void *alloc_extension,
2302 VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
2303{
2304 VkResult ret;
2305 int index = -1;
2306 VulkanDevicePriv *p = ctx->hwctx;
2307 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2308 AVVulkanDeviceContext *dev_hwctx = &p->p;
2309 VkMemoryAllocateInfo alloc_info = {
2310 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2311 .pNext = alloc_extension,
2312 .allocationSize = req->size,
2313 };
2314
2315 /* The vulkan spec requires memory types to be sorted in the "optimal"
2316 * order, so the first matching type we find will be the best/fastest one */
2317 for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
2318 const VkMemoryType *type = &p->mprops.memoryTypes[i];
2319
2320 /* The memory type must be supported by the requirements (bitfield) */
2321 if (!(req->memoryTypeBits & (1 << i)))
2322 continue;
2323
2324 /* The memory type flags must include our properties */
2325 if ((type->propertyFlags & req_flags) != req_flags)
2326 continue;
2327
2328 /* The memory type must be large enough */
2329 if (req->size > p->mprops.memoryHeaps[type->heapIndex].size)
2330 continue;
2331
2332 /* Found a suitable memory type */
2333 index = i;
2334 break;
2335 }
2336
2337 if (index < 0) {
2338 av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
2339 req_flags);
2340 return AVERROR(EINVAL);
2341 }
2342
2343 alloc_info.memoryTypeIndex = index;
2344
2345 ret = vk->AllocateMemory(dev_hwctx->act_dev, &alloc_info,
2346 dev_hwctx->alloc, mem);
2347 if (ret != VK_SUCCESS) {
2348 av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
2349 ff_vk_ret2str(ret));
2350 return AVERROR(ENOMEM);
2351 }
2352
2353 *mem_flags |= p->mprops.memoryTypes[index].propertyFlags;
2354
2355 return 0;
2356}
2357
2359{
2360 av_unused AVVkFrameInternal *internal = f->internal;
2361
2362 // Make this function safe to call repeatedly
2363 if (!internal)
2364 return;
2365
2366#if CONFIG_CUDA
2367 if (internal->cuda_fc_ref) {
2368 AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
2370 AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2371 AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2372 AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2373 CudaFunctions *cu = cu_internal->cuda_dl;
2374
2375 for (int i = 0; i < planes; i++) {
2376 if (internal->cu_sem[i])
2377 CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
2378 if (internal->cu_mma[i])
2379 CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
2380 if (internal->ext_mem[i])
2381 CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
2382#ifdef _WIN32
2383 if (internal->ext_sem_handle[i])
2384 CloseHandle(internal->ext_sem_handle[i]);
2385 if (internal->ext_mem_handle[i])
2386 CloseHandle(internal->ext_mem_handle[i]);
2387#endif
2388 }
2389
2390 av_buffer_unref(&internal->cuda_fc_ref);
2391 }
2392#endif
2393
2394 if (internal->drm_sync_sem != VK_NULL_HANDLE)
2395 p->vkctx.vkfn.DestroySemaphore(p->p.act_dev, internal->drm_sync_sem,
2396 p->p.alloc);
2397
2398 pthread_mutex_destroy(&internal->update_mutex);
2399 av_freep(&f->internal);
2400}
2401
2403{
2404 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2405 AVVulkanDeviceContext *hwctx = &p->p;
2406 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2407 int nb_images = ff_vk_count_images(f);
2408 int nb_sems = 0;
2409
2410 while (nb_sems < FF_ARRAY_ELEMS(f->sem) && f->sem[nb_sems])
2411 nb_sems++;
2412
2413 if (nb_sems) {
2414 VkSemaphoreWaitInfo sem_wait = {
2415 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
2416 .flags = 0x0,
2417 .pSemaphores = f->sem,
2418 .pValues = f->sem_value,
2419 .semaphoreCount = nb_sems,
2420 };
2421
2422 vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
2423 }
2424
2426
2427 for (int i = 0; i < nb_images; i++) {
2428 vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2429 vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2430 vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2431 }
2432
2433 av_free(f);
2434}
2435
2436static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
2437{
2438 vulkan_frame_free(opaque, (AVVkFrame*)data);
2439}
2440
2442 void *alloc_pnext, size_t alloc_pnext_stride)
2443{
2444 int img_cnt = 0, err;
2445 VkResult ret;
2447 VulkanDevicePriv *p = ctx->hwctx;
2448 AVVulkanDeviceContext *hwctx = &p->p;
2449 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2450 VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
2451
2452 while (f->img[img_cnt]) {
2453 int use_ded_mem;
2454 VkImageMemoryRequirementsInfo2 req_desc = {
2455 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2456 .image = f->img[img_cnt],
2457 };
2458 VkMemoryDedicatedAllocateInfo ded_alloc = {
2459 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2460 .pNext = (void *)(((uint8_t *)alloc_pnext) + img_cnt*alloc_pnext_stride),
2461 };
2462 VkMemoryDedicatedRequirements ded_req = {
2463 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2464 };
2465 VkMemoryRequirements2 req = {
2466 .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2467 .pNext = &ded_req,
2468 };
2469
2470 vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
2471
2472 av_log(hwfc, AV_LOG_TRACE,
2473 "plane %d: driver reports prefersDedicatedAllocation=%i requiresDedicatedAllocation=%i\n",
2474 img_cnt, ded_req.prefersDedicatedAllocation, ded_req.requiresDedicatedAllocation);
2475
2476 if (f->tiling == VK_IMAGE_TILING_LINEAR)
2477 req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
2478 p->props.properties.limits.minMemoryMapAlignment);
2479
2480 /* In case the implementation prefers/requires dedicated allocation */
2481 use_ded_mem = ded_req.prefersDedicatedAllocation |
2482 ded_req.requiresDedicatedAllocation;
2483 if (((VulkanFramesPriv *)hwfc->hwctx)->export_requires_dedicated)
2484 use_ded_mem = 1;
2485 if (use_ded_mem)
2486 ded_alloc.image = f->img[img_cnt];
2487
2488 /* Allocate memory */
2489 if ((err = alloc_mem(ctx, &req.memoryRequirements,
2490 f->tiling == VK_IMAGE_TILING_LINEAR ?
2491 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
2492 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2493 use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
2494 &f->flags, &f->mem[img_cnt])))
2495 return err;
2496
2497 f->size[img_cnt] = req.memoryRequirements.size;
2498 bind_info[img_cnt].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2499 bind_info[img_cnt].image = f->img[img_cnt];
2500 bind_info[img_cnt].memory = f->mem[img_cnt];
2501
2502 img_cnt++;
2503 }
2504
2505 /* Bind the allocated memory to the images */
2506 ret = vk->BindImageMemory2(hwctx->act_dev, img_cnt, bind_info);
2507 if (ret != VK_SUCCESS) {
2508 av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2509 ff_vk_ret2str(ret));
2510 return AVERROR_EXTERNAL;
2511 }
2512
2513 return 0;
2514}
2515
2525
2526static void switch_new_props(enum PrepMode pmode, VkImageLayout *new_layout,
2527 VkAccessFlags2 *new_access)
2528{
2529 switch (pmode) {
2530 case PREP_MODE_GENERAL:
2531 *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2532 *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2533 break;
2534 case PREP_MODE_WRITE:
2535 *new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2536 *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2537 break;
2539 *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2540 *new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
2541 break;
2543 *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2544 *new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
2545 break;
2547 *new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR;
2548 *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2549 break;
2551 *new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
2552 *new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
2553 break;
2555 *new_layout = VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR;
2556 *new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
2557 break;
2558 }
2559}
2560
2562 AVVkFrame *frame, enum PrepMode pmode)
2563{
2564 int err;
2565 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2566 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2567 VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
2568 int nb_img_bar = 0;
2569
2570 VkImageLayout new_layout;
2571 VkAccessFlags2 new_access;
2572 switch_new_props(pmode, &new_layout, &new_access);
2573
2574 uint32_t dst_qf = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2575 VkPipelineStageFlagBits2 src_stage = VK_PIPELINE_STAGE_2_NONE;
2576 if (pmode == PREP_MODE_EXTERNAL_EXPORT) {
2577 dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
2578 src_stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
2579 }
2580
2581 /* This is dirty - but it works. The vulkan.c dependency system doesn't
2582 * free non-refcounted frames, and non-refcounted hardware frames cannot
2583 * happen anywhere outside of here. */
2584 AVBufferRef tmp_ref = {
2585 .data = (uint8_t *)hwfc,
2586 };
2587 AVFrame tmp_frame = {
2588 .data[0] = (uint8_t *)frame,
2589 .hw_frames_ctx = &tmp_ref,
2590 };
2591
2592 VkCommandBuffer cmd_buf;
2593 FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, ectx);
2594 cmd_buf = exec->buf;
2595 err = ff_vk_exec_start(&p->vkctx, exec);
2596 if (err < 0)
2597 return err;
2598
2599 err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, &tmp_frame,
2600 VK_PIPELINE_STAGE_2_NONE,
2601 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
2602 if (err < 0)
2603 return err;
2604
2605 ff_vk_frame_barrier(&p->vkctx, exec, &tmp_frame, img_bar, &nb_img_bar,
2606 src_stage,
2607 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
2608 new_access, new_layout, dst_qf);
2609
2610 vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
2611 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
2612 .pImageMemoryBarriers = img_bar,
2613 .imageMemoryBarrierCount = nb_img_bar,
2614 });
2615
2616 err = ff_vk_exec_submit(&p->vkctx, exec);
2617 if (err < 0)
2618 return err;
2619
2620 /* Drops the stack-based frame above from the dependency list */
2621 ff_vk_exec_wait(&p->vkctx, exec);
2622
2623 return 0;
2624}
2625
2627 AVVkFrame *frame, enum PrepMode pmode)
2628{
2629 VkResult ret;
2630 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2631 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2632 VkHostImageLayoutTransitionInfoEXT layout_change[AV_NUM_DATA_POINTERS];
2633 int nb_images = ff_vk_count_images(frame);
2634
2635 VkImageLayout new_layout;
2636 VkAccessFlags2 new_access;
2637 switch_new_props(pmode, &new_layout, &new_access);
2638
2639 int i;
2640 for (i = 0; i < p->vkctx.host_image_props.copyDstLayoutCount; i++) {
2641 if (p->vkctx.host_image_props.pCopyDstLayouts[i] == new_layout)
2642 break;
2643 }
2644 if (i == p->vkctx.host_image_props.copyDstLayoutCount)
2645 return AVERROR(ENOTSUP);
2646
2647 for (i = 0; i < nb_images; i++) {
2648 layout_change[i] = (VkHostImageLayoutTransitionInfoEXT) {
2649 .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
2650 .image = frame->img[i],
2651 .oldLayout = frame->layout[i],
2652 .newLayout = new_layout,
2653 .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2654 .subresourceRange.layerCount = 1,
2655 .subresourceRange.levelCount = 1,
2656 };
2657 frame->layout[i] = new_layout;
2658 }
2659
2660 ret = vk->TransitionImageLayoutEXT(p->vkctx.hwctx->act_dev,
2661 nb_images, layout_change);
2662 if (ret != VK_SUCCESS) {
2663 av_log(hwfc, AV_LOG_ERROR, "Unable to prepare frame: %s\n",
2664 ff_vk_ret2str(ret));
2665 return AVERROR_EXTERNAL;
2666 }
2667
2668 return 0;
2669}
2670
2672 AVVkFrame *frame, enum PrepMode pmode)
2673{
2674 int err = 0;
2675 AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
2676 if (hwfc_vk->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
2677 (pmode != PREP_MODE_EXTERNAL_EXPORT) &&
2678 (pmode != PREP_MODE_EXTERNAL_IMPORT))
2679 err = switch_layout_host(hwfc, ectx, frame, pmode);
2680
2681 if (err != AVERROR(ENOTSUP))
2682 return err;
2683
2684 return switch_layout(hwfc, ectx, frame, pmode);
2685}
2686
2687static inline void get_plane_wh(uint32_t *w, uint32_t *h, enum AVPixelFormat format,
2688 int frame_w, int frame_h, int plane)
2689{
2691
2692 /* Currently always true unless gray + alpha support is added */
2693 if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB ||
2694 !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
2695 *w = frame_w;
2696 *h = frame_h;
2697 return;
2698 }
2699
2700 *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w);
2701 *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h);
2702}
2703
2705 VkImageTiling tiling, VkImageUsageFlagBits usage,
2706 VkImageCreateFlags flags, int nb_layers,
2707 void *create_pnext)
2708{
2709 int err;
2710 VkResult ret;
2711 AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
2713 VulkanDevicePriv *p = ctx->hwctx;
2714 AVVulkanDeviceContext *hwctx = &p->p;
2715 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2716 AVVkFrame *f;
2717
2718 VkSemaphoreTypeCreateInfo sem_type_info = {
2719 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2720 .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2721 .initialValue = 0,
2722 };
2723 VkSemaphoreCreateInfo sem_spawn = {
2724 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2725 .pNext = &sem_type_info,
2726 };
2727
2728 VkExportSemaphoreCreateInfo ext_sem_info_opaque = {
2729 .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
2730#ifdef _WIN32
2731 .handleTypes = IsWindows8OrGreater()
2732 ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2733 : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2734#else
2735 .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2736#endif
2737 };
2738
2739 /* Check if exporting is supported before chaining any structs */
2740 if (p->ext_sem_props_opaque.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) {
2741 if (p->vkctx.extensions & (FF_VK_EXT_EXTERNAL_WIN32_SEM | FF_VK_EXT_EXTERNAL_FD_SEM))
2742 ff_vk_link_struct(&sem_type_info, &ext_sem_info_opaque);
2743 }
2744
2745 f = av_vk_frame_alloc();
2746 if (!f) {
2747 av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2748 return AVERROR(ENOMEM);
2749 }
2750
2751 // TODO: check width and height for alignment in case of multiplanar (must be mod-2 if subsampled)
2752
2753 /* Create the images */
2754 for (int i = 0; (hwfc_vk->format[i] != VK_FORMAT_UNDEFINED); i++) {
2755 VkImageCreateInfo create_info = {
2756 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2757 .pNext = create_pnext,
2758 .imageType = VK_IMAGE_TYPE_2D,
2759 .format = hwfc_vk->format[i],
2760 .extent.depth = 1,
2761 .mipLevels = 1,
2762 .arrayLayers = nb_layers,
2763 .flags = flags,
2764 .tiling = tiling,
2765 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2766 .usage = usage,
2767 .samples = VK_SAMPLE_COUNT_1_BIT,
2768 .pQueueFamilyIndices = p->img_qfs,
2769 .queueFamilyIndexCount = p->nb_img_qfs,
2770 .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2771 VK_SHARING_MODE_EXCLUSIVE,
2772 };
2773
2774 get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2775 hwfc->sw_format, hwfc->width, hwfc->height, i);
2776
2777 ret = vk->CreateImage(hwctx->act_dev, &create_info,
2778 hwctx->alloc, &f->img[i]);
2779 if (ret != VK_SUCCESS) {
2780 av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2781 ff_vk_ret2str(ret));
2782 err = AVERROR(EINVAL);
2783 goto fail;
2784 }
2785
2786 /* Create semaphore */
2787 ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2788 hwctx->alloc, &f->sem[i]);
2789 if (ret != VK_SUCCESS) {
2790 av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2791 ff_vk_ret2str(ret));
2792 err = AVERROR_EXTERNAL;
2793 goto fail;
2794 }
2795
2796 f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2797 f->layout[i] = create_info.initialLayout;
2798 f->access[i] = 0x0;
2799 f->sem_value[i] = 0;
2800 }
2801
2802 f->flags = 0x0;
2803 f->tiling = tiling;
2804
2805 *frame = f;
2806 return 0;
2807
2808fail:
2809 vulkan_frame_free(hwfc, f);
2810 return err;
2811}
2812
2813/* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2815 VkExternalMemoryHandleTypeFlags *comp_handle_types,
2816 VkExternalMemoryHandleTypeFlags *iexp,
2817 VkExternalMemoryHandleTypeFlagBits exp)
2818{
2819 VkResult ret;
2820 AVVulkanFramesContext *hwctx = hwfc->hwctx;
2821 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2822 AVVulkanDeviceContext *dev_hwctx = &p->p;
2823 FFVulkanFunctions *vk = &p->vkctx.vkfn;
2824
2825 const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
2827 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2828 int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
2829 int nb_mods;
2830
2831 VkExternalImageFormatProperties eprops = {
2832 .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2833 };
2834 VkImageFormatProperties2 props = {
2835 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2836 .pNext = &eprops,
2837 };
2838 VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
2839 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2840 .pNext = NULL,
2841 .pQueueFamilyIndices = p->img_qfs,
2842 .queueFamilyIndexCount = p->nb_img_qfs,
2843 .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2844 VK_SHARING_MODE_EXCLUSIVE,
2845 };
2846 VkPhysicalDeviceExternalImageFormatInfo enext = {
2847 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2848 .handleType = exp,
2849 .pNext = has_mods ? &phy_dev_mod_info : NULL,
2850 };
2851 VkPhysicalDeviceImageFormatInfo2 pinfo = {
2852 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2853 .pNext = !exp ? NULL : &enext,
2854 .format = hwctx->format[0],
2855 .type = VK_IMAGE_TYPE_2D,
2856 .tiling = hwctx->tiling,
2857 .usage = hwctx->usage,
2858 .flags = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && has_mods) ?
2859 (hwctx->img_flags) : hwctx->img_flags ? hwctx->img_flags : (VkImageCreateFlags)(VK_IMAGE_CREATE_ALIAS_BIT),
2860 };
2861
2862 nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
2863 for (int i = 0; i < nb_mods; i++) {
2864 if (has_mods)
2865 phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
2866
2867 ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
2868 &pinfo, &props);
2869
2870 if (has_mods)
2871 av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
2872 i, (unsigned long long)phy_dev_mod_info.drmFormatModifier,
2873 ret == VK_SUCCESS ? "OK" : "FAIL");
2874 if (ret == VK_SUCCESS) {
2875 *iexp |= exp;
2876 *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2877 if (exp == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
2878 VulkanFramesPriv *fp = hwfc->hwctx;
2879 fp->export_requires_dedicated = !!(eprops.externalMemoryProperties.externalMemoryFeatures &
2880 VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
2881 }
2882 }
2883 }
2884}
2885
2886static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2887{
2888 int err;
2889 AVVkFrame *f;
2890 AVBufferRef *avbuf = NULL;
2891 AVHWFramesContext *hwfc = opaque;
2892 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2893 VulkanFramesPriv *fp = hwfc->hwctx;
2894 AVVulkanFramesContext *hwctx = &fp->p;
2895 VkExternalMemoryHandleTypeFlags e = 0x0;
2896 VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2897
2898 VkExternalMemoryImageCreateInfo eiinfo = {
2899 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2900 .pNext = hwctx->create_pnext,
2901 };
2902
2903#ifdef _WIN32
2904 if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2905 try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2906 ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2907 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2908#else
2909 if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
2910 (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
2911 try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2912 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2913
2914 if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_DMABUF_MEMORY &&
2915 hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
2916 try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2917 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2918#endif
2919
2920 for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2921 eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2922 eminfo[i].pNext = hwctx->alloc_pnext[i];
2923 eminfo[i].handleTypes = e;
2924 }
2925
2926 err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
2927 hwctx->nb_layers,
2928 eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
2929 if (err) {
2930 av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed: create_frame failed: %d\n", err);
2931 return NULL;
2932 }
2933
2934 err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2935 if (err)
2936 goto fail;
2937
2938 if ( (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2939 !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR))
2941 else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)
2943 else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR)
2945 else if (hwctx->usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
2946 err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_WRITE);
2947 else
2948 err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_GENERAL);
2949 if (err)
2950 goto fail;
2951
2952 avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2953 vulkan_frame_free_cb, hwfc, 0);
2954 if (!avbuf)
2955 goto fail;
2956
2957 return avbuf;
2958
2959fail:
2960 av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed with error %d\n", err);
2961 vulkan_frame_free(hwfc, f);
2962 return NULL;
2963}
2964
2969
2974
2976{
2977 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2978 VulkanFramesPriv *fp = hwfc->hwctx;
2979
2980 if (fp->modifier_info) {
2981 if (fp->modifier_info->pDrmFormatModifiers)
2982 av_freep(&fp->modifier_info->pDrmFormatModifiers);
2983 av_freep(&fp->modifier_info);
2984 }
2985
2986 ff_vk_exec_pool_free(&p->vkctx, &fp->compute_exec);
2987 ff_vk_exec_pool_free(&p->vkctx, &fp->upload_exec);
2988 ff_vk_exec_pool_free(&p->vkctx, &fp->download_exec);
2989
2991}
2992
2993/* Probes whether the host transfer usage bit is actually usable in combination
2994 * with the rest of the image creation parameters. Drivers may expose the
2995 * format feature, yet reject the final image, or provide no memory type from
2996 * which such an image can be allocated. Notably video decode/encode images
2997 * are often not possible to allocate from the host visible memory type. */
2999{
3000 VulkanFramesPriv *fp = hwfc->hwctx;
3001 AVVulkanFramesContext *hwctx = &fp->p;
3002 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
3003 AVVulkanDeviceContext *dev_hwctx = &p->p;
3004 FFVulkanFunctions *vk = &p->vkctx.vkfn;
3005 VkResult ret;
3006
3007 const VkImageDrmFormatModifierListCreateInfoEXT *mod_list =
3009 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
3010 int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
3011 mod_list && mod_list->drmFormatModifierCount;
3012 int nb_mods = has_mods ? mod_list->drmFormatModifierCount : 1;
3013
3014 /* Without a modifier list the final modifier is not knowable here. */
3015 if (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && !has_mods)
3016 return 0;
3017
3018 VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = {
3019 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
3020 .pQueueFamilyIndices = p->img_qfs,
3021 .queueFamilyIndexCount = p->nb_img_qfs,
3022 .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
3023 VK_SHARING_MODE_EXCLUSIVE,
3024 };
3025 VkPhysicalDeviceImageFormatInfo2 pinfo = {
3026 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
3027 .type = VK_IMAGE_TYPE_2D,
3028 .tiling = hwctx->tiling,
3029 .usage = hwctx->usage,
3030 .flags = hwctx->img_flags,
3031 };
3032
3033 if (has_mods)
3034 ff_vk_link_struct(&pinfo, &mod_info);
3035
3036 VkVideoProfileListInfoKHR profile_list;
3037 const VkVideoProfileListInfoKHR *pl =
3039 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
3040 if (pl) {
3041 profile_list = *pl;
3042 profile_list.pNext = NULL;
3043 ff_vk_link_struct(&pinfo, &profile_list);
3044 }
3045
3046 VkImageFormatListCreateInfo format_list;
3047 const VkImageFormatListCreateInfo *fl =
3049 VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO);
3050 if (fl) {
3051 format_list = *fl;
3052 format_list.pNext = NULL;
3053 ff_vk_link_struct(&pinfo, &format_list);
3054 }
3055
3056 /* The same usage is applied to the images of every plane, so each plane
3057 * format has to support host transfers for the usage to be usable. */
3058 for (int i = 0; i < AV_NUM_DATA_POINTERS &&
3059 hwctx->format[i] != VK_FORMAT_UNDEFINED; i++) {
3060 pinfo.format = hwctx->format[i];
3061
3062 /* The driver is free to pick any modifier from the list, so all of
3063 * them have to be compatible. */
3064 for (int j = 0; j < nb_mods; j++) {
3065 VkImageFormatProperties2 props = {
3066 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
3067 };
3068
3069 if (has_mods)
3070 mod_info.drmFormatModifier = mod_list->pDrmFormatModifiers[j];
3071
3072 ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
3073 &pinfo, &props);
3074 if (ret != VK_SUCCESS) {
3075 av_log(hwfc, AV_LOG_VERBOSE, "Disabling host image transfers: "
3076 "format %i is not supported: %s\n",
3077 pinfo.format, ff_vk_ret2str(ret));
3078 return 0;
3079 }
3080 }
3081 }
3082
3083 if (!p->vkctx.host_image_props.identicalMemoryTypeRequirements) {
3084 VkImageCreateInfo create_info = {
3085 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3086 .pNext = hwctx->create_pnext,
3087 .imageType = VK_IMAGE_TYPE_2D,
3088 .format = hwctx->format[0],
3089 .extent = { hwfc->width, hwfc->height, 1 },
3090 .mipLevels = 1,
3091 .arrayLayers = hwctx->nb_layers,
3092 .flags = hwctx->img_flags,
3093 .tiling = hwctx->tiling,
3094 .usage = hwctx->usage,
3095 .samples = VK_SAMPLE_COUNT_1_BIT,
3096 .pQueueFamilyIndices = p->img_qfs,
3097 .queueFamilyIndexCount = p->nb_img_qfs,
3098 .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
3099 VK_SHARING_MODE_EXCLUSIVE,
3100 };
3101 VkDeviceImageMemoryRequirements req_info = {
3102 .sType = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS,
3103 .pCreateInfo = &create_info,
3104 .planeAspect = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT ?
3105 VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT : 0,
3106 };
3107 VkMemoryRequirements2 req = {
3108 .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3109 };
3110
3111 vk->GetDeviceImageMemoryRequirements(dev_hwctx->act_dev, &req_info, &req);
3112 if (!req.memoryRequirements.memoryTypeBits) {
3113 av_log(hwfc, AV_LOG_VERBOSE, "Disabling host image transfers: "
3114 "no compatible memory type\n");
3115 return 0;
3116 }
3117 }
3118
3119 return 1;
3120}
3121
3123{
3124 int err;
3125 AVVkFrame *f;
3126 VulkanFramesPriv *fp = hwfc->hwctx;
3127 AVVulkanFramesContext *hwctx = &fp->p;
3128 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
3129 AVVulkanDeviceContext *dev_hwctx = &p->p;
3130 VkImageUsageFlags supported_usage;
3131 FFVulkanFunctions *vk = &p->vkctx.vkfn;
3132 const struct FFVkFormatEntry *fmt;
3133 int disable_multiplane = p->disable_multiplane ||
3135 int is_lone_dpb = ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR) ||
3136 ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
3137 !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)));
3138
3139 /* Defaults */
3140 if (!hwctx->nb_layers)
3141 hwctx->nb_layers = 1;
3142
3143 /* VK_IMAGE_TILING_OPTIMAL == 0, can't check for it really */
3144 if (p->use_linear_images &&
3145 (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
3146 hwctx->tiling = VK_IMAGE_TILING_LINEAR;
3147
3148
3149 fmt = vk_find_format_entry(hwfc->sw_format);
3150 if (!fmt) {
3151 av_log(hwfc, AV_LOG_ERROR, "Unsupported pixel format: %s!\n",
3153 return AVERROR(ENOTSUP);
3154 }
3155
3156 if (hwctx->format[0] != VK_FORMAT_UNDEFINED) {
3157 if (hwctx->format[0] != fmt->vkf) {
3158 for (int i = 0; i < fmt->nb_images_fallback; i++) {
3159 if (hwctx->format[i] != fmt->fallback[i]) {
3160 av_log(hwfc, AV_LOG_ERROR, "Incompatible Vulkan format given "
3161 "for the current sw_format %s!\n",
3163 return AVERROR(EINVAL);
3164 }
3165 }
3166 }
3167
3168 /* Check if the sw_format itself is supported */
3169 err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3170 hwctx->tiling, NULL,
3171 NULL, NULL, &supported_usage, 0,
3172 !hwctx->usage ||
3173 (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3174 if (err < 0) {
3175 av_log(hwfc, AV_LOG_ERROR, "Unsupported sw format: %s!\n",
3177 return AVERROR(EINVAL);
3178 }
3179 } else {
3180 err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3181 hwctx->tiling, hwctx->format, NULL,
3182 NULL, &supported_usage,
3183 disable_multiplane,
3184 !hwctx->usage ||
3185 (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3186 if (err < 0)
3187 return err;
3188 }
3189
3190 /* Lone DPB images do not need additional flags. */
3191 /* With DRM modifier + video profile the caller has already chosen a valid
3192 * usage/img_flags/chain; do not add usage or img_flags (supported_usage does
3193 * not consider the actual modifier or video profile). */
3194 int drm_mod_with_video = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
3196 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
3197
3198 if (!is_lone_dpb && !drm_mod_with_video) {
3199 /* Image usage flags */
3200 hwctx->usage |= supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
3201 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
3202 VK_IMAGE_USAGE_STORAGE_BIT |
3203 VK_IMAGE_USAGE_SAMPLED_BIT);
3204
3205 /* Frames which may double as active references (coinciding decode
3206 * output) cannot support host transfers: decode submissions bake the
3207 * image layout into their barriers at record time, so a host-side
3208 * layout transition cannot be synchronized against them, not even
3209 * by the frame lock and timeline semaphore. */
3210 if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY &&
3211 !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR))
3212 hwctx->usage |= supported_usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
3213
3214 /* Enables encoding of images, if supported by format and extensions */
3215 if ((supported_usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3216 (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3217 (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1))
3218 hwctx->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
3219
3220 /* Image creation flags.
3221 * Only fill them in automatically if the image is not going to be used as
3222 * a DPB-only image, and we have SAMPLED/STORAGE bits set. */
3223 if (!hwctx->img_flags) {
3224 int sampleable = hwctx->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
3225 VK_IMAGE_USAGE_STORAGE_BIT);
3226 hwctx->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
3227 if (sampleable) {
3228 hwctx->img_flags |= VK_IMAGE_CREATE_ALIAS_BIT;
3229 if ((fmt->vk_planes > 1) && (hwctx->format[0] == fmt->vkf))
3230 hwctx->img_flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
3231 }
3232 }
3233 }
3234
3235 /* If the image has an ENCODE_SRC usage, and the maintenance1
3236 * extension is supported, check if it has a profile list.
3237 * If there's no profile list, or it has no encode operations,
3238 * then allow creating the image with no specific profile. */
3239 if ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3240 (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3241 (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) {
3242 const VkVideoProfileListInfoKHR *pl;
3243 pl = ff_vk_find_struct(hwctx->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
3244 if (!pl) {
3245 hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3246 } else {
3247 uint32_t i;
3248 for (i = 0; i < pl->profileCount; i++) {
3249 /* Video ops start at exactly 0x00010000 */
3250 if (pl->pProfiles[i].videoCodecOperation & 0xFFFF0000)
3251 break;
3252 }
3253 if (i == pl->profileCount)
3254 hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3255 }
3256 }
3257
3258 /* Drop the host transfer if it isn't usable for this image configuration. */
3259 if ((hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) &&
3261 hwctx->usage &= ~VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
3262
3263 if (!hwctx->lock_frame)
3264 hwctx->lock_frame = lock_frame;
3265
3266 if (!hwctx->unlock_frame)
3267 hwctx->unlock_frame = unlock_frame;
3268
3269 err = ff_vk_exec_pool_init(&p->vkctx, p->compute_qf, &fp->compute_exec,
3270 2, 0, 0, 0, NULL);
3271 if (err)
3272 return err;
3273
3274 err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->upload_exec,
3276 if (err)
3277 return err;
3278
3279 err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->download_exec,
3280 2, 0, 0, 0, NULL);
3281 if (err)
3282 return err;
3283
3284 /* Test to see if allocation will fail */
3285 err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
3286 hwctx->nb_layers, hwctx->create_pnext);
3287 if (err)
3288 return err;
3289
3290 /* Collect `VkDrmFormatModifierPropertiesEXT` for each plane. Required for DRM export. */
3291 if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS && hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
3292 VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3293 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3294 };
3295 err = vk->GetImageDrmFormatModifierPropertiesEXT(dev_hwctx->act_dev, f->img[0],
3296 &drm_mod);
3297 if (err != VK_SUCCESS) {
3298 av_log(hwfc, AV_LOG_ERROR, "Failed to get image DRM format modifier properties");
3299 vulkan_frame_free(hwfc, f);
3300 return AVERROR_EXTERNAL;
3301 }
3302 for (int i = 0; i < fmt->vk_planes; ++i) {
3303 VkDrmFormatModifierPropertiesListEXT modp;
3304 VkFormatProperties2 fmtp;
3305 VkDrmFormatModifierPropertiesEXT *mod_props = NULL;
3306
3307 modp = (VkDrmFormatModifierPropertiesListEXT) {
3308 .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
3309 };
3310 fmtp = (VkFormatProperties2) {
3311 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
3312 .pNext = &modp,
3313 };
3314
3315 /* query drmFormatModifierCount by keeping pDrmFormatModifierProperties NULL */
3316 vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3317
3318 modp.pDrmFormatModifierProperties =
3319 av_calloc(modp.drmFormatModifierCount, sizeof(*modp.pDrmFormatModifierProperties));
3320 if (!modp.pDrmFormatModifierProperties) {
3321 vulkan_frame_free(hwfc, f);
3322 return AVERROR(ENOMEM);
3323 }
3324 vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3325
3326 for (uint32_t j = 0; j < modp.drmFormatModifierCount; ++j) {
3327 VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[j];
3328 if (m->drmFormatModifier == drm_mod.drmFormatModifier) {
3329 mod_props = m;
3330 break;
3331 }
3332 }
3333
3334 if (mod_props == NULL) {
3335 av_log(hwfc, AV_LOG_ERROR, "No DRM format modifier properties found for modifier 0x%016"PRIx64"\n",
3336 drm_mod.drmFormatModifier);
3337 av_free(modp.pDrmFormatModifierProperties);
3338 vulkan_frame_free(hwfc, f);
3339 return AVERROR_EXTERNAL;
3340 }
3341
3342 fp->drm_format_modifier_properties[i] = *mod_props;
3343 av_free(modp.pDrmFormatModifierProperties);
3344 }
3345 }
3346
3347 vulkan_frame_free(hwfc, f);
3348
3349 /* If user did not specify a pool, hwfc->pool will be set to the internal one
3350 * in hwcontext.c just after this gets called */
3351 if (!hwfc->pool) {
3353 hwfc, vulkan_pool_alloc,
3354 NULL);
3355 if (!ffhwframesctx(hwfc)->pool_internal)
3356 return AVERROR(ENOMEM);
3357 }
3358
3359 return 0;
3360}
3361
3363{
3364 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
3365 if (!frame->buf[0])
3366 return AVERROR(ENOMEM);
3367
3368 frame->data[0] = frame->buf[0]->data;
3369 frame->format = AV_PIX_FMT_VULKAN;
3370 frame->width = hwfc->width;
3371 frame->height = hwfc->height;
3372
3373 return 0;
3374}
3375
3378 enum AVPixelFormat **formats)
3379{
3380 enum AVPixelFormat *fmts;
3381 int n = 2;
3382
3383#if CONFIG_CUDA
3384 n++;
3385#endif
3386 fmts = av_malloc_array(n, sizeof(*fmts));
3387 if (!fmts)
3388 return AVERROR(ENOMEM);
3389
3390 n = 0;
3391 fmts[n++] = hwfc->sw_format;
3392#if CONFIG_CUDA
3393 fmts[n++] = AV_PIX_FMT_CUDA;
3394#endif
3395 fmts[n++] = AV_PIX_FMT_NONE;
3396
3397 *formats = fmts;
3398 return 0;
3399}
3400
3401#if CONFIG_LIBDRM
3402static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3403{
3404 vulkan_frame_free(hwfc, hwmap->priv);
3405}
3406
3407static const struct {
3408 uint32_t drm_fourcc;
3409 VkFormat vk_format;
3410} vulkan_drm_format_map[] = {
3411 { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
3412 { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
3413 { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
3414 { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
3415 { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
3416 { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
3417 { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3418 { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3419 { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3420 { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3421 { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3422 { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3423 { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3424 { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3425
3426 // All these DRM_FORMATs were added in the same libdrm commit.
3427#ifdef DRM_FORMAT_XYUV8888
3428 { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
3429 { DRM_FORMAT_XVYU2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 } ,
3430 { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 } ,
3431 { DRM_FORMAT_XVYU16161616, VK_FORMAT_R16G16B16A16_UNORM } ,
3432#endif
3433};
3434
3435static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
3436{
3437 for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3438 if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
3439 return vulkan_drm_format_map[i].vk_format;
3440 return VK_FORMAT_UNDEFINED;
3441}
3442
3443static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
3444 const AVFrame *src, int flags)
3445{
3446 int err = 0;
3447 VkResult ret;
3448 AVVkFrame *f;
3449 int bind_counts = 0;
3451 VulkanDevicePriv *p = ctx->hwctx;
3452 AVVulkanDeviceContext *hwctx = &p->p;
3453 FFVulkanFunctions *vk = &p->vkctx.vkfn;
3455 VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
3456 VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
3457
3458 for (int i = 0; i < desc->nb_layers; i++) {
3459 if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
3460 av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
3461 desc->layers[i].format);
3462 return AVERROR(EINVAL);
3463 }
3464 }
3465
3466 if (!(f = av_vk_frame_alloc())) {
3467 av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
3468 err = AVERROR(ENOMEM);
3469 goto fail;
3470 }
3471
3472 f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
3473
3474 for (int i = 0; i < desc->nb_layers; i++) {
3475 const int planes = desc->layers[i].nb_planes;
3476
3477 /* Semaphore */
3478 VkSemaphoreTypeCreateInfo sem_type_info = {
3479 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3480 .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
3481 .initialValue = 0,
3482 };
3483 VkSemaphoreCreateInfo sem_spawn = {
3484 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3485 .pNext = &sem_type_info,
3486 };
3487
3488 /* Image creation */
3489 VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
3490 VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
3491 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
3492 .drmFormatModifier = desc->objects[0].format_modifier,
3493 .drmFormatModifierPlaneCount = planes,
3494 .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
3495 };
3496 VkExternalMemoryImageCreateInfo ext_img_spec = {
3497 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
3498 .pNext = &ext_img_mod_spec,
3499 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3500 };
3501 VkImageCreateInfo create_info = {
3502 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3503 .pNext = &ext_img_spec,
3504 .imageType = VK_IMAGE_TYPE_2D,
3505 .format = drm_to_vulkan_fmt(desc->layers[i].format),
3506 .extent.depth = 1,
3507 .mipLevels = 1,
3508 .arrayLayers = 1,
3509 .flags = 0x0,
3510 .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
3511 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
3512 .usage = 0x0, /* filled in below */
3513 .samples = VK_SAMPLE_COUNT_1_BIT,
3514 .pQueueFamilyIndices = p->img_qfs,
3515 .queueFamilyIndexCount = p->nb_img_qfs,
3516 .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
3517 VK_SHARING_MODE_EXCLUSIVE,
3518 };
3519
3520 /* The DRM fourcc fixes a specific channel order (f.ex ARGB8888 maps to
3521 * B8G8R8A8), but image views are always created from the destination
3522 * frames context sw_format (like how bgra maps to R8G8B8A8). For a
3523 * single plane layer, create the image with the sw_format's compatible
3524 * VkFormat so the image and its views agree without a mutable format
3525 * list, the format query below validates this */
3526 if (planes == 1) {
3527 const VkFormat *sw_vkfmts = av_vkfmt_from_pixfmt(hwfc->sw_format);
3528 if (sw_vkfmts && sw_vkfmts[i] != VK_FORMAT_UNDEFINED)
3529 create_info.format = sw_vkfmts[i];
3530 }
3531
3532 /* Image format verification */
3533 VkExternalImageFormatProperties ext_props = {
3534 .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
3535 };
3536 VkImageFormatProperties2 props_ret = {
3537 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
3538 .pNext = &ext_props,
3539 };
3540 VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
3541 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
3542 .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
3543 .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
3544 .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
3545 .sharingMode = create_info.sharingMode,
3546 };
3547 VkPhysicalDeviceExternalImageFormatInfo props_ext = {
3548 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
3549 .pNext = &props_drm_mod,
3550 .handleType = ext_img_spec.handleTypes,
3551 };
3552 VkPhysicalDeviceImageFormatInfo2 fmt_props;
3553
3555 create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT |
3556 VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
3558 create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT |
3559 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
3560
3561 fmt_props = (VkPhysicalDeviceImageFormatInfo2) {
3562 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
3563 .pNext = &props_ext,
3564 .format = create_info.format,
3565 .type = create_info.imageType,
3566 .tiling = create_info.tiling,
3567 .usage = create_info.usage,
3568 .flags = create_info.flags,
3569 };
3570
3571 /* Check if importing is possible for this combination of parameters */
3572 ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
3573 &fmt_props, &props_ret);
3574 if (ret != VK_SUCCESS) {
3575 av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
3576 ff_vk_ret2str(ret));
3577 err = AVERROR_EXTERNAL;
3578 goto fail;
3579 }
3580
3581 /* Set the image width/height */
3582 get_plane_wh(&create_info.extent.width, &create_info.extent.height,
3583 hwfc->sw_format, src->width, src->height, i);
3584
3585 /* Set the subresource layout based on the layer properties */
3586 for (int j = 0; j < planes; j++) {
3587 ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
3588 ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
3589 ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
3590 ext_img_layouts[j].arrayPitch = 0;
3591 ext_img_layouts[j].depthPitch = 0;
3592 }
3593
3594 /* Create image */
3595 ret = vk->CreateImage(hwctx->act_dev, &create_info,
3596 hwctx->alloc, &f->img[i]);
3597 if (ret != VK_SUCCESS) {
3598 av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
3599 ff_vk_ret2str(ret));
3600 err = AVERROR(EINVAL);
3601 goto fail;
3602 }
3603
3604 ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3605 hwctx->alloc, &f->sem[i]);
3606 if (ret != VK_SUCCESS) {
3607 av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3608 ff_vk_ret2str(ret));
3609 err = AVERROR_EXTERNAL;
3610 goto fail;
3611 }
3612
3613 f->queue_family[i] = VK_QUEUE_FAMILY_EXTERNAL;
3614 f->layout[i] = create_info.initialLayout;
3615 f->access[i] = 0x0;
3616 f->sem_value[i] = 0;
3617 }
3618
3619 for (int i = 0; i < desc->nb_layers; i++) {
3620 /* Memory requirements */
3621 VkImageMemoryRequirementsInfo2 req_desc = {
3622 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
3623 .image = f->img[i],
3624 };
3625 VkMemoryDedicatedRequirements ded_req = {
3626 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
3627 };
3628 VkMemoryRequirements2 req2 = {
3629 .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3630 .pNext = &ded_req,
3631 };
3632
3633 /* Allocation/importing */
3634 VkMemoryFdPropertiesKHR fdmp = {
3635 .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
3636 };
3637 /* This assumes that a layer will never be constructed from multiple
3638 * objects. If that was to happen in the real world, this code would
3639 * need to import each plane separately.
3640 */
3641 VkImportMemoryFdInfoKHR idesc = {
3642 .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
3643 .fd = dup(desc->objects[desc->layers[i].planes[0].object_index].fd),
3644 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3645 };
3646 VkMemoryDedicatedAllocateInfo ded_alloc = {
3647 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
3648 .pNext = &idesc,
3649 .image = req_desc.image,
3650 };
3651
3652 /* Get object properties */
3653 ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
3654 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3655 idesc.fd, &fdmp);
3656 if (ret != VK_SUCCESS) {
3657 av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
3658 ff_vk_ret2str(ret));
3659 err = AVERROR_EXTERNAL;
3660 close(idesc.fd);
3661 goto fail;
3662 }
3663
3664 vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
3665
3666 /* Only a single bit must be set, not a range, and it must match */
3667 req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
3668
3669 err = alloc_mem(ctx, &req2.memoryRequirements,
3670 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
3671 (ded_req.prefersDedicatedAllocation ||
3672 ded_req.requiresDedicatedAllocation) ?
3673 &ded_alloc : ded_alloc.pNext,
3674 &f->flags, &f->mem[i]);
3675 if (err) {
3676 close(idesc.fd);
3677 goto fail;
3678 }
3679
3680 f->size[i] = req2.memoryRequirements.size;
3681 }
3682
3683 for (int i = 0; i < desc->nb_layers; i++) {
3684 const int planes = desc->layers[i].nb_planes;
3685 for (int j = 0; j < planes; j++) {
3686 VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
3687 j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
3688 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
3689
3690 plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
3691 plane_info[bind_counts].pNext = NULL;
3692 plane_info[bind_counts].planeAspect = aspect;
3693
3694 bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
3695 bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
3696 bind_info[bind_counts].image = f->img[i];
3697 bind_info[bind_counts].memory = f->mem[i];
3698
3699 /* Offset is already signalled via pPlaneLayouts above */
3700 bind_info[bind_counts].memoryOffset = 0;
3701
3702 bind_counts++;
3703 }
3704 }
3705
3706 /* Bind the allocated memory to the images */
3707 ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
3708 if (ret != VK_SUCCESS) {
3709 av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
3710 ff_vk_ret2str(ret));
3711 err = AVERROR_EXTERNAL;
3712 goto fail;
3713 }
3714
3715 *frame = f;
3716
3717 return 0;
3718
3719fail:
3720 vulkan_frame_free(hwfc, f);
3721
3722 return err;
3723}
3724
3725static int vulkan_map_from_drm_frame_sync(AVHWFramesContext *hwfc, AVFrame *dst,
3726 const AVDRMFrameDescriptor *desc, int flags)
3727{
3728 int err;
3729 VkResult ret;
3731 VulkanDevicePriv *p = ctx->hwctx;
3732 VulkanFramesPriv *fp = hwfc->hwctx;
3733 AVVulkanDeviceContext *hwctx = &p->p;
3734 FFVulkanFunctions *vk = &p->vkctx.vkfn;
3735
3736#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
3737 if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) {
3738 VkCommandBuffer cmd_buf;
3739 FFVkExecContext *exec;
3740 VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
3741 VkSemaphore drm_sync_sem[AV_DRM_MAX_PLANES] = { 0 };
3742 int nb_img_bar = 0;
3743
3744 for (int i = 0; i < desc->nb_objects; i++) {
3745 VkSemaphoreTypeCreateInfo sem_type_info = {
3746 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3747 .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
3748 };
3749 VkSemaphoreCreateInfo sem_spawn = {
3750 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3751 .pNext = &sem_type_info,
3752 };
3753 VkImportSemaphoreFdInfoKHR import_info;
3754 struct dma_buf_export_sync_file implicit_fd_info = {
3755 .flags = DMA_BUF_SYNC_READ,
3756 .fd = -1,
3757 };
3758
3759 if (ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
3760 &implicit_fd_info)) {
3761 err = AVERROR(errno);
3762 av_log(hwctx, AV_LOG_ERROR, "Failed to retrieve implicit DRM sync file: %s\n",
3763 av_err2str(err));
3764 for (; i >= 0; i--)
3765 vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3766 return err;
3767 }
3768
3769 ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3770 hwctx->alloc, &drm_sync_sem[i]);
3771 if (ret != VK_SUCCESS) {
3772 av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3773 ff_vk_ret2str(ret));
3774 err = AVERROR_EXTERNAL;
3775 for (; i >= 0; i--)
3776 vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3777 return err;
3778 }
3779
3780 import_info = (VkImportSemaphoreFdInfoKHR) {
3781 .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
3782 .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
3783 .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
3784 .semaphore = drm_sync_sem[i],
3785 .fd = implicit_fd_info.fd,
3786 };
3787
3788 ret = vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info);
3789 if (ret != VK_SUCCESS) {
3790 av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n",
3791 ff_vk_ret2str(ret));
3792 err = AVERROR_EXTERNAL;
3793 for (; i >= 0; i--)
3794 vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3795 return err;
3796 }
3797 }
3798
3799 exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
3800 cmd_buf = exec->buf;
3801
3802 err = ff_vk_exec_start(&p->vkctx, exec);
3803 if (err < 0) {
3804 for (int i = 0; i < desc->nb_objects; i++)
3805 vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3806 return err;
3807 }
3808
3809 /* Ownership of semaphores is passed */
3810 ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec,
3811 drm_sync_sem, desc->nb_objects,
3812 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1);
3813
3814 err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, dst,
3815 VK_PIPELINE_STAGE_2_NONE,
3816 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
3817 if (err < 0) {
3818 ff_vk_exec_discard(&p->vkctx, exec);
3819 return err;
3820 }
3821
3822 ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar,
3823 VK_PIPELINE_STAGE_2_NONE,
3824 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
3826 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT : 0x0) |
3828 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT : 0x0),
3829 VK_IMAGE_LAYOUT_GENERAL,
3830 p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
3831
3832 vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
3833 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
3834 .pImageMemoryBarriers = img_bar,
3835 .imageMemoryBarrierCount = nb_img_bar,
3836 });
3837
3838 err = ff_vk_exec_submit(&p->vkctx, exec);
3839 if (err < 0)
3840 return err;
3841 } else
3842#endif
3843 {
3844 AVVkFrame *f = (AVVkFrame *)dst->data[0];
3845 av_log(hwctx, AV_LOG_WARNING, "No support for synchronization when importing DMA-BUFs, "
3846 "image may be corrupted.\n");
3848 if (err)
3849 return err;
3850 }
3851
3852 return 0;
3853}
3854
3855static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3856 const AVFrame *src, int flags)
3857{
3858 int err = 0;
3859 AVVkFrame *f;
3861
3862 if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src, flags)))
3863 return err;
3864
3865 /* The unmapping function will free this */
3866 dst->data[0] = (uint8_t *)f;
3867 dst->width = src->width;
3868 dst->height = src->height;
3869
3870 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
3871 &vulkan_unmap_from_drm, f);
3872 if (err < 0)
3873 goto fail;
3874
3875 err = vulkan_map_from_drm_frame_sync(hwfc, dst, desc, flags);
3876 if (err < 0)
3877 return err;
3878
3879 av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
3880
3881 return 0;
3882
3883fail:
3885 dst->data[0] = NULL;
3886 return err;
3887}
3888
3889#if CONFIG_VAAPI
3890static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
3891 AVFrame *dst, const AVFrame *src,
3892 int flags)
3893{
3894 int err;
3896 AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3897 AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
3898 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
3899
3900 if (!tmp)
3901 return AVERROR(ENOMEM);
3902
3903 /* We have to sync since like the previous comment said, no semaphores */
3904 vaSyncSurface(vaapi_ctx->display, surface_id);
3905
3906 tmp->format = AV_PIX_FMT_DRM_PRIME;
3907
3908 err = av_hwframe_map(tmp, src, flags);
3909 if (err < 0)
3910 goto fail;
3911
3912 err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
3913 if (err < 0)
3914 goto fail;
3915
3917
3918fail:
3920 return err;
3921}
3922#endif
3923#endif
3924
3925#if CONFIG_CUDA
3926static int export_mem_to_cuda(AVHWDeviceContext *ctx,
3927 AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3928 AVVkFrameInternal *dst_int, int idx,
3929 VkDeviceMemory mem, size_t size)
3930{
3931 VkResult ret;
3932 VulkanDevicePriv *p = ctx->hwctx;
3933 AVVulkanDeviceContext *hwctx = &p->p;
3934 FFVulkanFunctions *vk = &p->vkctx.vkfn;
3935
3936#ifdef _WIN32
3937 CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3938 .type = IsWindows8OrGreater()
3939 ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3940 : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
3941 .size = size,
3942 };
3943 VkMemoryGetWin32HandleInfoKHR export_info = {
3944 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
3945 .memory = mem,
3946 .handleType = IsWindows8OrGreater()
3947 ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3948 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3949 };
3950
3951 ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
3952 &ext_desc.handle.win32.handle);
3953 if (ret != VK_SUCCESS) {
3954 av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
3955 ff_vk_ret2str(ret));
3956 return AVERROR_EXTERNAL;
3957 }
3958 dst_int->ext_mem_handle[idx] = ext_desc.handle.win32.handle;
3959#else
3960 CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3961 .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
3962 .size = size,
3963 };
3964 VkMemoryGetFdInfoKHR export_info = {
3965 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3966 .memory = mem,
3967 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
3968 };
3969
3970 ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3971 &ext_desc.handle.fd);
3972 if (ret != VK_SUCCESS) {
3973 av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
3974 ff_vk_ret2str(ret));
3975 return AVERROR_EXTERNAL;
3976 }
3977#endif
3978
3979 ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[idx], &ext_desc));
3980 if (ret < 0) {
3981#ifndef _WIN32
3982 close(ext_desc.handle.fd);
3983#endif
3984 return AVERROR_EXTERNAL;
3985 }
3986
3987 return 0;
3988}
3989
3990static int export_sem_to_cuda(AVHWDeviceContext *ctx,
3991 AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3992 AVVkFrameInternal *dst_int, int idx,
3993 VkSemaphore sem)
3994{
3995 VkResult ret;
3996 VulkanDevicePriv *p = ctx->hwctx;
3997 AVVulkanDeviceContext *hwctx = &p->p;
3998 FFVulkanFunctions *vk = &p->vkctx.vkfn;
3999
4000#ifdef _WIN32
4001 VkSemaphoreGetWin32HandleInfoKHR sem_export = {
4002 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
4003 .semaphore = sem,
4004 .handleType = IsWindows8OrGreater()
4005 ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
4006 : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
4007 };
4008 CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
4009 .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
4010 };
4011#else
4012 VkSemaphoreGetFdInfoKHR sem_export = {
4013 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
4014 .semaphore = sem,
4015 .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
4016 };
4017 CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
4018 .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
4019 };
4020#endif
4021
4022#ifdef _WIN32
4023 ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
4024 &ext_sem_desc.handle.win32.handle);
4025#else
4026 ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
4027 &ext_sem_desc.handle.fd);
4028#endif
4029 if (ret != VK_SUCCESS) {
4030 av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
4031 ff_vk_ret2str(ret));
4032 return AVERROR_EXTERNAL;
4033 }
4034#ifdef _WIN32
4035 dst_int->ext_sem_handle[idx] = ext_sem_desc.handle.win32.handle;
4036#endif
4037
4038 ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[idx],
4039 &ext_sem_desc));
4040 if (ret < 0) {
4041#ifndef _WIN32
4042 close(ext_sem_desc.handle.fd);
4043#endif
4044 return AVERROR_EXTERNAL;
4045 }
4046
4047 return 0;
4048}
4049
4050static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
4051 AVBufferRef *cuda_hwfc,
4052 const AVFrame *frame)
4053{
4054 int err;
4055 VkResult ret;
4056 AVVkFrame *dst_f;
4057 AVVkFrameInternal *dst_int;
4059 const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4061 VulkanDevicePriv *p = ctx->hwctx;
4062 AVVulkanDeviceContext *hwctx = &p->p;
4063 FFVulkanFunctions *vk = &p->vkctx.vkfn;
4064 int nb_images;
4065
4066 AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
4067 AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4068 AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4069 AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4070 CudaFunctions *cu = cu_internal->cuda_dl;
4071 CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
4072 CU_AD_FORMAT_UNSIGNED_INT8;
4073 const int elem_size = 1 + (desc->comp[0].depth > 8);
4074
4075 dst_f = (AVVkFrame *)frame->data[0];
4076 dst_int = dst_f->internal;
4077
4078 if (!dst_int->cuda_fc_ref) {
4079 size_t offsets[3] = { 0 };
4080
4081 dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
4082 if (!dst_int->cuda_fc_ref)
4083 return AVERROR(ENOMEM);
4084
4085 nb_images = ff_vk_count_images(dst_f);
4086 for (int i = 0; i < nb_images; i++) {
4087 err = export_mem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
4088 dst_f->mem[i], dst_f->size[i]);
4089 if (err < 0)
4090 goto fail;
4091
4092 err = export_sem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
4093 dst_f->sem[i]);
4094 if (err < 0)
4095 goto fail;
4096 }
4097
4098 if (nb_images != planes) {
4099 for (int i = 0; i < planes; i++) {
4100 /* Cuda now defines array formats for semi-planar, but these are
4101 * not currently supported for imported Vulkan images. */
4102 if (desc->comp[i].step / elem_size > 1) {
4104 "Cannot map a multiplane Vulkan image (%d image(s) "
4105 "for %d plane(s)) to CUDA; create the Vulkan device "
4106 "with the disable_multiplane=1 option (one image per "
4107 "plane) for CUDA interop.\n", nb_images, planes);
4108 err = AVERROR(ENOSYS);
4109 goto fail;
4110 }
4111
4112 VkImageSubresource subres = {
4113 .aspectMask = i == 2 ? VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT :
4114 i == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
4115 VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
4116 };
4117 VkSubresourceLayout layout = { 0 };
4118 vk->GetImageSubresourceLayout(hwctx->act_dev, dst_f->img[FFMIN(i, nb_images - 1)],
4119 &subres, &layout);
4120 offsets[i] = layout.offset;
4121 }
4122 }
4123
4124 for (int i = 0; i < planes; i++) {
4125 CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
4126 .offset = offsets[i],
4127 .arrayDesc = {
4128 .Depth = 0,
4129 .Format = cufmt,
4130 .NumChannels = desc->comp[i].step / elem_size,
4131 .Flags = 0,
4132 },
4133 .numLevels = 1,
4134 };
4135 int p_w, p_h;
4136
4137 get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4138 tex_desc.arrayDesc.Width = p_w;
4139 tex_desc.arrayDesc.Height = p_h;
4140
4141 ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
4142 dst_int->ext_mem[FFMIN(i, nb_images - 1)],
4143 &tex_desc));
4144 if (ret < 0) {
4145 err = AVERROR_EXTERNAL;
4146 goto fail;
4147 }
4148
4149 ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
4150 dst_int->cu_mma[i], 0));
4151 if (ret < 0) {
4152 err = AVERROR_EXTERNAL;
4153 goto fail;
4154 }
4155
4156 }
4157 }
4158
4159 return 0;
4160
4161fail:
4162 vulkan_free_internal(p, dst_f);
4163 return err;
4164}
4165
4166static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
4167 AVFrame *dst, const AVFrame *src)
4168{
4169 int err;
4170 CUcontext dummy;
4171 AVVkFrame *dst_f;
4172 AVVkFrameInternal *dst_int;
4174 VulkanFramesPriv *fp = hwfc->hwctx;
4175 const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4177 int nb_images;
4178
4179 AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
4180 AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4181 AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4182 AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4183 CudaFunctions *cu = cu_internal->cuda_dl;
4184 CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4185 CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4186
4187 dst_f = (AVVkFrame *)dst->data[0];
4188 nb_images = ff_vk_count_images(dst_f);
4189
4190 err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4191 if (err < 0)
4192 return err;
4193
4194 err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4195 if (err < 0)
4196 return err;
4197
4198 err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
4199 if (err < 0) {
4200 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4201 return err;
4202 }
4203
4204 dst_int = dst_f->internal;
4205
4206 for (int i = 0; i < nb_images; i++) {
4207 s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4208 s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4209 }
4210
4211 err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4212 nb_images, cuda_dev->stream));
4213 if (err < 0)
4214 goto fail;
4215
4216 for (int i = 0; i < planes; i++) {
4217 CUDA_MEMCPY2D cpy = {
4218 .srcMemoryType = CU_MEMORYTYPE_DEVICE,
4219 .srcDevice = (CUdeviceptr)src->data[i],
4220 .srcPitch = src->linesize[i],
4221 .srcY = 0,
4222
4223 .dstMemoryType = CU_MEMORYTYPE_ARRAY,
4224 .dstArray = dst_int->cu_array[i],
4225 };
4226
4227 int p_w, p_h;
4228 get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4229
4230 cpy.WidthInBytes = p_w * desc->comp[i].step;
4231 cpy.Height = p_h;
4232
4233 err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4234 if (err < 0)
4235 goto fail;
4236 }
4237
4238 err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4239 nb_images, cuda_dev->stream));
4240 if (err < 0)
4241 goto fail;
4242
4243 for (int i = 0; i < nb_images; i++)
4244 dst_f->sem_value[i]++;
4245
4246 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4247
4248 av_log(hwfc, AV_LOG_VERBOSE, "Transferred CUDA image to Vulkan!\n");
4249
4250 return err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4251
4252fail:
4253 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4254 vulkan_free_internal(p, dst_f);
4255 av_buffer_unref(&dst->buf[0]);
4256 return err;
4257}
4258#endif
4259
4261 const AVFrame *src, int flags)
4262{
4264
4265 switch (src->format) {
4266#if CONFIG_LIBDRM
4267#if CONFIG_VAAPI
4268 case AV_PIX_FMT_VAAPI:
4269 if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4270 return vulkan_map_from_vaapi(hwfc, dst, src, flags);
4271 else
4272 return AVERROR(ENOSYS);
4273#endif
4275 if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4276 return vulkan_map_from_drm(hwfc, dst, src, flags);
4277 else
4278 return AVERROR(ENOSYS);
4279#endif
4280 default:
4281 return AVERROR(ENOSYS);
4282 }
4283}
4284
4285#if CONFIG_LIBDRM
4286typedef struct VulkanDRMMapping {
4287 AVDRMFrameDescriptor drm_desc;
4288 AVVkFrame *source;
4289} VulkanDRMMapping;
4290
4291static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
4292{
4293 AVDRMFrameDescriptor *drm_desc = hwmap->priv;
4294
4295 /* on unmap from DRM, make sure to import sync objects so that we are sync'd with any work that was
4296 * done on the buffer while exported. We don't know if who used the dmabuf did reads or writes, so protect against both */
4297 vulkan_map_from_drm_frame_sync(hwfc, hwmap->source, drm_desc, AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE);
4298
4299 for (int i = 0; i < drm_desc->nb_objects; i++)
4300 close(drm_desc->objects[i].fd);
4301
4302 av_free(drm_desc);
4303}
4304
4305static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
4306{
4307 for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
4308 if (vulkan_drm_format_map[i].vk_format == vkfmt)
4309 return vulkan_drm_format_map[i].drm_fourcc;
4310 return DRM_FORMAT_INVALID;
4311}
4312
4313#define MAX_MEMORY_PLANES 4
4314static VkImageAspectFlags plane_index_to_aspect(int plane) {
4315 if (plane == 0) return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4316 if (plane == 1) return VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
4317 if (plane == 2) return VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
4318 if (plane == 3) return VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
4319
4320 av_assert2 (0 && "Invalid plane index");
4321 return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4322}
4323
4324#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4325static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
4326 VulkanFramesPriv *fp, int nb_sems)
4327{
4328 int sync_fd = -1;
4329 VkResult ret;
4331 AVVulkanDeviceContext *hwctx = &p->p;
4332 FFVulkanFunctions *vk = &p->vkctx.vkfn;
4333
4334 if (f->internal->drm_sync_sem == VK_NULL_HANDLE) {
4335 VkExportSemaphoreCreateInfo exp_info = {
4336 .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
4337 .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4338 };
4339 VkSemaphoreTypeCreateInfo type_info = {
4340 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
4341 .pNext = &exp_info,
4342 .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
4343 };
4344 VkSemaphoreCreateInfo sem_create = {
4345 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
4346 .pNext = &type_info,
4347 };
4348 ret = vk->CreateSemaphore(hwctx->act_dev, &sem_create, hwctx->alloc,
4349 &f->internal->drm_sync_sem);
4350 if (ret != VK_SUCCESS) {
4351 av_log(hwctx, AV_LOG_ERROR, "Failed to create DRM export semaphore: %s\n",
4352 ff_vk_ret2str(ret));
4353 return AVERROR_EXTERNAL;
4354 }
4355 }
4356
4357 /* Submit a lightweight exec that waits on the timeline semaphore
4358 * (true last operation on the frame) and signals the binary semaphore,
4359 * so any Vulkan frame can get a SYNC_FD regardless of origin. */
4360 FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
4361 if (ff_vk_exec_start(&p->vkctx, exec) >= 0) {
4362 for (int i = 0; i < nb_sems; i++)
4363 ff_vk_exec_add_dep_wait_sem(&p->vkctx, exec, f->sem[i],
4364 f->sem_value[i],
4365 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
4366 ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, &f->internal->drm_sync_sem, 1,
4367 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0);
4368 if (ff_vk_exec_submit(&p->vkctx, exec) >= 0) {
4369 VkSemaphoreGetFdInfoKHR get_fd_info = {
4370 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
4371 .semaphore = f->internal->drm_sync_sem,
4372 .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4373 };
4374 ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &get_fd_info, &sync_fd);
4375 if (ret != VK_SUCCESS) {
4376 av_log(hwctx, AV_LOG_WARNING,
4377 "Failed to get sync fd from DRM map export semaphore: %s\n",
4378 ff_vk_ret2str(ret));
4379 sync_fd = -1;
4380 }
4381 }
4382 }
4383
4384 return sync_fd;
4385}
4386#endif
4387
4388static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
4389 const AVFrame *src, int flags)
4390{
4391 int err = 0;
4392 VkResult ret;
4393 AVVkFrame *f = (AVVkFrame *)src->data[0];
4395 AVVulkanDeviceContext *hwctx = &p->p;
4396 FFVulkanFunctions *vk = &p->vkctx.vkfn;
4397 VulkanFramesPriv *fp = hwfc->hwctx;
4398 const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4399 const int nb_images = ff_vk_count_images(f);
4400 VkImageDrmFormatModifierPropertiesEXT drm_mod = {
4401 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
4402 };
4403 const int nb_sems = nb_images;
4404 int free_drm_desc_on_err = 1;
4405 int sync_fd = -1;
4406
4407 AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
4408 if (!drm_desc)
4409 return AVERROR(ENOMEM);
4410
4412 if (err < 0)
4413 goto end;
4414
4415#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4416 if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
4417 f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
4418 vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
4419 err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
4420 if (err < 0)
4421 goto end;
4422 sync_fd = err;
4423 err = 0;
4424 }
4425#endif
4426
4427 if (sync_fd < 0) {
4428 VkSemaphoreWaitInfo wait_info = {
4429 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4430 .flags = 0x0,
4431 .semaphoreCount = nb_sems,
4432 .pSemaphores = f->sem,
4433 .pValues = f->sem_value,
4434 };
4435 vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
4436 }
4437
4438 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
4439 if (err < 0)
4440 goto end;
4441
4442 /* It will be freed in ff_hwframe_map_create callback */
4443 free_drm_desc_on_err = 0;
4444
4445 ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
4446 &drm_mod);
4447 if (ret != VK_SUCCESS) {
4448 av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
4449 err = AVERROR_EXTERNAL;
4450 goto end;
4451 }
4452
4453 for (int i = 0; (i < planes) && (f->mem[i]); i++) {
4454 VkMemoryGetFdInfoKHR export_info = {
4455 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
4456 .memory = f->mem[i],
4457 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
4458 };
4459
4460 ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
4461 &drm_desc->objects[i].fd);
4462 if (ret != VK_SUCCESS) {
4463 av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
4464 err = AVERROR_EXTERNAL;
4465 goto end;
4466 }
4467
4468#if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
4469 if (sync_fd >= 0) {
4470 int dup_fd = dup(sync_fd);
4471 if (dup_fd >= 0) {
4472 struct dma_buf_import_sync_file import_info = {
4473 .flags = DMA_BUF_SYNC_WRITE,
4474 .fd = dup_fd,
4475 };
4476 if (ioctl(drm_desc->objects[i].fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_info) < 0)
4477 av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s\n", av_err2str(AVERROR(errno)));
4478 close(dup_fd);
4479 } else {
4480 av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
4481 }
4482 }
4483#endif
4484
4485 drm_desc->nb_objects++;
4486 drm_desc->objects[i].size = f->size[i];
4487 drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
4488 }
4489
4490 /* NV12 has 2 planes but 1 image/semaphore */
4491 drm_desc->nb_layers = FFMAX(planes, nb_images);
4492 for (int i = 0; i < drm_desc->nb_layers; i++) {
4493 VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
4494
4495 drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
4496 drm_desc->layers[i].nb_planes = fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount;
4497
4498 if (drm_desc->layers[i].nb_planes > MAX_MEMORY_PLANES) {
4499 av_log(hwfc, AV_LOG_ERROR, "Too many memory planes for DRM format!\n");
4500 err = AVERROR_EXTERNAL;
4501 goto end;
4502 }
4503
4504 for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
4505 VkSubresourceLayout layout;
4506 int aspect_plane = (nb_images == 1) ? i : j;
4507 VkImageSubresource sub = {
4508 .aspectMask = plane_index_to_aspect(aspect_plane),
4509 };
4510
4511 drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
4512
4513 vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[FFMIN(i, nb_images - 1)], &sub, &layout);
4514 drm_desc->layers[i].planes[j].offset = layout.offset;
4515 drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
4516 }
4517
4518 if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
4519 av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
4521 goto end;
4522 }
4523
4524
4525 if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
4526 continue;
4527
4528 }
4529
4530 dst->width = src->width;
4531 dst->height = src->height;
4532 dst->data[0] = (uint8_t *)drm_desc;
4533 dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
4534
4535 if (sync_fd >= 0)
4536 close(sync_fd);
4537
4538 av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
4539
4540 return 0;
4541
4542end:
4543 for (int i = 0; i < drm_desc->nb_objects; i++)
4544 close(drm_desc->objects[i].fd);
4545 if (free_drm_desc_on_err)
4546 av_free(drm_desc);
4547 if (sync_fd >= 0)
4548 close(sync_fd);
4549 return err;
4550}
4551
4552#if CONFIG_VAAPI
4553static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
4554 const AVFrame *src, int flags)
4555{
4556 int err;
4558 if (!tmp)
4559 return AVERROR(ENOMEM);
4560
4561 tmp->format = AV_PIX_FMT_DRM_PRIME;
4562
4563 err = vulkan_map_to_drm(hwfc, tmp, src, flags);
4564 if (err < 0)
4565 goto fail;
4566
4567 err = av_hwframe_map(dst, tmp, flags);
4568 if (err < 0)
4569 goto fail;
4570
4572
4573fail:
4575 return err;
4576}
4577#endif
4578#endif
4579
4581 const AVFrame *src, int flags)
4582{
4584
4585 switch (dst->format) {
4586#if CONFIG_LIBDRM
4588 if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4589 return vulkan_map_to_drm(hwfc, dst, src, flags);
4590 else
4591 return AVERROR(ENOSYS);
4592#if CONFIG_VAAPI
4593 case AV_PIX_FMT_VAAPI:
4594 if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4595 return vulkan_map_to_vaapi(hwfc, dst, src, flags);
4596 else
4597 return AVERROR(ENOSYS);
4598#endif
4599#endif
4600 default:
4601 break;
4602 }
4603 return AVERROR(ENOSYS);
4604}
4605
4607 AVFrame *swf, VkBufferImageCopy *region,
4608 int planes, int upload)
4609{
4610 int err;
4611 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4612
4613 if (upload) {
4614 for (int i = 0; i < planes; i++)
4615 av_image_copy_plane(vkbuf->mapped_mem + region[i].bufferOffset,
4616 region[i].bufferRowLength,
4617 swf->data[i],
4618 swf->linesize[i],
4619 swf->linesize[i],
4620 region[i].imageExtent.height);
4621
4622 err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 1);
4623 if (err != VK_SUCCESS) {
4624 av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n",
4625 av_err2str(err));
4626 return AVERROR_EXTERNAL;
4627 }
4628 } else {
4629 err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 0);
4630 if (err != VK_SUCCESS) {
4631 av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n",
4632 av_err2str(err));
4633 return AVERROR_EXTERNAL;
4634 }
4635
4636 for (int i = 0; i < planes; i++)
4638 swf->linesize[i],
4639 vkbuf->mapped_mem + region[i].bufferOffset,
4640 region[i].bufferRowLength,
4641 swf->linesize[i],
4642 region[i].imageExtent.height);
4643 }
4644
4645 return 0;
4646}
4647
4649 AVFrame *swf, VkBufferImageCopy *region, int upload)
4650{
4651 int err;
4652 uint32_t p_w, p_h;
4653 VulkanFramesPriv *fp = hwfc->hwctx;
4654 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4655 const int planes = av_pix_fmt_count_planes(swf->format);
4656 VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4657 VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4658
4659 size_t buf_offset = 0;
4660 for (int i = 0; i < planes; i++) {
4661 get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4662
4663 region[i] = (VkBufferImageCopy) {
4664 .bufferOffset = buf_offset,
4665 .bufferRowLength = FFALIGN(swf->linesize[i],
4666 p->props.properties.limits.optimalBufferCopyRowPitchAlignment),
4667 .bufferImageHeight = p_h,
4668 .imageSubresource.layerCount = 1,
4669 .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4670 /* Rest of the fields adjusted/filled in later */
4671 };
4672
4673 buf_offset += FFALIGN(p_h*region[i].bufferRowLength,
4674 p->props.properties.limits.optimalBufferCopyOffsetAlignment);
4675 }
4676
4677 err = ff_vk_get_pooled_buffer(&p->vkctx, &fp->tmp, dst, buf_usage,
4678 NULL, buf_offset,
4679 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
4680 p->vkctx.host_cached_flag);
4681 if (err < 0)
4682 return err;
4683
4684 return 0;
4685}
4686
4687static int host_map_frame(AVHWFramesContext *hwfc, FFVkBuffer **dst, int *nb_bufs,
4688 AVFrame *swf, VkBufferImageCopy *region, int upload)
4689{
4690 int err;
4691 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4692
4693 int nb_src_bufs;
4694 const int planes = av_pix_fmt_count_planes(swf->format);
4695 VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4696 VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4697
4698 /* We can't host map images with negative strides */
4699 for (int i = 0; i < planes; i++)
4700 if (swf->linesize[i] < 0)
4701 return AVERROR(EINVAL);
4702
4703 /* Count the number of buffers in the software frame */
4704 nb_src_bufs = 0;
4705 while (swf->buf[nb_src_bufs])
4706 nb_src_bufs++;
4707
4708 /* Single buffer contains all planes */
4709 if (nb_src_bufs == 1) {
4710 err = ff_vk_host_map_buffer(&p->vkctx, &dst[0],
4711 swf->data[0], VK_WHOLE_SIZE, swf->buf[0],
4712 buf_usage);
4713 if (err < 0)
4714 return err;
4715 (*nb_bufs)++;
4716
4717 for (int i = 0; i < planes; i++)
4718 region[i].bufferOffset = dst[0]->virtual_offset +
4719 swf->data[i] - swf->data[0];
4720 } else if (nb_src_bufs == planes) { /* One buffer per plane */
4721 for (int i = 0; i < planes; i++) {
4722 err = ff_vk_host_map_buffer(&p->vkctx, &dst[i],
4723 swf->data[i], VK_WHOLE_SIZE,
4724 swf->buf[i], buf_usage);
4725 if (err < 0)
4726 goto fail;
4727 (*nb_bufs)++;
4728
4729 region[i].bufferOffset = dst[i]->virtual_offset;
4730 }
4731 } else {
4732 /* Weird layout (3 planes, 2 buffers), patch welcome, fallback to copy */
4733 return AVERROR_PATCHWELCOME;
4734 }
4735
4736 return 0;
4737
4738fail:
4739 for (int i = 0; i < (*nb_bufs); i++)
4741 return err;
4742}
4743
4745 AVFrame *swf, int upload)
4746{
4747 VulkanFramesPriv *fp = hwfc->hwctx;
4748 AVVulkanFramesContext *hwfc_vk = &fp->p;
4749 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4750 AVVulkanDeviceContext *hwctx = &p->p;
4751 FFVulkanFunctions *vk = &p->vkctx.vkfn;
4752
4753 AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4755 const int planes = av_pix_fmt_count_planes(swf->format);
4756 const int nb_images = ff_vk_count_images(hwf_vk);
4757
4758 VkSemaphoreWaitInfo sem_wait;
4759 VkHostImageLayoutTransitionInfoEXT layout_ch_info[AV_NUM_DATA_POINTERS];
4760 int nb_layout_ch = 0;
4761
4762 hwfc_vk->lock_frame(hwfc, hwf_vk);
4763
4764 for (int i = 0; i < nb_images; i++) {
4765 int compat = 0;
4766 for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount; j++) {
4767 if (hwf_vk->layout[i] == p->vkctx.host_image_props.pCopySrcLayouts[j]) {
4768 compat = 1;
4769 break;
4770 }
4771 }
4772 if (compat)
4773 continue;
4774
4775 /* This should only ever happen on uploads, so using UNDEFINED is safe */
4776 av_assert1(upload);
4777 layout_ch_info[nb_layout_ch] = (VkHostImageLayoutTransitionInfoEXT) {
4778 .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
4779 .image = hwf_vk->img[i],
4780 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
4781 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
4782 .subresourceRange = {
4783 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4784 .levelCount = 1,
4785 .layerCount = 1,
4786 },
4787 };
4788
4789 hwf_vk->layout[i] = layout_ch_info[nb_layout_ch].newLayout;
4790 nb_layout_ch++;
4791 }
4792
4793 sem_wait = (VkSemaphoreWaitInfo) {
4794 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4795 .pSemaphores = hwf_vk->sem,
4796 .pValues = hwf_vk->sem_value,
4797 .semaphoreCount = nb_images,
4798 };
4799
4800 vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
4801
4802 if (nb_layout_ch)
4803 vk->TransitionImageLayoutEXT(hwctx->act_dev,
4804 nb_layout_ch, layout_ch_info);
4805
4806 if (upload) {
4807 VkMemoryToImageCopyEXT region_info = {
4808 .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
4809 .imageSubresource = {
4810 .layerCount = 1,
4811 },
4812 };
4813 VkCopyMemoryToImageInfoEXT copy_info = {
4814 .sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
4815 .regionCount = 1,
4816 .pRegions = &region_info,
4817 };
4818 for (int i = 0; i < planes; i++) {
4819 int img_idx = FFMIN(i, (nb_images - 1));
4820 uint32_t p_w, p_h;
4821 get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4822
4823 region_info.pHostPointer = swf->data[i];
4824 region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4825 region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4826 region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4827 copy_info.dstImage = hwf_vk->img[img_idx];
4828 copy_info.dstImageLayout = hwf_vk->layout[img_idx];
4829
4830 vk->CopyMemoryToImageEXT(hwctx->act_dev, &copy_info);
4831 }
4832 } else {
4833 VkImageToMemoryCopyEXT region_info = {
4834 .sType = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT,
4835 .imageSubresource = {
4836 .layerCount = 1,
4837 },
4838 };
4839 VkCopyImageToMemoryInfoEXT copy_info = {
4840 .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
4841 .regionCount = 1,
4842 .pRegions = &region_info,
4843 };
4844 for (int i = 0; i < planes; i++) {
4845 int img_idx = FFMIN(i, (nb_images - 1));
4846 uint32_t p_w, p_h;
4847 get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4848
4849 region_info.pHostPointer = swf->data[i];
4850 region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4851 region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4852 region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4853 copy_info.srcImage = hwf_vk->img[img_idx];
4854 copy_info.srcImageLayout = hwf_vk->layout[img_idx];
4855
4856 vk->CopyImageToMemoryEXT(hwctx->act_dev, &copy_info);
4857 }
4858 }
4859
4860 hwfc_vk->unlock_frame(hwfc, hwf_vk);
4861
4862 return 0;
4863}
4864
4866 AVFrame *swf, AVFrame *hwf,
4867 int upload)
4868{
4869 int err;
4870 VulkanFramesPriv *fp = hwfc->hwctx;
4871 AVVulkanFramesContext *hwctx = &fp->p;
4872 VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4873 FFVulkanFunctions *vk = &p->vkctx.vkfn;
4874
4875 int host_mapped = 0;
4876
4877 AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4878 VkBufferImageCopy region[AV_NUM_DATA_POINTERS]; // always one per plane
4879
4880 const int planes = av_pix_fmt_count_planes(swf->format);
4882 const int nb_images = ff_vk_count_images(hwf_vk);
4883
4884 VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
4885 int nb_img_bar = 0;
4886
4888 int nb_bufs = 0;
4889
4890 VkCommandBuffer cmd_buf;
4891 FFVkExecContext *exec;
4892
4893 /* Sanity checking */
4894 if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
4895 av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
4896 return AVERROR(EINVAL);
4897 }
4898
4899 if (swf->width > hwfc->width || swf->height > hwfc->height)
4900 return AVERROR(EINVAL);
4901
4902 int host_copy = hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
4903
4904 /* Host layout transitions may only originate from a host-copyable layout */
4905 if (!upload && host_copy) {
4906 for (int i = 0; i < nb_images; i++) {
4907 int compat = 0;
4908 for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount; j++) {
4909 if (hwf_vk->layout[i] == p->vkctx.host_image_props.pCopySrcLayouts[j]) {
4910 compat = 1;
4911 break;
4912 }
4913 }
4914 if (!compat) {
4915 host_copy = 0;
4916 break;
4917 }
4918 }
4919 }
4920
4921 if (host_copy)
4922 return vulkan_transfer_host(hwfc, hwf, swf, upload);
4923
4924 for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
4925 uint32_t p_w, p_h;
4926 get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4927
4928 /* Buffer region for this plane */
4929 region[i] = (VkBufferImageCopy) {
4930 .bufferOffset = 0,
4931 .bufferRowLength = swf->linesize[i],
4932 .bufferImageHeight = p_h,
4933 .imageSubresource.layerCount = 1,
4934 .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4935 /* Rest of the fields adjusted/filled in later */
4936 };
4937 }
4938
4939 /* Setup buffers first */
4940 if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY && !p->avoid_host_import) {
4941 err = host_map_frame(hwfc, bufs, &nb_bufs, swf, region, upload);
4942 if (err >= 0)
4943 host_mapped = 1;
4944 }
4945
4946 if (!host_mapped) {
4947 err = get_plane_buf(hwfc, &bufs[0], swf, region, upload);
4948 if (err < 0)
4949 goto end;
4950 nb_bufs = 1;
4951
4952 if (upload) {
4953 err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 1);
4954 if (err < 0)
4955 goto end;
4956 }
4957 }
4958
4959 exec = ff_vk_exec_get(&p->vkctx, &fp->upload_exec);
4960 cmd_buf = exec->buf;
4961
4962 err = ff_vk_exec_start(&p->vkctx, exec);
4963 if (err < 0)
4964 goto end;
4965
4966 /* Prep destination Vulkan frame */
4967 err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, hwf,
4968 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4969 VK_PIPELINE_STAGE_2_TRANSFER_BIT);
4970 if (err < 0) {
4971 ff_vk_exec_discard(&p->vkctx, exec);
4972 goto end;
4973 }
4974
4975 /* No need to declare buf deps for synchronous transfers (downloads) */
4976 if (upload) {
4977 /* Add the software frame backing the buffers if we're host mapping */
4978 if (host_mapped) {
4979 err = ff_vk_exec_add_dep_sw_frame(&p->vkctx, exec, swf);
4980 if (err < 0) {
4981 ff_vk_exec_discard(&p->vkctx, exec);
4982 goto end;
4983 }
4984 }
4985
4986 /* Add the buffers as a dependency */
4987 for (int i = 0; i < nb_bufs; i++)
4988 ff_vk_exec_add_dep_refstruct(&p->vkctx, exec, bufs[i]);
4989 }
4990
4991 ff_vk_frame_barrier(&p->vkctx, exec, hwf, img_bar, &nb_img_bar,
4992 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4993 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
4994 upload ? VK_ACCESS_TRANSFER_WRITE_BIT :
4995 VK_ACCESS_TRANSFER_READ_BIT,
4996 upload ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL :
4997 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4998 p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
4999
5000 vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
5001 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
5002 .pImageMemoryBarriers = img_bar,
5003 .imageMemoryBarrierCount = nb_img_bar,
5004 });
5005
5006 for (int i = 0; i < planes; i++) {
5007 int buf_idx = FFMIN(i, (nb_bufs - 1));
5008 int img_idx = FFMIN(i, (nb_images - 1));
5009 FFVkBuffer *vkbuf = bufs[buf_idx];
5010
5011 uint32_t orig_stride = region[i].bufferRowLength;
5012 region[i].bufferRowLength /= desc->comp[i].step;
5013 region[i].imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
5014
5015 if (upload)
5016 vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf,
5017 hwf_vk->img[img_idx],
5018 img_bar[img_idx].newLayout,
5019 1, &region[i]);
5020 else
5021 vk->CmdCopyImageToBuffer(cmd_buf, hwf_vk->img[img_idx],
5022 img_bar[img_idx].newLayout,
5023 vkbuf->buf,
5024 1, &region[i]);
5025
5026 region[i].bufferRowLength = orig_stride;
5027 }
5028
5029 err = ff_vk_exec_submit(&p->vkctx, exec);
5030 if (err >= 0 && !upload) {
5031 ff_vk_exec_wait(&p->vkctx, exec);
5032 if (!host_mapped)
5033 err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 0);
5034 }
5035
5036end:
5037 for (int i = 0; i < nb_bufs; i++)
5038 av_refstruct_unref(&bufs[i]);
5039
5040 return err;
5041}
5042
5044 const AVFrame *src)
5045{
5047
5048 switch (src->format) {
5049#if CONFIG_CUDA
5050 case AV_PIX_FMT_CUDA:
5051#ifdef _WIN32
5052 if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
5053 (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
5054#else
5055 if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
5056 (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
5057#endif
5058 return vulkan_transfer_data_from_cuda(hwfc, dst, src);
5060#endif
5061 default:
5062 if (src->hw_frames_ctx)
5063 return AVERROR(ENOSYS);
5064 else
5065 return vulkan_transfer_frame(hwfc, (AVFrame *)src, dst, 1);
5066 }
5067}
5068
5069#if CONFIG_CUDA
5070static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
5071 const AVFrame *src)
5072{
5073 int err;
5074 CUcontext dummy;
5075 AVVkFrame *dst_f;
5076 AVVkFrameInternal *dst_int;
5078 VulkanFramesPriv *fp = hwfc->hwctx;
5079 const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
5081 int nb_images;
5082
5083 AVHWFramesContext *cuda_fc = (AVHWFramesContext*)dst->hw_frames_ctx->data;
5084 AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
5085 AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
5086 AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
5087 CudaFunctions *cu = cu_internal->cuda_dl;
5088 CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
5089 CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
5090
5091 dst_f = (AVVkFrame *)src->data[0];
5092 nb_images = ff_vk_count_images(dst_f);
5093
5094 err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
5095 if (err < 0)
5096 return err;
5097
5098 err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
5099 if (err < 0)
5100 return err;
5101
5102 err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
5103 if (err < 0) {
5104 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
5105 return err;
5106 }
5107
5108 dst_int = dst_f->internal;
5109
5110 for (int i = 0; i < nb_images; i++) {
5111 s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
5112 s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
5113 }
5114
5115 err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
5116 nb_images, cuda_dev->stream));
5117 if (err < 0)
5118 goto fail;
5119
5120 for (int i = 0; i < planes; i++) {
5121 CUDA_MEMCPY2D cpy = {
5122 .dstMemoryType = CU_MEMORYTYPE_DEVICE,
5123 .dstDevice = (CUdeviceptr)dst->data[i],
5124 .dstPitch = dst->linesize[i],
5125 .dstY = 0,
5126
5127 .srcMemoryType = CU_MEMORYTYPE_ARRAY,
5128 .srcArray = dst_int->cu_array[i],
5129 };
5130
5131 int w, h;
5132 get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
5133
5134 cpy.WidthInBytes = w * desc->comp[i].step;
5135 cpy.Height = h;
5136
5137 err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
5138 if (err < 0)
5139 goto fail;
5140 }
5141
5142 err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
5143 nb_images, cuda_dev->stream));
5144 if (err < 0)
5145 goto fail;
5146
5147 for (int i = 0; i < nb_images; i++)
5148 dst_f->sem_value[i]++;
5149
5150 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
5151
5152 av_log(hwfc, AV_LOG_VERBOSE, "Transferred Vulkan image to CUDA!\n");
5153
5154 return prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
5155
5156fail:
5157 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
5158 vulkan_free_internal(p, dst_f);
5159 av_buffer_unref(&dst->buf[0]);
5160 return err;
5161}
5162#endif
5163
5165 const AVFrame *src)
5166{
5168
5169 switch (dst->format) {
5170#if CONFIG_CUDA
5171 case AV_PIX_FMT_CUDA:
5172#ifdef _WIN32
5173 if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
5174 (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
5175#else
5176 if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
5177 (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
5178#endif
5179 return vulkan_transfer_data_to_cuda(hwfc, dst, src);
5181#endif
5182 default:
5183 if (dst->hw_frames_ctx)
5184 return AVERROR(ENOSYS);
5185 else
5186 return vulkan_transfer_frame(hwfc, dst, (AVFrame *)src, 0);
5187 }
5188}
5189
5191 AVHWFramesContext *src_fc, int flags)
5192{
5193 return vulkan_frames_init(dst_fc);
5194}
5195
5197{
5198 int err;
5199 AVVkFrame *f = av_mallocz(sizeof(AVVkFrame));
5200 if (!f)
5201 return NULL;
5202
5203 f->internal = av_mallocz(sizeof(*f->internal));
5204 if (!f->internal) {
5205 av_free(f);
5206 return NULL;
5207 }
5208
5209 err = pthread_mutex_init(&f->internal->update_mutex, NULL);
5210 if (err != 0) {
5211 av_free(f->internal);
5212 av_free(f);
5213 return NULL;
5214 }
5215
5216 return f;
5217}
5218
5221 .name = "Vulkan",
5222
5223 .device_hwctx_size = sizeof(VulkanDevicePriv),
5224 .frames_hwctx_size = sizeof(VulkanFramesPriv),
5225
5226 .device_init = &vulkan_device_init,
5227 .device_uninit = &vulkan_device_uninit,
5228 .device_create = &vulkan_device_create,
5229 .device_derive = &vulkan_device_derive,
5230
5231 .frames_get_constraints = &vulkan_frames_get_constraints,
5232 .frames_init = vulkan_frames_init,
5233 .frames_get_buffer = vulkan_get_buffer,
5234 .frames_uninit = vulkan_frames_uninit,
5235
5236 .transfer_get_formats = vulkan_transfer_get_formats,
5237 .transfer_data_to = vulkan_transfer_data_to,
5238 .transfer_data_from = vulkan_transfer_data_from,
5239
5240 .map_to = vulkan_map_to,
5241 .map_from = vulkan_map_from,
5242 .frames_derive_to = &vulkan_frames_derive_to,
5243
5244 .pix_fmts = (const enum AVPixelFormat []) {
5247 },
5248};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static const char *const format[]
Definition af_aiir.c:444
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition avassert.h:68
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition avassert.h:58
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
#define av_popcount
Definition common.h:154
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
#define CHECK_CU(x)
Definition cuviddec.c:142
static const uint16_t fc[]
Definition dcaenc.h:43
static AVFrame * frame
int8_t exp
Definition eval.c:76
static int dummy
Definition ffplay.c:3754
const char * usage
#define AV_NUM_DATA_POINTERS
Definition frame.h:473
#define fail
Definition test.h:479
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition buffer.c:139
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition buffer.c:55
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition buffer.c:390
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition buffer.c:259
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition dict.c:60
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition imgutils.c:374
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition avstring.c:179
#define LIBAVUTIL_VERSION_MINOR
Definition version.h:82
#define LIBAVUTIL_VERSION_MAJOR
Definition version.h:81
#define LIBAVUTIL_VERSION_MICRO
Definition version.h:83
int index
Definition gxfenc.c:90
static const int offsets[]
Definition hevc_pel.c:34
static const int weights[]
Definition hevc_pel.c:32
int ff_hwframe_map_create(AVBufferRef *hwframe_ref, AVFrame *dst, const AVFrame *src, void(*unmap)(AVHWFramesContext *ctx, HWMapDescriptor *hwmap), void *priv)
Definition hwcontext.c:741
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition hwcontext.c:793
int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src)
Replace the current hwmap of dst with the one from src, used for indirect mappings like VAAPI->(DRM)-...
Definition hwcontext.c:948
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition hwcontext.h:515
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition hwcontext.h:519
AVHWFrameTransferDirection
Definition hwcontext.h:406
@ AV_HWDEVICE_TYPE_VULKAN
Definition hwcontext.h:39
@ AV_HWDEVICE_TYPE_CUDA
Definition hwcontext.h:30
@ AV_HWDEVICE_TYPE_DRM
Definition hwcontext.h:36
@ AV_HWDEVICE_TYPE_VAAPI
Definition hwcontext.h:31
FFmpeg internal API for CUDA.
API-specific header for AV_HWDEVICE_TYPE_DRM.
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
static FFHWFramesContext * ffhwframesctx(AVHWFramesContext *ctx)
const HWContextType ff_hwcontext_type_vulkan
cl_device_type type
const VkFormat * av_vkfmt_from_pixfmt(enum AVPixelFormat p)
Returns the optimal per-plane Vulkan format for a given sw_format, one for each plane.
enum VkFormat VkFormat
API-specific header for AV_HWDEVICE_TYPE_VAAPI.
static int pick_queue_family(VkQueueFamilyProperties2 *qf, uint32_t num_qf, VkQueueFlagBits flags)
AVVkFrame * av_vk_frame_alloc(void)
Allocates a single AVVkFrame and initializes everything as 0.
#define PICK_QF(type, vid_op)
static void unlock_frame(AVHWFramesContext *fc, AVVkFrame *vkf)
static void vulkan_free_internal(VulkanDevicePriv *p, AVVkFrame *f)
static int vulkan_frames_init(AVHWFramesContext *hwfc)
static VKAPI_ATTR VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *data, void *priv)
static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req, VkMemoryPropertyFlagBits req_flags, const void *alloc_extension, VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
#define RELEASE_PROPS(props, count)
static const struct FFVkFormatEntry vk_formats_list[]
static int vulkan_transfer_host(AVHWFramesContext *hwfc, AVFrame *hwf, AVFrame *swf, int upload)
static void device_features_init(AVHWDeviceContext *ctx, VulkanDeviceFeatures *feats)
static const int nb_vk_formats_list
static int pick_video_queue_family(VkQueueFamilyProperties2 *qf, VkQueueFamilyVideoPropertiesKHR *qf_vid, uint32_t num_qf, VkVideoCodecOperationFlagsKHR flags)
static const char * vk_dev_type(enum VkPhysicalDeviceType type)
static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, void *alloc_pnext, size_t alloc_pnext_stride)
static void device_features_copy_needed(VulkanDeviceFeatures *dst, VulkanDeviceFeatures *src)
const VkFormat * av_vkfmt_from_pixfmt(enum AVPixelFormat p)
Returns the optimal per-plane Vulkan format for a given sw_format, one for each plane.
static int switch_layout(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
static int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame, VkImageTiling tiling, VkImageUsageFlagBits usage, VkImageCreateFlags flags, int nb_layers, void *create_pnext)
static int vulkan_host_transfer_usable(AVHWFramesContext *hwfc)
static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
static int find_device(AVHWDeviceContext *ctx, VulkanDeviceSelection *select)
static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
#define ADD_VAL_TO_LIST(list, count, val)
#define COPY_VAL(VAL)
static int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
static int copy_buffer_data(AVHWFramesContext *hwfc, FFVkBuffer *vkbuf, AVFrame *swf, VkBufferImageCopy *region, int planes, int upload)
static int vulkan_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
static int vulkan_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, AVDictionary *opts, int flags)
static int vulkan_device_init(AVHWDeviceContext *ctx)
static int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags)
FFVulkanDebugMode
@ FF_VULKAN_DEBUG_PRINTF
@ FF_VULKAN_DEBUG_VALIDATE
@ FF_VULKAN_DEBUG_NB
@ FF_VULKAN_DEBUG_PRACTICES
@ FF_VULKAN_DEBUG_NONE
static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static void switch_new_props(enum PrepMode pmode, VkImageLayout *new_layout, VkAccessFlags2 *new_access)
static int vulkan_transfer_frame(AVHWFramesContext *hwfc, AVFrame *swf, AVFrame *hwf, int upload)
static int host_map_frame(AVHWFramesContext *hwfc, FFVkBuffer **dst, int *nb_bufs, AVFrame *swf, VkBufferImageCopy *region, int upload)
static void lock_frame(AVHWFramesContext *fc, AVVkFrame *vkf)
static AVBufferRef * vulkan_pool_alloc(void *opaque, size_t size)
static void vulkan_frame_free(AVHWFramesContext *hwfc, AVVkFrame *f)
static void vulkan_device_uninit(AVHWDeviceContext *ctx)
static void lock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VulkanDeviceSelection *dev_select, int disable_multiplane, AVDictionary *opts, int flags)
static const struct FFVkFormatEntry * vk_find_format_entry(enum AVPixelFormat p)
static void try_export_flags(AVHWFramesContext *hwfc, VkExternalMemoryHandleTypeFlags *comp_handle_types, VkExternalMemoryHandleTypeFlags *iexp, VkExternalMemoryHandleTypeFlagBits exp)
static void vulkan_device_free(AVHWDeviceContext *ctx)
static void get_plane_wh(uint32_t *w, uint32_t *h, enum AVPixelFormat format, int frame_w, int frame_h, int plane)
const char ** av_vk_get_optional_device_extensions(int *count)
Returns an array of optional Vulkan device extensions that FFmpeg may use if enabled.
static int load_libvulkan(AVHWDeviceContext *ctx)
static int get_plane_buf(AVHWFramesContext *hwfc, FFVkBuffer **dst, AVFrame *swf, VkBufferImageCopy *region, int upload)
static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
static int vulkan_device_has_rebar(AVHWDeviceContext *ctx)
static const VulkanOptExtension optional_instance_exts[]
static int check_layers(AVHWDeviceContext *ctx, AVDictionary *opts, const char *const **dst, uint32_t *num, enum FFVulkanDebugMode *debug_mode)
static int switch_layout_host(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, const char *const **dst, uint32_t *num, enum FFVulkanDebugMode debug_mode)
const char ** av_vk_get_optional_instance_extensions(int *count)
Returns an array of optional Vulkan instance extensions that FFmpeg may use if enabled.
static int vkfmt_from_pixfmt2(AVHWDeviceContext *dev_ctx, enum AVPixelFormat p, VkImageTiling tiling, VkFormat fmts[AV_NUM_DATA_POINTERS], int *nb_images, VkImageAspectFlags *aspect, VkImageUsageFlags *supported_usage, int disable_multiplane, int need_storage)
static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts, enum FFVulkanDebugMode *debug_mode)
static const VulkanOptExtension optional_device_exts[]
@ PREP_MODE_GENERAL
@ PREP_MODE_DECODING_DPB
@ PREP_MODE_WRITE
@ PREP_MODE_ENCODING_DPB
@ PREP_MODE_EXTERNAL_EXPORT
@ PREP_MODE_DECODING_DST
@ PREP_MODE_EXTERNAL_IMPORT
static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
API-specific header for AV_HWDEVICE_TYPE_VULKAN.
@ AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE
misc image utilities
enum AVPixelFormat pixfmt
Definition kmsgrab.c:367
#define av_fallthrough
Definition attributes.h:67
#define av_unused
Definition attributes.h:164
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition internal.h:66
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition internal.h:67
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition vulkan.c:331
VkImageAspectFlags ff_vk_aspect_flag(AVFrame *f, int p)
Get the aspect flag for a plane from an image.
Definition vulkan.c:1656
int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext)
Allocates/frees an execution pool.
Definition vulkan.c:395
void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e)
Definition vulkan.c:645
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition vulkan.c:2808
int ff_vk_load_props(FFVulkanContext *s)
Loads props/mprops/driver_props.
Definition vulkan.c:151
const char * ff_vk_ret2str(VkResult res)
Converts Vulkan return values to strings.
Definition vulkan.c:42
int ff_vk_exec_add_dep_sw_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f)
Definition vulkan.c:811
void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e, AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar, VkPipelineStageFlags2 src_stage, VkPipelineStageFlags2 dst_stage, VkAccessFlagBits2 new_access, VkImageLayout new_layout, uint32_t new_qf)
Definition vulkan.c:2197
int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e)
Start/submit/wait an execution.
Definition vulkan.c:660
FFVkExecContext * ff_vk_exec_get(FFVulkanContext *s, FFVkExecPool *pool)
Retrieve an execution pool.
Definition vulkan.c:622
int ff_vk_exec_submit(FFVulkanContext *s, FFVkExecContext *e)
Definition vulkan.c:969
AVVulkanDeviceQueueFamily * ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops)
Chooses an appropriate QF.
Definition vulkan.c:316
int ff_vk_host_map_buffer(FFVulkanContext *s, FFVkBuffer **dst, uint8_t *src_data, VkDeviceSize size, const AVBufferRef *src_buf, VkBufferUsageFlags usage)
Maps a system RAM buffer into a Vulkan buffer.
Definition vulkan.c:1522
void ff_vk_exec_add_dep_refstruct(FFVulkanContext *s, FFVkExecContext *e, void *obj)
Execution dependency management.
Definition vulkan.c:779
int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVRefStructPool **buf_pool, FFVkBuffer **buf, VkBufferUsageFlags usage, void *create_pNext, size_t size, VkMemoryPropertyFlagBits mem_props)
Initialize a pool and create AVBufferRefs containing FFVkBuffer.
Definition vulkan.c:1426
int ff_vk_flush_buffer(FFVulkanContext *s, FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize mem_size, int flush)
Flush or invalidate a single buffer, with a given size and offset.
Definition vulkan.c:1327
void ff_vk_exec_discard(FFVulkanContext *s, FFVkExecContext *e)
Definition vulkan.c:763
void ff_vk_exec_add_dep_bool_sem(FFVulkanContext *s, FFVkExecContext *e, VkSemaphore *sem, int nb, VkPipelineStageFlagBits2 stage, int wait)
Definition vulkan.c:839
int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, VkPipelineStageFlagBits2 wait_stage, VkPipelineStageFlagBits2 signal_stage)
Definition vulkan.c:867
void ff_vk_exec_add_dep_wait_sem(FFVulkanContext *s, FFVkExecContext *e, VkSemaphore sem, uint64_t val, VkPipelineStageFlagBits2 stage)
Definition vulkan.c:825
const char * desc
Definition libsvtav1.c:83
static const struct @257111027162314367033347246032313251342043035002 planes[]
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define FFALIGN(x, a)
Definition macros.h:78
uint64_t layout
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
const char data[16]
Definition mxf.c:149
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
#define av_strdup(s)
Definition ops_static.c:55
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
Definition os2threads.h:119
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition os2threads.h:104
_fmutex pthread_mutex_t
Definition os2threads.h:53
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
Definition os2threads.h:126
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition os2threads.h:112
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition pixdesc.h:136
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition pixdesc.h:132
#define AV_PIX_FMT_GBRAP12
Definition pixfmt.h:569
#define AV_PIX_FMT_YUV420P16
Definition pixfmt.h:556
#define AV_PIX_FMT_GBRPF32
Definition pixfmt.h:584
#define AV_PIX_FMT_P212
Definition pixfmt.h:624
#define AV_PIX_FMT_YUV444P12
Definition pixfmt.h:552
#define AV_PIX_FMT_RGBF32
Definition pixfmt.h:632
#define AV_PIX_FMT_YUV420P10
Definition pixfmt.h:545
#define AV_PIX_FMT_RGBAF32
Definition pixfmt.h:633
#define AV_PIX_FMT_RGBAF16
Definition pixfmt.h:630
#define AV_PIX_FMT_GBRAP16
Definition pixfmt.h:571
#define AV_PIX_FMT_P412
Definition pixfmt.h:625
#define AV_PIX_FMT_P210
Definition pixfmt.h:622
#define AV_PIX_FMT_YUVA444P10
Definition pixfmt.h:598
#define AV_PIX_FMT_P012
Definition pixfmt.h:609
#define AV_PIX_FMT_YUVA420P16
Definition pixfmt.h:601
#define AV_PIX_FMT_P216
Definition pixfmt.h:626
#define AV_PIX_FMT_GBRAP32
Definition pixfmt.h:572
#define AV_PIX_FMT_YUV420P12
Definition pixfmt.h:549
#define AV_PIX_FMT_YUVA420P10
Definition pixfmt.h:596
#define AV_PIX_FMT_YUV422P12
Definition pixfmt.h:550
#define AV_PIX_FMT_Y210
Definition pixfmt.h:612
#define AV_PIX_FMT_GBRAP14
Definition pixfmt.h:570
#define AV_PIX_FMT_P010
Definition pixfmt.h:608
#define AV_PIX_FMT_P016
Definition pixfmt.h:610
#define AV_PIX_FMT_GBRP10
Definition pixfmt.h:564
#define AV_PIX_FMT_GRAY32
Definition pixfmt.h:529
#define AV_PIX_FMT_RGBA128
Definition pixfmt.h:636
#define AV_PIX_FMT_YUV422P10
Definition pixfmt.h:546
#define AV_PIX_FMT_GRAY12
Definition pixfmt.h:526
#define AV_PIX_FMT_GBRAPF16
Definition pixfmt.h:583
#define AV_PIX_FMT_RGBA64
Definition pixfmt.h:535
#define AV_PIX_FMT_XV30
Definition pixfmt.h:615
#define AV_PIX_FMT_GBRP12
Definition pixfmt.h:565
#define AV_PIX_FMT_RGB48
Definition pixfmt.h:531
#define AV_PIX_FMT_BAYER_RGGB16
Definition pixfmt.h:578
#define AV_PIX_FMT_YUVA422P10
Definition pixfmt.h:597
#define AV_PIX_FMT_X2RGB10
Definition pixfmt.h:619
#define AV_PIX_FMT_GRAYF32
Definition pixfmt.h:588
#define AV_PIX_FMT_XV48
Definition pixfmt.h:617
#define AV_PIX_FMT_P410
Definition pixfmt.h:623
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition pixfmt.h:379
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition pixfmt.h:75
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition pixfmt.h:265
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition pixfmt.h:102
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition pixfmt.h:88
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition pixfmt.h:108
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition pixfmt.h:260
@ AV_PIX_FMT_NV24
planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:371
@ AV_PIX_FMT_DRM_PRIME
DRM-managed buffers exposed through PRIME buffer sharing.
Definition pixfmt.h:351
@ AV_PIX_FMT_NV16
interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:198
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition pixfmt.h:100
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition pixfmt.h:174
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition pixfmt.h:212
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition pixfmt.h:263
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition pixfmt.h:173
@ AV_PIX_FMT_VAAPI
Hardware acceleration through VA-API, data[3] contains a VASurfaceID.
Definition pixfmt.h:126
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition pixfmt.h:74
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition pixfmt.h:76
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition pixfmt.h:165
#define AV_PIX_FMT_YUVA422P12
Definition pixfmt.h:599
#define AV_PIX_FMT_RGB96
Definition pixfmt.h:635
#define AV_PIX_FMT_P416
Definition pixfmt.h:627
#define AV_PIX_FMT_X2BGR10
Definition pixfmt.h:620
#define AV_PIX_FMT_Y216
Definition pixfmt.h:614
#define AV_PIX_FMT_GRAY10
Definition pixfmt.h:525
#define AV_PIX_FMT_GRAY14
Definition pixfmt.h:527
#define AV_PIX_FMT_GBRPF16
Definition pixfmt.h:582
#define AV_PIX_FMT_YUV422P16
Definition pixfmt.h:557
#define AV_PIX_FMT_GRAY16
Definition pixfmt.h:528
#define AV_PIX_FMT_GBRAP10
Definition pixfmt.h:568
#define AV_PIX_FMT_Y212
Definition pixfmt.h:613
#define AV_PIX_FMT_YUVA444P16
Definition pixfmt.h:603
#define AV_PIX_FMT_YUVA422P16
Definition pixfmt.h:602
#define AV_PIX_FMT_GBRP16
Definition pixfmt.h:567
#define AV_PIX_FMT_XV36
Definition pixfmt.h:616
#define AV_PIX_FMT_GBRP14
Definition pixfmt.h:566
#define AV_PIX_FMT_YUVA444P12
Definition pixfmt.h:600
#define AV_PIX_FMT_GBRAPF32
Definition pixfmt.h:585
#define AV_PIX_FMT_YUV444P16
Definition pixfmt.h:558
#define AV_PIX_FMT_YUV444P10
Definition pixfmt.h:548
const char * name
Definition qsvenc.c:142
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition refstruct.c:120
static void av_refstruct_pool_uninit(AVRefStructPool **poolp)
Mark the pool as being available for freeing.
Definition refstruct.h:292
#define sem_wait(psem)
Definition semaphore.h:27
formats
Definition signature.h:47
#define FF_ARRAY_ELEMS(a)
A reference to a data buffer.
Definition buffer.h:82
uint8_t * data
The data buffer.
Definition buffer.h:90
This struct is allocated as AVHWDeviceContext.hwctx.
AVCUDADeviceContextInternal * internal
int fd
File descriptor of DRM device.
DRM frame descriptor.
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
int nb_layers
Number of layers in the frame.
int nb_objects
Number of DRM objects making up this frame.
AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]
Array of layers in the frame.
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
int nb_planes
Number of planes in the layer.
uint32_t format
Format of the layer (DRM_FORMAT_*).
int fd
DRM PRIME fd for the object.
size_t size
Total size of the object.
uint64_t format_modifier
Format modifier applied to the object (DRM_FORMAT_MOD_*).
ptrdiff_t pitch
Pitch (linesize) of this plane.
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor.
ptrdiff_t offset
Offset within that object of this plane.
char * value
Definition dict.h:92
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int width
Definition frame.h:544
int height
Definition frame.h:544
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition frame.h:649
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition hwcontext.h:63
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition hwcontext.h:88
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition hwcontext.h:75
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition hwcontext.h:444
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition hwcontext.h:469
enum AVPixelFormat * valid_hw_formats
A list of possible values for format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition hwcontext.h:449
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition hwcontext.h:456
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition hwcontext.h:462
This struct describes a set or pool of "hardware" frames (i.e.
Definition hwcontext.h:118
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition hwcontext.h:153
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition hwcontext.h:213
int width
The allocated dimensions of the frames in this pool.
Definition hwcontext.h:220
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition hwcontext.h:137
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition hwcontext.h:181
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
AVRefStructPool is an API for a thread-safe pool of objects managed via the RefStruct API.
Definition refstruct.c:183
VAAPI connection details.
VADisplay display
The VADisplay handle, to be filled by the user.
pthread_mutex_t update_mutex
VkImageLayout layout[AV_NUM_DATA_POINTERS]
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization timeline semaphores, one for each VkImage.
uint64_t sem_value[AV_NUM_DATA_POINTERS]
Up to date semaphore value at which each image becomes accessible.
struct AVVkFrameInternal * internal
Internal data.
VkImage img[AV_NUM_DATA_POINTERS]
Vulkan images to which the memory is bound to.
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
VkPhysicalDevice phys_dev
Physical device.
AVVulkanDeviceQueueFamily qf[64]
Queue families used.
const char *const * enabled_dev_extensions
Enabled device extensions.
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
VkDevice act_dev
Active device.
const char *const * enabled_inst_extensions
Enabled instance extensions.
VkInstance inst
Vulkan instance.
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation.
VkDeviceQueueCreateFlags queue_flags
PFN_vkGetInstanceProcAddr get_proc_addr
Pointer to a vkGetInstanceProcAddr loading function.
VkVideoCodecOperationFlagBitsKHR video_caps
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
void * create_pnext
Extension data for image creation.
VkImageTiling tiling
Controls the tiling of allocated frames.
VkImageCreateFlags img_flags
Flags to set during image creation.
void * alloc_pnext[AV_NUM_DATA_POINTERS]
Extension data for memory allocation.
VkImageUsageFlagBits usage
Defines extra usage of output frames.
AVVkFrameFlags flags
A combination of AVVkFrameFlags.
void(* lock_frame)(struct AVHWFramesContext *fc, AVVkFrame *vkf)
Locks a frame, preventing other threads from changing frame properties.
int nb_layers
Number of layers each image will have.
void(* unlock_frame)(struct AVHWFramesContext *fc, AVVkFrame *vkf)
Similar to lock_frame(), unlocks a frame.
VkFormat format[AV_NUM_DATA_POINTERS]
Vulkan format for each image.
AVBufferPool * pool_internal
VkBuffer buf
Definition vulkan.h:95
uint8_t * mapped_mem
Definition vulkan.h:103
VkCommandBuffer buf
Definition vulkan.h:142
VkImageAspectFlags aspect
enum AVPixelFormat pixfmt
const VkFormat fallback[5]
FFVulkanFunctions vkfn
Definition vulkan.h:298
void * priv
Hardware-specific private data associated with the mapping.
AVFrame * source
A reference to the original source of the mapping.
VkPhysicalDeviceVulkan11Features vulkan_1_1
VkPhysicalDeviceVideoMaintenance1FeaturesKHR video_maintenance_1
VkPhysicalDeviceVulkan12Features vulkan_1_2
VkPhysicalDeviceCooperativeMatrixFeaturesKHR cooperative_matrix
VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR explicit_mem_layout
VkPhysicalDeviceVulkan13Features vulkan_1_3
VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore
VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR subgroup_rotate
VkPhysicalDeviceShaderObjectFeaturesEXT shader_object
VkPhysicalDeviceFeatures2 device
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float
VkPhysicalDeviceHostImageCopyFeaturesEXT host_image_copy
AVVulkanDeviceQueueFamily * compute_qf
pthread_mutex_t ** qf_mutex
VkPhysicalDeviceMemoryProperties mprops
VulkanDeviceFeatures feats
AVVulkanDeviceContext p
The public AVVulkanDeviceContext.
VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
VkPhysicalDeviceDriverProperties dprops
VkPhysicalDeviceProperties2 props
VkDebugUtilsMessengerEXT debug_ctx
VkExternalSemaphoreProperties ext_sem_props_opaque
AVVulkanDeviceQueueFamily * transfer_qf
FFVulkanContext vkctx
uint8_t uuid[VK_UUID_SIZE]
VkImageDrmFormatModifierListCreateInfoEXT * modifier_info
FFVkExecPool upload_exec
VkDrmFormatModifierPropertiesEXT drm_format_modifier_properties[5]
FFVkExecPool compute_exec
FFVkExecPool download_exec
AVVulkanFramesContext p
The public AVVulkanFramesContext.
AVRefStructPool * tmp
FFVulkanExtensions flag
Definition swscale.c:71
#define av_free(p)
#define av_malloc_array(a, b)
#define av_mallocz(s)
#define av_freep(p)
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
#define src
Definition vp8dsp.c:248
static AVFormatContext * ctx
Definition movenc.c:49
static AVDictionary * opts
Definition movenc.c:51
int size
static void lock_queue(void *priv, uint32_t qf, uint32_t qidx)
static void unlock_queue(void *priv, uint32_t qf, uint32_t qidx)
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition vf_v360.c:755
#define FF_VK_DEFAULT_EXEC_CONTEXTS
Definition vulkan.h:121
#define FF_VK_STRUCT_EXT(CTX, BASE, STRUCT_P, EXT_FLAG, TYPE)
Definition vulkan.h:387
static const void * ff_vk_find_struct(const void *chain, VkStructureType stype)
Definition vulkan.h:365
static int ff_vk_count_images(AVVkFrame *f)
Definition vulkan.h:356
VkImageUsageFlags ff_vk_map_feats_to_usage(VkFormatFeatureFlagBits2 feats)
Map between usage and features.
static void ff_vk_link_struct(void *chain, const void *in)
Definition vulkan.h:378
#define FF_VK_EXT_VIDEO_ENCODE_AV1
#define FF_VK_EXT_EXPLICIT_MEM_LAYOUT
#define FF_VK_EXT_VIDEO_DECODE_H265
#define FF_VK_EXT_RELAXED_EXTENDED_INSTR
#define FF_VK_EXT_EXTERNAL_FD_SEM
#define FF_VK_EXT_PORTABILITY_SUBSET
#define FF_VK_EXT_VIDEO_MAINTENANCE_1
#define FF_VK_EXT_DRM_MODIFIER_FLAGS
#define FF_VK_EXT_SHADER_OBJECT
#define FF_VK_EXT_VIDEO_QUEUE
#define FF_VK_EXT_UNIFIED_IMAGE_LAYOUTS
uint64_t FFVulkanExtensions
#define FF_VK_EXT_COOP_MATRIX
#define FF_VK_EXT_INTERNAL_QUEUE_SYNC
#define FF_VK_EXT_VIDEO_ENCODE_QUEUE
#define FF_VK_EXT_NO_FLAG
#define FF_VK_EXT_VIDEO_DECODE_AV1
#define FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
#define FF_VK_EXT_SUBGROUP_ROTATE
#define FF_VK_EXT_PUSH_DESCRIPTOR
#define FF_VK_EXT_MAXIMAL_RECONVERGENCE
#define FF_VK_EXT_DEVICE_DRM
#define FF_VK_EXT_VIDEO_DECODE_H264
#define FF_VK_EXT_VIDEO_ENCODE_H264
#define FF_VK_EXT_VIDEO_DECODE_QUEUE
#define FF_VK_EXT_LONG_VECTOR
#define FF_VK_EXT_VIDEO_DECODE_VP9
#define FF_VK_EXT_EXTERNAL_WIN32_SEM
#define FF_VK_EXT_MAINTENANCE_9
#define FF_VK_EXT_EXPECT_ASSUME
#define FF_VK_EXT_HOST_IMAGE_COPY
#define FF_VK_EXT_EXTERNAL_FD_MEMORY
#define FF_VK_EXT_ZERO_INITIALIZE
#define FF_VK_EXT_REPLICATED_COMPOSITES
#define FF_VK_EXT_VIDEO_ENCODE_H265
#define FF_VK_EXT_ATOMIC_FLOAT
#define FF_VK_EXT_EXTERNAL_HOST_MEMORY
#define FF_VK_EXT_EXTERNAL_WIN32_MEMORY
#define FF_VK_EXT_VIDEO_MAINTENANCE_2
static int ff_vk_load_functions(AVHWDeviceContext *ctx, FFVulkanFunctions *vk, uint64_t extensions_mask, int has_inst, int has_dev)
Function loader.
#define ASPECT_2PLANE
#define ASPECT_3PLANE