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