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 #if FF_API_VULKAN_FIXED_QUEUES
1746  /* Setup deprecated fields */
1747  hwctx->queue_family_index = -1;
1748  hwctx->queue_family_comp_index = -1;
1749  hwctx->queue_family_tx_index = -1;
1750  hwctx->queue_family_encode_index = -1;
1751  hwctx->queue_family_decode_index = -1;
1752 
1753 #define SET_OLD_QF(field, nb_field, type) \
1754  do { \
1755  if (field < 0 && hwctx->qf[i].flags & type) { \
1756  field = hwctx->qf[i].idx; \
1757  nb_field = hwctx->qf[i].num; \
1758  } \
1759  } while (0)
1760 
1761  for (uint32_t i = 0; i < hwctx->nb_qf; i++) {
1762  SET_OLD_QF(hwctx->queue_family_index, hwctx->nb_graphics_queues, VK_QUEUE_GRAPHICS_BIT);
1763  SET_OLD_QF(hwctx->queue_family_comp_index, hwctx->nb_comp_queues, VK_QUEUE_COMPUTE_BIT);
1764  SET_OLD_QF(hwctx->queue_family_tx_index, hwctx->nb_tx_queues, VK_QUEUE_TRANSFER_BIT);
1765  SET_OLD_QF(hwctx->queue_family_encode_index, hwctx->nb_encode_queues, VK_QUEUE_VIDEO_ENCODE_BIT_KHR);
1766  SET_OLD_QF(hwctx->queue_family_decode_index, hwctx->nb_decode_queues, VK_QUEUE_VIDEO_DECODE_BIT_KHR);
1767  }
1768 
1769 #undef SET_OLD_QF
1771 #endif
1772 
1773  return 0;
1774 }
1775 
1776 /* Only resources created by vulkan_device_create should be released here,
1777  * resources created by vulkan_device_init should be released by
1778  * vulkan_device_uninit, to make sure we don't free user provided resources,
1779  * and there is no leak.
1780  */
1782 {
1783  VulkanDevicePriv *p = ctx->hwctx;
1784  AVVulkanDeviceContext *hwctx = &p->p;
1785  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1786 
1787  if (hwctx->act_dev)
1788  vk->DestroyDevice(hwctx->act_dev, hwctx->alloc);
1789 
1790  if (p->debug_ctx)
1791  vk->DestroyDebugUtilsMessengerEXT(hwctx->inst, p->debug_ctx,
1792  hwctx->alloc);
1793 
1794  if (hwctx->inst)
1795  vk->DestroyInstance(hwctx->inst, hwctx->alloc);
1796 
1797  if (p->libvulkan)
1798  dlclose(p->libvulkan);
1799 
1802 }
1803 
1805 {
1806  VulkanDevicePriv *p = ctx->hwctx;
1807 
1808  if (p->qf_mutex) {
1809  for (uint32_t i = 0; i < p->nb_tot_qfs; i++) {
1810  pthread_mutex_destroy(p->qf_mutex[i]);
1811  av_freep(&p->qf_mutex[i]);
1812  }
1813  av_freep(&p->qf_mutex);
1814  }
1815 
1816  ff_vk_uninit(&p->vkctx);
1817 }
1818 
1820  VulkanDeviceSelection *dev_select,
1821  int disable_multiplane,
1822  AVDictionary *opts, int flags)
1823 {
1824  int err = 0;
1825  VkResult ret;
1826  AVDictionaryEntry *opt_d;
1827  VulkanDevicePriv *p = ctx->hwctx;
1828  AVVulkanDeviceContext *hwctx = &p->p;
1829  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1830  enum FFVulkanDebugMode debug_mode = FF_VULKAN_DEBUG_NONE;
1831  VulkanDeviceFeatures supported_feats = { 0 };
1832  VkDeviceCreateInfo dev_info = {
1833  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1834  };
1835 
1836  /* Create an instance if not given one */
1837  if ((err = create_instance(ctx, opts, &debug_mode)))
1838  goto end;
1839 
1840  /* Find a physical device (if not given one) */
1841  if ((err = find_device(ctx, dev_select)))
1842  goto end;
1843 
1844  /* Get supported memory types */
1845  vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
1846 
1847  /* Find and enable extensions for the physical device */
1848  if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
1849  &dev_info.enabledExtensionCount, debug_mode))) {
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  goto end;
1854  }
1855 
1856  /* Get all supported features for the physical device */
1857  device_features_init(ctx, &supported_feats);
1858  vk->GetPhysicalDeviceFeatures2(hwctx->phys_dev, &supported_feats.device);
1859 
1860  /* Copy all needed features from those supported and activate them */
1861  device_features_init(ctx, &p->feats);
1862  device_features_copy_needed(&p->feats, &supported_feats);
1863  dev_info.pNext = p->feats.device.pNext;
1864  dev_info.pEnabledFeatures = &p->feats.device.features;
1865 
1866  /* Limit queues to a given number if needed */
1867  opt_d = av_dict_get(opts, "limit_queues", NULL, 0);
1868  if (opt_d)
1869  p->limit_queues = strtol(opt_d->value, NULL, 10);
1870 
1871  /* Setup enabled queue families */
1872  if ((err = setup_queue_families(ctx, &dev_info)))
1873  goto end;
1874 
1875  /* Finally create the device */
1876  ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
1877  &hwctx->act_dev);
1878 
1879  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1880  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1881  av_free((void *)dev_info.pQueueCreateInfos);
1882 
1883  if (ret != VK_SUCCESS) {
1884  av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n",
1885  ff_vk_ret2str(ret));
1886  for (int i = 0; i < dev_info.enabledExtensionCount; i++)
1887  av_free((void *)dev_info.ppEnabledExtensionNames[i]);
1888  av_free((void *)dev_info.ppEnabledExtensionNames);
1889  err = AVERROR_EXTERNAL;
1890  goto end;
1891  }
1892 
1893  /* Tiled images setting, use them by default */
1894  opt_d = av_dict_get(opts, "linear_images", NULL, 0);
1895  if (opt_d)
1896  p->use_linear_images = strtol(opt_d->value, NULL, 10);
1897 
1898  /* The disable_multiplane argument takes precedent over the option */
1899  p->disable_multiplane = disable_multiplane;
1900  if (!p->disable_multiplane) {
1901  opt_d = av_dict_get(opts, "disable_multiplane", NULL, 0);
1902  if (opt_d)
1903  p->disable_multiplane = strtol(opt_d->value, NULL, 10);
1904  }
1905 
1906  /* Disable host pointer imports (by default on nvidia) */
1907  p->avoid_host_import = p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
1908  opt_d = av_dict_get(opts, "avoid_host_import", NULL, 0);
1909  if (opt_d)
1910  p->avoid_host_import = strtol(opt_d->value, NULL, 10);
1911 
1912  /* Set the public device feature struct and its pNext chain */
1913  hwctx->device_features = p->feats.device;
1914 
1915  /* Set the list of all active extensions */
1916  hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames;
1917  hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount;
1918 
1919  /* The extension lists need to be freed */
1920  ctx->free = vulkan_device_free;
1921 
1922 end:
1923  return err;
1924 }
1925 
1926 static void lock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
1927 {
1928  VulkanDevicePriv *p = ctx->hwctx;
1929  if (p->qf_mutex)
1930  pthread_mutex_lock(&p->qf_mutex[queue_family][index]);
1931 }
1932 
1933 static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
1934 {
1935  VulkanDevicePriv *p = ctx->hwctx;
1936  if (p->qf_mutex)
1937  pthread_mutex_unlock(&p->qf_mutex[queue_family][index]);
1938 }
1939 
1941 {
1942  int err = 0;
1943  uint32_t qf_num;
1944  VulkanDevicePriv *p = ctx->hwctx;
1945  AVVulkanDeviceContext *hwctx = &p->p;
1946  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1947  VkQueueFamilyProperties2 *qf;
1948  VkQueueFamilyVideoPropertiesKHR *qf_vid;
1949  VkPhysicalDeviceExternalSemaphoreInfo ext_sem_props_info;
1950  int graph_index, comp_index, tx_index, enc_index, dec_index;
1951 
1952  /* Set device extension flags */
1953  for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) {
1954  for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) {
1955  if (!strcmp(hwctx->enabled_dev_extensions[i],
1956  optional_device_exts[j].name)) {
1957  p->vkctx.extensions |= optional_device_exts[j].flag;
1958  break;
1959  }
1960  }
1961  }
1962 
1963  err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 1, 1);
1964  if (err < 0) {
1965  av_log(ctx, AV_LOG_ERROR, "Unable to load functions!\n");
1966  return err;
1967  }
1968 
1969  p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1970  p->props.pNext = &p->hprops;
1971  p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
1972  p->hprops.pNext = &p->dprops;
1973  p->dprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
1974 
1975  vk->GetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props);
1976  av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n",
1977  p->props.properties.deviceName);
1978  av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n");
1979  av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %"PRIu64"\n",
1980  p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
1981  av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %zu\n",
1982  p->props.properties.limits.minMemoryMapAlignment);
1983  av_log(ctx, AV_LOG_VERBOSE, " nonCoherentAtomSize: %"PRIu64"\n",
1984  p->props.properties.limits.nonCoherentAtomSize);
1985  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY)
1986  av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %"PRIu64"\n",
1987  p->hprops.minImportedHostPointerAlignment);
1988 
1989  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &qf_num, NULL);
1990  if (!qf_num) {
1991  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1992  return AVERROR_EXTERNAL;
1993  }
1994 
1995  ext_sem_props_info = (VkPhysicalDeviceExternalSemaphoreInfo) {
1996  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
1997  };
1998 
1999  /* Opaque FD semaphore properties */
2000  ext_sem_props_info.handleType =
2001 #ifdef _WIN32
2002  IsWindows8OrGreater()
2003  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2004  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
2005 #else
2006  VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2007 #endif
2008  p->ext_sem_props_opaque.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES;
2009  vk->GetPhysicalDeviceExternalSemaphoreProperties(hwctx->phys_dev,
2010  &ext_sem_props_info,
2011  &p->ext_sem_props_opaque);
2012 
2013  qf = av_malloc_array(qf_num, sizeof(VkQueueFamilyProperties2));
2014  if (!qf)
2015  return AVERROR(ENOMEM);
2016 
2017  qf_vid = av_malloc_array(qf_num, sizeof(VkQueueFamilyVideoPropertiesKHR));
2018  if (!qf_vid) {
2019  av_free(qf);
2020  return AVERROR(ENOMEM);
2021  }
2022 
2023  for (uint32_t i = 0; i < qf_num; i++) {
2024  qf_vid[i] = (VkQueueFamilyVideoPropertiesKHR) {
2025  .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR,
2026  };
2027  qf[i] = (VkQueueFamilyProperties2) {
2028  .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2,
2029  .pNext = p->vkctx.extensions & FF_VK_EXT_VIDEO_QUEUE ? &qf_vid[i] : NULL,
2030  };
2031  }
2032 
2033  vk->GetPhysicalDeviceQueueFamilyProperties2(hwctx->phys_dev, &qf_num, qf);
2034 
2035  p->nb_tot_qfs = qf_num;
2036 
2037  if (!(p->vkctx.extensions & FF_VK_EXT_INTERNAL_QUEUE_SYNC)) {
2038  p->qf_mutex = av_calloc(qf_num, sizeof(*p->qf_mutex));
2039  if (!p->qf_mutex) {
2040  err = AVERROR(ENOMEM);
2041  goto end;
2042  }
2043 
2044  for (uint32_t i = 0; i < qf_num; i++) {
2045  p->qf_mutex[i] = av_calloc(qf[i].queueFamilyProperties.queueCount,
2046  sizeof(**p->qf_mutex));
2047  if (!p->qf_mutex[i]) {
2048  err = AVERROR(ENOMEM);
2049  goto end;
2050  }
2051  for (uint32_t j = 0; j < qf[i].queueFamilyProperties.queueCount; j++) {
2052  err = pthread_mutex_init(&p->qf_mutex[i][j], NULL);
2053  if (err != 0) {
2054  av_log(ctx, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n",
2055  av_err2str(err));
2056  err = AVERROR(err);
2057  goto end;
2058  }
2059  }
2060  }
2061  }
2062 
2063 #if FF_API_VULKAN_FIXED_QUEUES
2065  graph_index = hwctx->nb_graphics_queues ? hwctx->queue_family_index : -1;
2066  comp_index = hwctx->nb_comp_queues ? hwctx->queue_family_comp_index : -1;
2067  tx_index = hwctx->nb_tx_queues ? hwctx->queue_family_tx_index : -1;
2068  dec_index = hwctx->nb_decode_queues ? hwctx->queue_family_decode_index : -1;
2069  enc_index = hwctx->nb_encode_queues ? hwctx->queue_family_encode_index : -1;
2070 
2071 #define CHECK_QUEUE(type, required, fidx, ctx_qf, qc) \
2072  do { \
2073  if (ctx_qf < 0 && required) { \
2074  av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \
2075  " in the context!\n", type); \
2076  err = AVERROR(EINVAL); \
2077  goto end; \
2078  } else if (fidx < 0 || ctx_qf < 0) { \
2079  break; \
2080  } else if (ctx_qf >= qf_num) { \
2081  av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \
2082  type, ctx_qf, qf_num); \
2083  err = AVERROR(EINVAL); \
2084  goto end; \
2085  } \
2086  \
2087  av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \
2088  " for%s%s%s%s%s\n", \
2089  ctx_qf, qc, \
2090  ctx_qf == graph_index ? " graphics" : "", \
2091  ctx_qf == comp_index ? " compute" : "", \
2092  ctx_qf == tx_index ? " transfers" : "", \
2093  ctx_qf == enc_index ? " encode" : "", \
2094  ctx_qf == dec_index ? " decode" : ""); \
2095  graph_index = (ctx_qf == graph_index) ? -1 : graph_index; \
2096  comp_index = (ctx_qf == comp_index) ? -1 : comp_index; \
2097  tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \
2098  enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \
2099  dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \
2100  } while (0)
2101 
2102  CHECK_QUEUE("graphics", 0, graph_index, hwctx->queue_family_index, hwctx->nb_graphics_queues);
2103  CHECK_QUEUE("compute", 1, comp_index, hwctx->queue_family_comp_index, hwctx->nb_comp_queues);
2104  CHECK_QUEUE("upload", 1, tx_index, hwctx->queue_family_tx_index, hwctx->nb_tx_queues);
2105  CHECK_QUEUE("decode", 0, dec_index, hwctx->queue_family_decode_index, hwctx->nb_decode_queues);
2106  CHECK_QUEUE("encode", 0, enc_index, hwctx->queue_family_encode_index, hwctx->nb_encode_queues);
2107 
2108 #undef CHECK_QUEUE
2109 
2110  /* Update the new queue family fields. If non-zero already,
2111  * it means API users have set it. */
2112  if (!hwctx->nb_qf) {
2113 #define ADD_QUEUE(ctx_qf, qc, flag) \
2114  do { \
2115  if (ctx_qf != -1) { \
2116  hwctx->qf[hwctx->nb_qf++] = (AVVulkanDeviceQueueFamily) { \
2117  .idx = ctx_qf, \
2118  .num = qc, \
2119  .flags = flag, \
2120  }; \
2121  } \
2122  } while (0)
2123 
2124  ADD_QUEUE(hwctx->queue_family_index, hwctx->nb_graphics_queues, VK_QUEUE_GRAPHICS_BIT);
2125  ADD_QUEUE(hwctx->queue_family_comp_index, hwctx->nb_comp_queues, VK_QUEUE_COMPUTE_BIT);
2126  ADD_QUEUE(hwctx->queue_family_tx_index, hwctx->nb_tx_queues, VK_QUEUE_TRANSFER_BIT);
2127  ADD_QUEUE(hwctx->queue_family_decode_index, hwctx->nb_decode_queues, VK_QUEUE_VIDEO_DECODE_BIT_KHR);
2128  ADD_QUEUE(hwctx->queue_family_encode_index, hwctx->nb_encode_queues, VK_QUEUE_VIDEO_ENCODE_BIT_KHR);
2129 #undef ADD_QUEUE
2130  }
2132 #endif
2133 
2134  for (int i = 0; i < hwctx->nb_qf; i++) {
2135  if (!hwctx->qf[i].video_caps &&
2136  hwctx->qf[i].flags & (VK_QUEUE_VIDEO_DECODE_BIT_KHR |
2137  VK_QUEUE_VIDEO_ENCODE_BIT_KHR)) {
2138  hwctx->qf[i].video_caps = qf_vid[hwctx->qf[i].idx].videoCodecOperations;
2139  }
2140  }
2141 
2142  /* Setup array for pQueueFamilyIndices with used queue families */
2143  p->nb_img_qfs = 0;
2144  for (int i = 0; i < hwctx->nb_qf; i++) {
2145  int seen = 0;
2146  /* Make sure each entry is unique
2147  * (VUID-VkBufferCreateInfo-sharingMode-01419) */
2148  for (int j = (i - 1); j >= 0; j--) {
2149  if (hwctx->qf[i].idx == hwctx->qf[j].idx) {
2150  seen = 1;
2151  break;
2152  }
2153  }
2154  if (!seen)
2155  p->img_qfs[p->nb_img_qfs++] = hwctx->qf[i].idx;
2156  }
2157 
2158 #if FF_API_VULKAN_SYNC_QUEUES
2160  if (!hwctx->lock_queue)
2161  hwctx->lock_queue = lock_queue;
2162  if (!hwctx->unlock_queue)
2163  hwctx->unlock_queue = unlock_queue;
2165 #endif
2166 
2167  /* Re-query device capabilities, in case the device was created externally */
2168  vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
2169 
2170  p->vkctx.device = ctx;
2171  p->vkctx.hwctx = hwctx;
2172 
2173  ff_vk_load_props(&p->vkctx);
2174  p->compute_qf = ff_vk_qf_find(&p->vkctx, VK_QUEUE_COMPUTE_BIT, 0);
2175  p->transfer_qf = ff_vk_qf_find(&p->vkctx, VK_QUEUE_TRANSFER_BIT, 0);
2176 
2177  /* Re-query device capabilities, in case the device was created externally */
2178  vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
2179 
2180 end:
2181  av_free(qf_vid);
2182  av_free(qf);
2183  return err;
2184 }
2185 
2186 static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device,
2187  AVDictionary *opts, int flags)
2188 {
2189  VulkanDeviceSelection dev_select = { 0 };
2190  if (device && device[0]) {
2191  char *end = NULL;
2192  dev_select.index = strtol(device, &end, 10);
2193  if (end == device) {
2194  dev_select.index = 0;
2195  dev_select.name = device;
2196  }
2197  }
2198 
2199  return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
2200 }
2201 
2203  AVHWDeviceContext *src_ctx,
2204  AVDictionary *opts, int flags)
2205 {
2206  av_unused VulkanDeviceSelection dev_select = { 0 };
2207 
2208  /* If there's only one device on the system, then even if its not covered
2209  * by the following checks (e.g. non-PCIe ARM GPU), having an empty
2210  * dev_select will mean it'll get picked. */
2211  switch(src_ctx->type) {
2212 #if CONFIG_VAAPI
2213  case AV_HWDEVICE_TYPE_VAAPI: {
2214  AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
2215  VADisplay dpy = src_hwctx->display;
2216 #if VA_CHECK_VERSION(1, 15, 0)
2217  VAStatus vas;
2218  VADisplayAttribute attr = {
2219  .type = VADisplayPCIID,
2220  };
2221 #endif
2222  const char *vendor;
2223 
2224 #if VA_CHECK_VERSION(1, 15, 0)
2225  vas = vaGetDisplayAttributes(dpy, &attr, 1);
2226  if (vas == VA_STATUS_SUCCESS && attr.flags != VA_DISPLAY_ATTRIB_NOT_SUPPORTED)
2227  dev_select.pci_device = (attr.value & 0xFFFF);
2228 #endif
2229 
2230  if (!dev_select.pci_device) {
2231  vendor = vaQueryVendorString(dpy);
2232  if (!vendor) {
2233  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n");
2234  return AVERROR_EXTERNAL;
2235  }
2236 
2237  if (strstr(vendor, "AMD"))
2238  dev_select.vendor_id = 0x1002;
2239  }
2240 
2241  return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
2242  }
2243 #endif
2244 #if CONFIG_LIBDRM
2245  case AV_HWDEVICE_TYPE_DRM: {
2246  int err;
2247  struct stat drm_node_info;
2248  drmDevice *drm_dev_info;
2249  AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
2250 
2251  err = fstat(src_hwctx->fd, &drm_node_info);
2252  if (err) {
2253  av_log(ctx, AV_LOG_ERROR, "Unable to get node info from DRM fd: %s!\n",
2254  av_err2str(AVERROR(errno)));
2255  return AVERROR_EXTERNAL;
2256  }
2257 
2258  dev_select.drm_major = major(drm_node_info.st_dev);
2259  dev_select.drm_minor = minor(drm_node_info.st_dev);
2260  dev_select.has_drm = 1;
2261 
2262  err = drmGetDevice(src_hwctx->fd, &drm_dev_info);
2263  if (err) {
2264  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd: %s!\n",
2265  av_err2str(AVERROR(errno)));
2266  return AVERROR_EXTERNAL;
2267  }
2268 
2269  if (drm_dev_info->bustype == DRM_BUS_PCI)
2270  dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id;
2271 
2272  drmFreeDevice(&drm_dev_info);
2273 
2274  return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
2275  }
2276 #endif
2277 #if CONFIG_CUDA
2278  case AV_HWDEVICE_TYPE_CUDA: {
2279  AVHWDeviceContext *cuda_cu = src_ctx;
2280  AVCUDADeviceContext *src_hwctx = src_ctx->hwctx;
2281  AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal;
2282  CudaFunctions *cu = cu_internal->cuda_dl;
2283 
2284  int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid,
2285  cu_internal->cuda_device));
2286  if (ret < 0) {
2287  av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n");
2288  return AVERROR_EXTERNAL;
2289  }
2290 
2291  dev_select.has_uuid = 1;
2292 
2293  /*
2294  * CUDA is not able to import multiplane images, so always derive a
2295  * Vulkan device with multiplane disabled.
2296  */
2297  return vulkan_device_create_internal(ctx, &dev_select, 1, opts, flags);
2298  }
2299 #endif
2300  default:
2301  return AVERROR(ENOSYS);
2302  }
2303 }
2304 
2306  const void *hwconfig,
2307  AVHWFramesConstraints *constraints)
2308 {
2309  int count = 0;
2310  VulkanDevicePriv *p = ctx->hwctx;
2311 
2312  for (enum AVPixelFormat i = 0; i < nb_vk_formats_list; i++) {
2314  p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
2315  VK_IMAGE_TILING_OPTIMAL,
2316  NULL, NULL, NULL, NULL, p->disable_multiplane, 1) >= 0;
2317  }
2318 
2319  constraints->valid_sw_formats = av_malloc_array(count + 1,
2320  sizeof(enum AVPixelFormat));
2321  if (!constraints->valid_sw_formats)
2322  return AVERROR(ENOMEM);
2323 
2324  count = 0;
2325  for (enum AVPixelFormat i = 0; i < nb_vk_formats_list; i++) {
2327  p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
2328  VK_IMAGE_TILING_OPTIMAL,
2329  NULL, NULL, NULL, NULL, p->disable_multiplane, 1) >= 0) {
2330  constraints->valid_sw_formats[count++] = vk_formats_list[i].pixfmt;
2331  }
2332  }
2333 
2334  constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE;
2335 
2336  constraints->min_width = 1;
2337  constraints->min_height = 1;
2338  constraints->max_width = p->props.properties.limits.maxImageDimension2D;
2339  constraints->max_height = p->props.properties.limits.maxImageDimension2D;
2340 
2341  constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat));
2342  if (!constraints->valid_hw_formats)
2343  return AVERROR(ENOMEM);
2344 
2345  constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN;
2346  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
2347 
2348  return 0;
2349 }
2350 
2351 static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
2352  VkMemoryPropertyFlagBits req_flags, const void *alloc_extension,
2353  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
2354 {
2355  VkResult ret;
2356  int index = -1;
2357  VulkanDevicePriv *p = ctx->hwctx;
2358  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2359  AVVulkanDeviceContext *dev_hwctx = &p->p;
2360  VkMemoryAllocateInfo alloc_info = {
2361  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2362  .pNext = alloc_extension,
2363  .allocationSize = req->size,
2364  };
2365 
2366  /* The vulkan spec requires memory types to be sorted in the "optimal"
2367  * order, so the first matching type we find will be the best/fastest one */
2368  for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
2369  const VkMemoryType *type = &p->mprops.memoryTypes[i];
2370 
2371  /* The memory type must be supported by the requirements (bitfield) */
2372  if (!(req->memoryTypeBits & (1 << i)))
2373  continue;
2374 
2375  /* The memory type flags must include our properties */
2376  if ((type->propertyFlags & req_flags) != req_flags)
2377  continue;
2378 
2379  /* The memory type must be large enough */
2380  if (req->size > p->mprops.memoryHeaps[type->heapIndex].size)
2381  continue;
2382 
2383  /* Found a suitable memory type */
2384  index = i;
2385  break;
2386  }
2387 
2388  if (index < 0) {
2389  av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
2390  req_flags);
2391  return AVERROR(EINVAL);
2392  }
2393 
2394  alloc_info.memoryTypeIndex = index;
2395 
2396  ret = vk->AllocateMemory(dev_hwctx->act_dev, &alloc_info,
2397  dev_hwctx->alloc, mem);
2398  if (ret != VK_SUCCESS) {
2399  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
2400  ff_vk_ret2str(ret));
2401  return AVERROR(ENOMEM);
2402  }
2403 
2404  *mem_flags |= p->mprops.memoryTypes[index].propertyFlags;
2405 
2406  return 0;
2407 }
2408 
2410 {
2411  av_unused AVVkFrameInternal *internal = f->internal;
2412 
2413 #if CONFIG_CUDA
2414  if (internal->cuda_fc_ref) {
2415  AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
2416  int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
2417  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2418  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2419  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2420  CudaFunctions *cu = cu_internal->cuda_dl;
2421 
2422  for (int i = 0; i < planes; i++) {
2423  if (internal->cu_sem[i])
2424  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
2425  if (internal->cu_mma[i])
2426  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
2427  if (internal->ext_mem[i])
2428  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
2429 #ifdef _WIN32
2430  if (internal->ext_sem_handle[i])
2431  CloseHandle(internal->ext_sem_handle[i]);
2432  if (internal->ext_mem_handle[i])
2433  CloseHandle(internal->ext_mem_handle[i]);
2434 #endif
2435  }
2436 
2437  av_buffer_unref(&internal->cuda_fc_ref);
2438  }
2439 #endif
2440 
2441  if (internal->drm_sync_sem != VK_NULL_HANDLE)
2442  p->vkctx.vkfn.DestroySemaphore(p->p.act_dev, internal->drm_sync_sem,
2443  p->p.alloc);
2444 
2445  pthread_mutex_destroy(&internal->update_mutex);
2446  av_freep(&f->internal);
2447 }
2448 
2450 {
2451  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2452  AVVulkanDeviceContext *hwctx = &p->p;
2453  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2454  int nb_images = ff_vk_count_images(f);
2455  int nb_sems = 0;
2456 
2457  while (nb_sems < FF_ARRAY_ELEMS(f->sem) && f->sem[nb_sems])
2458  nb_sems++;
2459 
2460  if (nb_sems) {
2461  VkSemaphoreWaitInfo sem_wait = {
2462  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
2463  .flags = 0x0,
2464  .pSemaphores = f->sem,
2465  .pValues = f->sem_value,
2466  .semaphoreCount = nb_sems,
2467  };
2468 
2469  vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
2470  }
2471 
2473 
2474  for (int i = 0; i < nb_images; i++) {
2475  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2476  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2477  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2478  }
2479 
2480  av_free(f);
2481 }
2482 
2483 static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
2484 {
2485  vulkan_frame_free(opaque, (AVVkFrame*)data);
2486 }
2487 
2489  void *alloc_pnext, size_t alloc_pnext_stride)
2490 {
2491  int img_cnt = 0, err;
2492  VkResult ret;
2493  AVHWDeviceContext *ctx = hwfc->device_ctx;
2494  VulkanDevicePriv *p = ctx->hwctx;
2495  AVVulkanDeviceContext *hwctx = &p->p;
2496  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2497  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
2498 
2499  while (f->img[img_cnt]) {
2500  int use_ded_mem;
2501  VkImageMemoryRequirementsInfo2 req_desc = {
2502  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2503  .image = f->img[img_cnt],
2504  };
2505  VkMemoryDedicatedAllocateInfo ded_alloc = {
2506  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2507  .pNext = (void *)(((uint8_t *)alloc_pnext) + img_cnt*alloc_pnext_stride),
2508  };
2509  VkMemoryDedicatedRequirements ded_req = {
2510  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2511  };
2512  VkMemoryRequirements2 req = {
2513  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2514  .pNext = &ded_req,
2515  };
2516 
2517  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
2518 
2519  av_log(hwfc, AV_LOG_TRACE,
2520  "plane %d: driver reports prefersDedicatedAllocation=%i requiresDedicatedAllocation=%i\n",
2521  img_cnt, ded_req.prefersDedicatedAllocation, ded_req.requiresDedicatedAllocation);
2522 
2523  if (f->tiling == VK_IMAGE_TILING_LINEAR)
2524  req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
2525  p->props.properties.limits.minMemoryMapAlignment);
2526 
2527  /* In case the implementation prefers/requires dedicated allocation */
2528  use_ded_mem = ded_req.prefersDedicatedAllocation |
2529  ded_req.requiresDedicatedAllocation;
2530  if (((VulkanFramesPriv *)hwfc->hwctx)->export_requires_dedicated)
2531  use_ded_mem = 1;
2532  if (use_ded_mem)
2533  ded_alloc.image = f->img[img_cnt];
2534 
2535  /* Allocate memory */
2536  if ((err = alloc_mem(ctx, &req.memoryRequirements,
2537  f->tiling == VK_IMAGE_TILING_LINEAR ?
2538  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
2539  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2540  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
2541  &f->flags, &f->mem[img_cnt])))
2542  return err;
2543 
2544  f->size[img_cnt] = req.memoryRequirements.size;
2545  bind_info[img_cnt].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2546  bind_info[img_cnt].image = f->img[img_cnt];
2547  bind_info[img_cnt].memory = f->mem[img_cnt];
2548 
2549  img_cnt++;
2550  }
2551 
2552  /* Bind the allocated memory to the images */
2553  ret = vk->BindImageMemory2(hwctx->act_dev, img_cnt, bind_info);
2554  if (ret != VK_SUCCESS) {
2555  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2556  ff_vk_ret2str(ret));
2557  return AVERROR_EXTERNAL;
2558  }
2559 
2560  return 0;
2561 }
2562 
2563 enum PrepMode {
2571 };
2572 
2573 static void switch_new_props(enum PrepMode pmode, VkImageLayout *new_layout,
2574  VkAccessFlags2 *new_access)
2575 {
2576  switch (pmode) {
2577  case PREP_MODE_GENERAL:
2578  *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2579  *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2580  break;
2581  case PREP_MODE_WRITE:
2582  *new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2583  *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2584  break;
2586  *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2587  *new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
2588  break;
2590  *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2591  *new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
2592  break;
2594  *new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR;
2595  *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2596  break;
2598  *new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
2599  *new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
2600  break;
2602  *new_layout = VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR;
2603  *new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
2604  break;
2605  }
2606 }
2607 
2609  AVVkFrame *frame, enum PrepMode pmode)
2610 {
2611  int err;
2612  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2613  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2614  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
2615  int nb_img_bar = 0;
2616 
2617  VkImageLayout new_layout;
2618  VkAccessFlags2 new_access;
2619  switch_new_props(pmode, &new_layout, &new_access);
2620 
2621  uint32_t dst_qf = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2622  VkPipelineStageFlagBits2 src_stage = VK_PIPELINE_STAGE_2_NONE;
2623  if (pmode == PREP_MODE_EXTERNAL_EXPORT) {
2624  dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
2625  src_stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
2626  }
2627 
2628  /* This is dirty - but it works. The vulkan.c dependency system doesn't
2629  * free non-refcounted frames, and non-refcounted hardware frames cannot
2630  * happen anywhere outside of here. */
2631  AVBufferRef tmp_ref = {
2632  .data = (uint8_t *)hwfc,
2633  };
2634  AVFrame tmp_frame = {
2635  .data[0] = (uint8_t *)frame,
2636  .hw_frames_ctx = &tmp_ref,
2637  };
2638 
2639  VkCommandBuffer cmd_buf;
2640  FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, ectx);
2641  cmd_buf = exec->buf;
2642  ff_vk_exec_start(&p->vkctx, exec);
2643 
2644  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, &tmp_frame,
2645  VK_PIPELINE_STAGE_2_NONE,
2646  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
2647  if (err < 0)
2648  return err;
2649 
2650  ff_vk_frame_barrier(&p->vkctx, exec, &tmp_frame, img_bar, &nb_img_bar,
2651  src_stage,
2652  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
2653  new_access, new_layout, dst_qf);
2654 
2655  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
2656  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
2657  .pImageMemoryBarriers = img_bar,
2658  .imageMemoryBarrierCount = nb_img_bar,
2659  });
2660 
2661  err = ff_vk_exec_submit(&p->vkctx, exec);
2662  if (err < 0)
2663  return err;
2664 
2665  /* We can do this because there are no real dependencies */
2666  ff_vk_exec_discard_deps(&p->vkctx, exec);
2667 
2668  return 0;
2669 }
2670 
2672  AVVkFrame *frame, enum PrepMode pmode)
2673 {
2674  VkResult ret;
2675  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2676  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2677  VkHostImageLayoutTransitionInfoEXT layout_change[AV_NUM_DATA_POINTERS];
2678  int nb_images = ff_vk_count_images(frame);
2679 
2680  VkImageLayout new_layout;
2681  VkAccessFlags2 new_access;
2682  switch_new_props(pmode, &new_layout, &new_access);
2683 
2684  int i;
2685  for (i = 0; i < p->vkctx.host_image_props.copyDstLayoutCount; i++) {
2686  if (p->vkctx.host_image_props.pCopyDstLayouts[i] == new_layout)
2687  break;
2688  }
2689  if (i == p->vkctx.host_image_props.copyDstLayoutCount)
2690  return AVERROR(ENOTSUP);
2691 
2692  for (i = 0; i < nb_images; i++) {
2693  layout_change[i] = (VkHostImageLayoutTransitionInfoEXT) {
2694  .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
2695  .image = frame->img[i],
2696  .oldLayout = frame->layout[i],
2697  .newLayout = new_layout,
2698  .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2699  .subresourceRange.layerCount = 1,
2700  .subresourceRange.levelCount = 1,
2701  };
2702  frame->layout[i] = new_layout;
2703  }
2704 
2705  ret = vk->TransitionImageLayoutEXT(p->vkctx.hwctx->act_dev,
2706  nb_images, layout_change);
2707  if (ret != VK_SUCCESS) {
2708  av_log(hwfc, AV_LOG_ERROR, "Unable to prepare frame: %s\n",
2709  ff_vk_ret2str(ret));
2710  return AVERROR_EXTERNAL;
2711  }
2712 
2713  return 0;
2714 }
2715 
2717  AVVkFrame *frame, enum PrepMode pmode)
2718 {
2719  int err = 0;
2720  AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
2721  if (hwfc_vk->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
2722  (pmode != PREP_MODE_EXTERNAL_EXPORT) &&
2723  (pmode != PREP_MODE_EXTERNAL_IMPORT))
2724  err = switch_layout_host(hwfc, ectx, frame, pmode);
2725 
2726  if (err != AVERROR(ENOTSUP))
2727  return err;
2728 
2729  return switch_layout(hwfc, ectx, frame, pmode);
2730 }
2731 
2732 static inline void get_plane_wh(uint32_t *w, uint32_t *h, enum AVPixelFormat format,
2733  int frame_w, int frame_h, int plane)
2734 {
2736 
2737  /* Currently always true unless gray + alpha support is added */
2738  if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB ||
2739  !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
2740  *w = frame_w;
2741  *h = frame_h;
2742  return;
2743  }
2744 
2745  *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w);
2746  *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h);
2747 }
2748 
2750  VkImageTiling tiling, VkImageUsageFlagBits usage,
2751  VkImageCreateFlags flags, int nb_layers,
2752  void *create_pnext)
2753 {
2754  int err;
2755  VkResult ret;
2756  AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
2757  AVHWDeviceContext *ctx = hwfc->device_ctx;
2758  VulkanDevicePriv *p = ctx->hwctx;
2759  AVVulkanDeviceContext *hwctx = &p->p;
2760  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2761  AVVkFrame *f;
2762 
2763  VkSemaphoreTypeCreateInfo sem_type_info = {
2764  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2765  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2766  .initialValue = 0,
2767  };
2768  VkSemaphoreCreateInfo sem_spawn = {
2769  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2770  .pNext = &sem_type_info,
2771  };
2772 
2773  VkExportSemaphoreCreateInfo ext_sem_info_opaque = {
2774  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
2775 #ifdef _WIN32
2776  .handleTypes = IsWindows8OrGreater()
2777  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2778  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2779 #else
2780  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2781 #endif
2782  };
2783 
2784  /* Check if exporting is supported before chaining any structs */
2785  if (p->ext_sem_props_opaque.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) {
2786  if (p->vkctx.extensions & (FF_VK_EXT_EXTERNAL_WIN32_SEM | FF_VK_EXT_EXTERNAL_FD_SEM))
2787  ff_vk_link_struct(&sem_type_info, &ext_sem_info_opaque);
2788  }
2789 
2790  f = av_vk_frame_alloc();
2791  if (!f) {
2792  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2793  return AVERROR(ENOMEM);
2794  }
2795 
2796  // TODO: check width and height for alignment in case of multiplanar (must be mod-2 if subsampled)
2797 
2798  /* Create the images */
2799  for (int i = 0; (hwfc_vk->format[i] != VK_FORMAT_UNDEFINED); i++) {
2800  VkImageCreateInfo create_info = {
2801  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2802  .pNext = create_pnext,
2803  .imageType = VK_IMAGE_TYPE_2D,
2804  .format = hwfc_vk->format[i],
2805  .extent.depth = 1,
2806  .mipLevels = 1,
2807  .arrayLayers = nb_layers,
2808  .flags = flags,
2809  .tiling = tiling,
2810  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2811  .usage = usage,
2812  .samples = VK_SAMPLE_COUNT_1_BIT,
2813  .pQueueFamilyIndices = p->img_qfs,
2814  .queueFamilyIndexCount = p->nb_img_qfs,
2815  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2816  VK_SHARING_MODE_EXCLUSIVE,
2817  };
2818 
2819  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2820  hwfc->sw_format, hwfc->width, hwfc->height, i);
2821 
2822  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2823  hwctx->alloc, &f->img[i]);
2824  if (ret != VK_SUCCESS) {
2825  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2826  ff_vk_ret2str(ret));
2827  err = AVERROR(EINVAL);
2828  goto fail;
2829  }
2830 
2831  /* Create semaphore */
2832  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2833  hwctx->alloc, &f->sem[i]);
2834  if (ret != VK_SUCCESS) {
2835  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2836  ff_vk_ret2str(ret));
2837  err = AVERROR_EXTERNAL;
2838  goto fail;
2839  }
2840 
2841  f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2842  f->layout[i] = create_info.initialLayout;
2843  f->access[i] = 0x0;
2844  f->sem_value[i] = 0;
2845  }
2846 
2847  f->flags = 0x0;
2848  f->tiling = tiling;
2849 
2850  *frame = f;
2851  return 0;
2852 
2853 fail:
2854  vulkan_frame_free(hwfc, f);
2855  return err;
2856 }
2857 
2858 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2860  VkExternalMemoryHandleTypeFlags *comp_handle_types,
2861  VkExternalMemoryHandleTypeFlags *iexp,
2862  VkExternalMemoryHandleTypeFlagBits exp)
2863 {
2864  VkResult ret;
2865  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2866  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2867  AVVulkanDeviceContext *dev_hwctx = &p->p;
2868  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2869 
2870  const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
2872  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2873  int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
2874  int nb_mods;
2875 
2876  VkExternalImageFormatProperties eprops = {
2877  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2878  };
2879  VkImageFormatProperties2 props = {
2880  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2881  .pNext = &eprops,
2882  };
2883  VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
2884  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2885  .pNext = NULL,
2886  .pQueueFamilyIndices = p->img_qfs,
2887  .queueFamilyIndexCount = p->nb_img_qfs,
2888  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2889  VK_SHARING_MODE_EXCLUSIVE,
2890  };
2891  VkPhysicalDeviceExternalImageFormatInfo enext = {
2892  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2893  .handleType = exp,
2894  .pNext = has_mods ? &phy_dev_mod_info : NULL,
2895  };
2896  VkPhysicalDeviceImageFormatInfo2 pinfo = {
2897  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2898  .pNext = !exp ? NULL : &enext,
2899  .format = vk_find_format_entry(hwfc->sw_format)->vkf,
2900  .type = VK_IMAGE_TYPE_2D,
2901  .tiling = hwctx->tiling,
2902  .usage = hwctx->usage,
2903  .flags = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && has_mods) ?
2904  (hwctx->img_flags) : (VkImageCreateFlags)(VK_IMAGE_CREATE_ALIAS_BIT),
2905  };
2906 
2907  nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
2908  for (int i = 0; i < nb_mods; i++) {
2909  if (has_mods)
2910  phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
2911 
2912  ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
2913  &pinfo, &props);
2914 
2915  if (has_mods)
2916  av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
2917  i, (unsigned long long)phy_dev_mod_info.drmFormatModifier,
2918  ret == VK_SUCCESS ? "OK" : "FAIL");
2919  if (ret == VK_SUCCESS) {
2920  *iexp |= exp;
2921  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2922  if (exp == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
2923  VulkanFramesPriv *fp = hwfc->hwctx;
2924  fp->export_requires_dedicated = !!(eprops.externalMemoryProperties.externalMemoryFeatures &
2925  VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
2926  }
2927  }
2928  }
2929 }
2930 
2931 static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2932 {
2933  int err;
2934  AVVkFrame *f;
2935  AVBufferRef *avbuf = NULL;
2936  AVHWFramesContext *hwfc = opaque;
2937  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2938  VulkanFramesPriv *fp = hwfc->hwctx;
2939  AVVulkanFramesContext *hwctx = &fp->p;
2940  VkExternalMemoryHandleTypeFlags e = 0x0;
2941  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2942 
2943  VkExternalMemoryImageCreateInfo eiinfo = {
2944  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2945  .pNext = hwctx->create_pnext,
2946  };
2947 
2948 #ifdef _WIN32
2949  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2950  try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2951  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2952  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2953 #else
2954  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
2955  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
2956  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2957  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2958 
2959  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_DMABUF_MEMORY &&
2960  hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
2961  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2962  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2963 #endif
2964 
2965  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2966  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2967  eminfo[i].pNext = hwctx->alloc_pnext[i];
2968  eminfo[i].handleTypes = e;
2969  }
2970 
2971  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
2972  hwctx->nb_layers,
2973  eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
2974  if (err) {
2975  av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed: create_frame failed: %d\n", err);
2976  return NULL;
2977  }
2978 
2979  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2980  if (err)
2981  goto fail;
2982 
2983  if ( (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2984  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR))
2985  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DPB);
2986  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)
2987  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DST);
2988  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR)
2989  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_ENCODING_DPB);
2990  else if (hwctx->usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
2991  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_WRITE);
2992  else
2993  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_GENERAL);
2994  if (err)
2995  goto fail;
2996 
2997  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2998  vulkan_frame_free_cb, hwfc, 0);
2999  if (!avbuf)
3000  goto fail;
3001 
3002  return avbuf;
3003 
3004 fail:
3005  av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed with error %d\n", err);
3006  vulkan_frame_free(hwfc, f);
3007  return NULL;
3008 }
3009 
3011 {
3013 }
3014 
3016 {
3018 }
3019 
3021 {
3022  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
3023  VulkanFramesPriv *fp = hwfc->hwctx;
3024 
3025  if (fp->modifier_info) {
3026  if (fp->modifier_info->pDrmFormatModifiers)
3027  av_freep(&fp->modifier_info->pDrmFormatModifiers);
3028  av_freep(&fp->modifier_info);
3029  }
3030 
3031  ff_vk_exec_pool_free(&p->vkctx, &fp->compute_exec);
3032  ff_vk_exec_pool_free(&p->vkctx, &fp->upload_exec);
3033  ff_vk_exec_pool_free(&p->vkctx, &fp->download_exec);
3034 
3035  av_buffer_pool_uninit(&fp->tmp);
3036 }
3037 
3039 {
3040  int err;
3041  AVVkFrame *f;
3042  VulkanFramesPriv *fp = hwfc->hwctx;
3043  AVVulkanFramesContext *hwctx = &fp->p;
3044  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
3045  AVVulkanDeviceContext *dev_hwctx = &p->p;
3046  VkImageUsageFlags supported_usage;
3047  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3048  const struct FFVkFormatEntry *fmt;
3049  int disable_multiplane = p->disable_multiplane ||
3051  int is_lone_dpb = ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR) ||
3052  ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
3053  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)));
3054 
3055  /* Defaults */
3056  if (!hwctx->nb_layers)
3057  hwctx->nb_layers = 1;
3058 
3059  /* VK_IMAGE_TILING_OPTIMAL == 0, can't check for it really */
3060  if (p->use_linear_images &&
3061  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
3062  hwctx->tiling = VK_IMAGE_TILING_LINEAR;
3063 
3064 
3065  fmt = vk_find_format_entry(hwfc->sw_format);
3066  if (!fmt) {
3067  av_log(hwfc, AV_LOG_ERROR, "Unsupported pixel format: %s!\n",
3069  return AVERROR(ENOTSUP);
3070  }
3071 
3072  if (hwctx->format[0] != VK_FORMAT_UNDEFINED) {
3073  if (hwctx->format[0] != fmt->vkf) {
3074  for (int i = 0; i < fmt->nb_images_fallback; i++) {
3075  if (hwctx->format[i] != fmt->fallback[i]) {
3076  av_log(hwfc, AV_LOG_ERROR, "Incompatible Vulkan format given "
3077  "for the current sw_format %s!\n",
3079  return AVERROR(EINVAL);
3080  }
3081  }
3082  }
3083 
3084  /* Check if the sw_format itself is supported */
3085  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3086  hwctx->tiling, NULL,
3087  NULL, NULL, &supported_usage, 0,
3088  !hwctx->usage ||
3089  (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3090  if (err < 0) {
3091  av_log(hwfc, AV_LOG_ERROR, "Unsupported sw format: %s!\n",
3093  return AVERROR(EINVAL);
3094  }
3095  } else {
3096  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3097  hwctx->tiling, hwctx->format, NULL,
3098  NULL, &supported_usage,
3099  disable_multiplane,
3100  !hwctx->usage ||
3101  (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3102  if (err < 0)
3103  return err;
3104  }
3105 
3106  /* Lone DPB images do not need additional flags. */
3107  /* With DRM modifier + video profile the caller has already chosen a valid
3108  * usage/img_flags/chain; do not add usage or img_flags (supported_usage does
3109  * not consider the actual modifier or video profile). */
3110  int drm_mod_with_video = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
3112  VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
3113 
3114  if (!is_lone_dpb && !drm_mod_with_video) {
3115  /* Image usage flags */
3116  hwctx->usage |= supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
3117  VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
3118  VK_IMAGE_USAGE_STORAGE_BIT |
3119  VK_IMAGE_USAGE_SAMPLED_BIT);
3120 
3121  if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY &&
3122  !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) &&
3123  !(p->dprops.driverID == VK_DRIVER_ID_MOLTENVK))
3124  hwctx->usage |= supported_usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
3125 
3126  /* Enables encoding of images, if supported by format and extensions */
3127  if ((supported_usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3128  (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3129  (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1))
3130  hwctx->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
3131 
3132  /* Image creation flags.
3133  * Only fill them in automatically if the image is not going to be used as
3134  * a DPB-only image, and we have SAMPLED/STORAGE bits set. */
3135  if (!hwctx->img_flags) {
3136  int sampleable = hwctx->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
3137  VK_IMAGE_USAGE_STORAGE_BIT);
3138  hwctx->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
3139  if (sampleable) {
3140  hwctx->img_flags |= VK_IMAGE_CREATE_ALIAS_BIT;
3141  if ((fmt->vk_planes > 1) && (hwctx->format[0] == fmt->vkf))
3142  hwctx->img_flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
3143  }
3144  }
3145  }
3146 
3147  /* If the image has an ENCODE_SRC usage, and the maintenance1
3148  * extension is supported, check if it has a profile list.
3149  * If there's no profile list, or it has no encode operations,
3150  * then allow creating the image with no specific profile. */
3151  if ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3152  (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3153  (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) {
3154  const VkVideoProfileListInfoKHR *pl;
3155  pl = ff_vk_find_struct(hwctx->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
3156  if (!pl) {
3157  hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3158  } else {
3159  uint32_t i;
3160  for (i = 0; i < pl->profileCount; i++) {
3161  /* Video ops start at exactly 0x00010000 */
3162  if (pl->pProfiles[i].videoCodecOperation & 0xFFFF0000)
3163  break;
3164  }
3165  if (i == pl->profileCount)
3166  hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3167  }
3168  }
3169 
3170  if (!hwctx->lock_frame)
3171  hwctx->lock_frame = lock_frame;
3172 
3173  if (!hwctx->unlock_frame)
3174  hwctx->unlock_frame = unlock_frame;
3175 
3176  err = ff_vk_exec_pool_init(&p->vkctx, p->compute_qf, &fp->compute_exec,
3177  p->compute_qf->num, 0, 0, 0, NULL);
3178  if (err)
3179  return err;
3180 
3181  err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->upload_exec,
3182  p->transfer_qf->num*2, 0, 0, 0, NULL);
3183  if (err)
3184  return err;
3185 
3186  err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->download_exec,
3187  p->transfer_qf->num, 0, 0, 0, NULL);
3188  if (err)
3189  return err;
3190 
3191  /* Test to see if allocation will fail */
3192  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
3193  hwctx->nb_layers, hwctx->create_pnext);
3194  if (err)
3195  return err;
3196 
3197  /* Collect `VkDrmFormatModifierPropertiesEXT` for each plane. Required for DRM export. */
3198  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS && hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
3199  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3200  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3201  };
3202  err = vk->GetImageDrmFormatModifierPropertiesEXT(dev_hwctx->act_dev, f->img[0],
3203  &drm_mod);
3204  if (err != VK_SUCCESS) {
3205  av_log(hwfc, AV_LOG_ERROR, "Failed to get image DRM format modifier properties");
3206  vulkan_frame_free(hwfc, f);
3207  return AVERROR_EXTERNAL;
3208  }
3209  for (int i = 0; i < fmt->vk_planes; ++i) {
3210  VkDrmFormatModifierPropertiesListEXT modp;
3211  VkFormatProperties2 fmtp;
3212  VkDrmFormatModifierPropertiesEXT *mod_props = NULL;
3213 
3214  modp = (VkDrmFormatModifierPropertiesListEXT) {
3215  .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
3216  };
3217  fmtp = (VkFormatProperties2) {
3218  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
3219  .pNext = &modp,
3220  };
3221 
3222  /* query drmFormatModifierCount by keeping pDrmFormatModifierProperties NULL */
3223  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3224 
3225  modp.pDrmFormatModifierProperties =
3226  av_calloc(modp.drmFormatModifierCount, sizeof(*modp.pDrmFormatModifierProperties));
3227  if (!modp.pDrmFormatModifierProperties) {
3228  vulkan_frame_free(hwfc, f);
3229  return AVERROR(ENOMEM);
3230  }
3231  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3232 
3233  for (uint32_t j = 0; j < modp.drmFormatModifierCount; ++j) {
3234  VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[j];
3235  if (m->drmFormatModifier == drm_mod.drmFormatModifier) {
3236  mod_props = m;
3237  break;
3238  }
3239  }
3240 
3241  if (mod_props == NULL) {
3242  av_log(hwfc, AV_LOG_ERROR, "No DRM format modifier properties found for modifier 0x%016"PRIx64"\n",
3243  drm_mod.drmFormatModifier);
3244  av_free(modp.pDrmFormatModifierProperties);
3245  vulkan_frame_free(hwfc, f);
3246  return AVERROR_EXTERNAL;
3247  }
3248 
3249  fp->drm_format_modifier_properties[i] = *mod_props;
3250  av_free(modp.pDrmFormatModifierProperties);
3251  }
3252  }
3253 
3254  vulkan_frame_free(hwfc, f);
3255 
3256  /* If user did not specify a pool, hwfc->pool will be set to the internal one
3257  * in hwcontext.c just after this gets called */
3258  if (!hwfc->pool) {
3260  hwfc, vulkan_pool_alloc,
3261  NULL);
3262  if (!ffhwframesctx(hwfc)->pool_internal)
3263  return AVERROR(ENOMEM);
3264  }
3265 
3266  return 0;
3267 }
3268 
3270 {
3271  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
3272  if (!frame->buf[0])
3273  return AVERROR(ENOMEM);
3274 
3275  frame->data[0] = frame->buf[0]->data;
3276  frame->format = AV_PIX_FMT_VULKAN;
3277  frame->width = hwfc->width;
3278  frame->height = hwfc->height;
3279 
3280  return 0;
3281 }
3282 
3284  enum AVHWFrameTransferDirection dir,
3285  enum AVPixelFormat **formats)
3286 {
3287  enum AVPixelFormat *fmts;
3288  int n = 2;
3289 
3290 #if CONFIG_CUDA
3291  n++;
3292 #endif
3293  fmts = av_malloc_array(n, sizeof(*fmts));
3294  if (!fmts)
3295  return AVERROR(ENOMEM);
3296 
3297  n = 0;
3298  fmts[n++] = hwfc->sw_format;
3299 #if CONFIG_CUDA
3300  fmts[n++] = AV_PIX_FMT_CUDA;
3301 #endif
3302  fmts[n++] = AV_PIX_FMT_NONE;
3303 
3304  *formats = fmts;
3305  return 0;
3306 }
3307 
3308 #if CONFIG_LIBDRM
3309 static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3310 {
3311  vulkan_frame_free(hwfc, hwmap->priv);
3312 }
3313 
3314 static const struct {
3315  uint32_t drm_fourcc;
3316  VkFormat vk_format;
3317 } vulkan_drm_format_map[] = {
3318  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
3319  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
3320  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
3321  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
3322  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
3323  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
3324  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3325  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3326  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3327  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3328  { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3329  { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3330  { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3331  { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3332 
3333  // All these DRM_FORMATs were added in the same libdrm commit.
3334 #ifdef DRM_FORMAT_XYUV8888
3335  { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
3336  { DRM_FORMAT_XVYU2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 } ,
3337  { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 } ,
3338  { DRM_FORMAT_XVYU16161616, VK_FORMAT_R16G16B16A16_UNORM } ,
3339 #endif
3340 };
3341 
3342 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
3343 {
3344  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3345  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
3346  return vulkan_drm_format_map[i].vk_format;
3347  return VK_FORMAT_UNDEFINED;
3348 }
3349 
3350 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
3351  const AVFrame *src, int flags)
3352 {
3353  int err = 0;
3354  VkResult ret;
3355  AVVkFrame *f;
3356  int bind_counts = 0;
3357  AVHWDeviceContext *ctx = hwfc->device_ctx;
3358  VulkanDevicePriv *p = ctx->hwctx;
3359  AVVulkanDeviceContext *hwctx = &p->p;
3360  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3361  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
3362  VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
3363  VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
3364 
3365  for (int i = 0; i < desc->nb_layers; i++) {
3366  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
3367  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
3368  desc->layers[i].format);
3369  return AVERROR(EINVAL);
3370  }
3371  }
3372 
3373  if (!(f = av_vk_frame_alloc())) {
3374  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
3375  err = AVERROR(ENOMEM);
3376  goto fail;
3377  }
3378 
3379  f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
3380 
3381  for (int i = 0; i < desc->nb_layers; i++) {
3382  const int planes = desc->layers[i].nb_planes;
3383 
3384  /* Semaphore */
3385  VkSemaphoreTypeCreateInfo sem_type_info = {
3386  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3387  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
3388  .initialValue = 0,
3389  };
3390  VkSemaphoreCreateInfo sem_spawn = {
3391  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3392  .pNext = &sem_type_info,
3393  };
3394 
3395  /* Image creation */
3396  VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
3397  VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
3398  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
3399  .drmFormatModifier = desc->objects[0].format_modifier,
3400  .drmFormatModifierPlaneCount = planes,
3401  .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
3402  };
3403  VkExternalMemoryImageCreateInfo ext_img_spec = {
3404  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
3405  .pNext = &ext_img_mod_spec,
3406  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3407  };
3408  VkImageCreateInfo create_info = {
3409  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3410  .pNext = &ext_img_spec,
3411  .imageType = VK_IMAGE_TYPE_2D,
3412  .format = drm_to_vulkan_fmt(desc->layers[i].format),
3413  .extent.depth = 1,
3414  .mipLevels = 1,
3415  .arrayLayers = 1,
3416  .flags = 0x0,
3417  .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
3418  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
3419  .usage = 0x0, /* filled in below */
3420  .samples = VK_SAMPLE_COUNT_1_BIT,
3421  .pQueueFamilyIndices = p->img_qfs,
3422  .queueFamilyIndexCount = p->nb_img_qfs,
3423  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
3424  VK_SHARING_MODE_EXCLUSIVE,
3425  };
3426 
3427  /* The DRM fourcc fixes a specific channel order (f.ex ARGB8888 maps to
3428  * B8G8R8A8), but image views are always created from the destination
3429  * frames context sw_format (like how bgra maps to R8G8B8A8). For a
3430  * single plane layer, create the image with the sw_format's compatible
3431  * VkFormat so the image and its views agree without a mutable format
3432  * list, the format query below validates this */
3433  if (planes == 1) {
3434  const VkFormat *sw_vkfmts = av_vkfmt_from_pixfmt(hwfc->sw_format);
3435  if (sw_vkfmts && sw_vkfmts[i] != VK_FORMAT_UNDEFINED)
3436  create_info.format = sw_vkfmts[i];
3437  }
3438 
3439  /* Image format verification */
3440  VkExternalImageFormatProperties ext_props = {
3441  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
3442  };
3443  VkImageFormatProperties2 props_ret = {
3444  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
3445  .pNext = &ext_props,
3446  };
3447  VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
3448  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
3449  .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
3450  .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
3451  .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
3452  .sharingMode = create_info.sharingMode,
3453  };
3454  VkPhysicalDeviceExternalImageFormatInfo props_ext = {
3455  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
3456  .pNext = &props_drm_mod,
3457  .handleType = ext_img_spec.handleTypes,
3458  };
3459  VkPhysicalDeviceImageFormatInfo2 fmt_props;
3460 
3461  if (flags & AV_HWFRAME_MAP_READ)
3462  create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT |
3463  VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
3465  create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT |
3466  VK_IMAGE_USAGE_TRANSFER_DST_BIT;
3467 
3468  fmt_props = (VkPhysicalDeviceImageFormatInfo2) {
3469  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
3470  .pNext = &props_ext,
3471  .format = create_info.format,
3472  .type = create_info.imageType,
3473  .tiling = create_info.tiling,
3474  .usage = create_info.usage,
3475  .flags = create_info.flags,
3476  };
3477 
3478  /* Check if importing is possible for this combination of parameters */
3479  ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
3480  &fmt_props, &props_ret);
3481  if (ret != VK_SUCCESS) {
3482  av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
3483  ff_vk_ret2str(ret));
3484  err = AVERROR_EXTERNAL;
3485  goto fail;
3486  }
3487 
3488  /* Set the image width/height */
3489  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
3490  hwfc->sw_format, src->width, src->height, i);
3491 
3492  /* Set the subresource layout based on the layer properties */
3493  for (int j = 0; j < planes; j++) {
3494  ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
3495  ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
3496  ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
3497  ext_img_layouts[j].arrayPitch = 0;
3498  ext_img_layouts[j].depthPitch = 0;
3499  }
3500 
3501  /* Create image */
3502  ret = vk->CreateImage(hwctx->act_dev, &create_info,
3503  hwctx->alloc, &f->img[i]);
3504  if (ret != VK_SUCCESS) {
3505  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
3506  ff_vk_ret2str(ret));
3507  err = AVERROR(EINVAL);
3508  goto fail;
3509  }
3510 
3511  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3512  hwctx->alloc, &f->sem[i]);
3513  if (ret != VK_SUCCESS) {
3514  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3515  ff_vk_ret2str(ret));
3516  err = AVERROR_EXTERNAL;
3517  goto fail;
3518  }
3519 
3520  f->queue_family[i] = VK_QUEUE_FAMILY_EXTERNAL;
3521  f->layout[i] = create_info.initialLayout;
3522  f->access[i] = 0x0;
3523  f->sem_value[i] = 0;
3524  }
3525 
3526  for (int i = 0; i < desc->nb_layers; i++) {
3527  /* Memory requirements */
3528  VkImageMemoryRequirementsInfo2 req_desc = {
3529  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
3530  .image = f->img[i],
3531  };
3532  VkMemoryDedicatedRequirements ded_req = {
3533  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
3534  };
3535  VkMemoryRequirements2 req2 = {
3536  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3537  .pNext = &ded_req,
3538  };
3539 
3540  /* Allocation/importing */
3541  VkMemoryFdPropertiesKHR fdmp = {
3542  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
3543  };
3544  /* This assumes that a layer will never be constructed from multiple
3545  * objects. If that was to happen in the real world, this code would
3546  * need to import each plane separately.
3547  */
3548  VkImportMemoryFdInfoKHR idesc = {
3549  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
3550  .fd = dup(desc->objects[desc->layers[i].planes[0].object_index].fd),
3551  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3552  };
3553  VkMemoryDedicatedAllocateInfo ded_alloc = {
3554  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
3555  .pNext = &idesc,
3556  .image = req_desc.image,
3557  };
3558 
3559  /* Get object properties */
3560  ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
3561  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3562  idesc.fd, &fdmp);
3563  if (ret != VK_SUCCESS) {
3564  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
3565  ff_vk_ret2str(ret));
3566  err = AVERROR_EXTERNAL;
3567  close(idesc.fd);
3568  goto fail;
3569  }
3570 
3571  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
3572 
3573  /* Only a single bit must be set, not a range, and it must match */
3574  req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
3575 
3576  err = alloc_mem(ctx, &req2.memoryRequirements,
3577  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
3578  (ded_req.prefersDedicatedAllocation ||
3579  ded_req.requiresDedicatedAllocation) ?
3580  &ded_alloc : ded_alloc.pNext,
3581  &f->flags, &f->mem[i]);
3582  if (err) {
3583  close(idesc.fd);
3584  goto fail;
3585  }
3586 
3587  f->size[i] = req2.memoryRequirements.size;
3588  }
3589 
3590  for (int i = 0; i < desc->nb_layers; i++) {
3591  const int planes = desc->layers[i].nb_planes;
3592  for (int j = 0; j < planes; j++) {
3593  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
3594  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
3595  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
3596 
3597  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
3598  plane_info[bind_counts].pNext = NULL;
3599  plane_info[bind_counts].planeAspect = aspect;
3600 
3601  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
3602  bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
3603  bind_info[bind_counts].image = f->img[i];
3604  bind_info[bind_counts].memory = f->mem[i];
3605 
3606  /* Offset is already signalled via pPlaneLayouts above */
3607  bind_info[bind_counts].memoryOffset = 0;
3608 
3609  bind_counts++;
3610  }
3611  }
3612 
3613  /* Bind the allocated memory to the images */
3614  ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
3615  if (ret != VK_SUCCESS) {
3616  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
3617  ff_vk_ret2str(ret));
3618  err = AVERROR_EXTERNAL;
3619  goto fail;
3620  }
3621 
3622  *frame = f;
3623 
3624  return 0;
3625 
3626 fail:
3627  vulkan_frame_free(hwfc, f);
3628 
3629  return err;
3630 }
3631 
3632 static int vulkan_map_from_drm_frame_sync(AVHWFramesContext *hwfc, AVFrame *dst,
3633  const AVDRMFrameDescriptor *desc, int flags)
3634 {
3635  int err;
3636  VkResult ret;
3637  AVHWDeviceContext *ctx = hwfc->device_ctx;
3638  VulkanDevicePriv *p = ctx->hwctx;
3639  VulkanFramesPriv *fp = hwfc->hwctx;
3640  AVVulkanDeviceContext *hwctx = &p->p;
3641  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3642 
3643 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
3644  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) {
3645  VkCommandBuffer cmd_buf;
3646  FFVkExecContext *exec;
3647  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
3648  VkSemaphore drm_sync_sem[AV_DRM_MAX_PLANES] = { 0 };
3649  int nb_img_bar = 0;
3650 
3651  for (int i = 0; i < desc->nb_objects; i++) {
3652  VkSemaphoreTypeCreateInfo sem_type_info = {
3653  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3654  .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
3655  };
3656  VkSemaphoreCreateInfo sem_spawn = {
3657  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3658  .pNext = &sem_type_info,
3659  };
3660  VkImportSemaphoreFdInfoKHR import_info;
3661  struct dma_buf_export_sync_file implicit_fd_info = {
3662  .flags = DMA_BUF_SYNC_READ,
3663  .fd = -1,
3664  };
3665 
3666  if (ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
3667  &implicit_fd_info)) {
3668  err = AVERROR(errno);
3669  av_log(hwctx, AV_LOG_ERROR, "Failed to retrieve implicit DRM sync file: %s\n",
3670  av_err2str(err));
3671  for (; i >= 0; i--)
3672  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3673  return err;
3674  }
3675 
3676  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3677  hwctx->alloc, &drm_sync_sem[i]);
3678  if (ret != VK_SUCCESS) {
3679  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3680  ff_vk_ret2str(ret));
3681  err = AVERROR_EXTERNAL;
3682  for (; i >= 0; i--)
3683  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3684  return err;
3685  }
3686 
3687  import_info = (VkImportSemaphoreFdInfoKHR) {
3688  .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
3689  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
3690  .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
3691  .semaphore = drm_sync_sem[i],
3692  .fd = implicit_fd_info.fd,
3693  };
3694 
3695  ret = vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info);
3696  if (ret != VK_SUCCESS) {
3697  av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n",
3698  ff_vk_ret2str(ret));
3699  err = AVERROR_EXTERNAL;
3700  for (; i >= 0; i--)
3701  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3702  return err;
3703  }
3704  }
3705 
3706  exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
3707  cmd_buf = exec->buf;
3708 
3709  ff_vk_exec_start(&p->vkctx, exec);
3710 
3711  /* Ownership of semaphores is passed */
3712  err = ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec,
3713  drm_sync_sem, desc->nb_objects,
3714  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1);
3715  if (err < 0)
3716  return err;
3717 
3718  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, dst,
3719  VK_PIPELINE_STAGE_2_NONE,
3720  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
3721  if (err < 0)
3722  return err;
3723 
3724  ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar,
3725  VK_PIPELINE_STAGE_2_NONE,
3726  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
3727  ((flags & AV_HWFRAME_MAP_READ) ?
3728  VK_ACCESS_2_SHADER_SAMPLED_READ_BIT : 0x0) |
3730  VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT : 0x0),
3731  VK_IMAGE_LAYOUT_GENERAL,
3732  p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
3733 
3734  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
3735  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
3736  .pImageMemoryBarriers = img_bar,
3737  .imageMemoryBarrierCount = nb_img_bar,
3738  });
3739 
3740  err = ff_vk_exec_submit(&p->vkctx, exec);
3741  if (err < 0)
3742  return err;
3743  } else
3744 #endif
3745  {
3746  AVVkFrame *f = (AVVkFrame *)dst->data[0];
3747  av_log(hwctx, AV_LOG_WARNING, "No support for synchronization when importing DMA-BUFs, "
3748  "image may be corrupted.\n");
3750  if (err)
3751  return err;
3752  }
3753 
3754  return 0;
3755 }
3756 
3757 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3758  const AVFrame *src, int flags)
3759 {
3760  int err = 0;
3761  AVVkFrame *f;
3762  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
3763 
3764  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src, flags)))
3765  return err;
3766 
3767  /* The unmapping function will free this */
3768  dst->data[0] = (uint8_t *)f;
3769  dst->width = src->width;
3770  dst->height = src->height;
3771 
3772  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
3773  &vulkan_unmap_from_drm, f);
3774  if (err < 0)
3775  goto fail;
3776 
3777  err = vulkan_map_from_drm_frame_sync(hwfc, dst, desc, flags);
3778  if (err < 0)
3779  return err;
3780 
3781  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
3782 
3783  return 0;
3784 
3785 fail:
3787  dst->data[0] = NULL;
3788  return err;
3789 }
3790 
3791 #if CONFIG_VAAPI
3792 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
3793  AVFrame *dst, const AVFrame *src,
3794  int flags)
3795 {
3796  int err;
3797  AVFrame *tmp = av_frame_alloc();
3798  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3799  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
3800  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
3801 
3802  if (!tmp)
3803  return AVERROR(ENOMEM);
3804 
3805  /* We have to sync since like the previous comment said, no semaphores */
3806  vaSyncSurface(vaapi_ctx->display, surface_id);
3807 
3808  tmp->format = AV_PIX_FMT_DRM_PRIME;
3809 
3810  err = av_hwframe_map(tmp, src, flags);
3811  if (err < 0)
3812  goto fail;
3813 
3814  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
3815  if (err < 0)
3816  goto fail;
3817 
3818  err = ff_hwframe_map_replace(dst, src);
3819 
3820 fail:
3821  av_frame_free(&tmp);
3822  return err;
3823 }
3824 #endif
3825 #endif
3826 
3827 #if CONFIG_CUDA
3828 static int export_mem_to_cuda(AVHWDeviceContext *ctx,
3829  AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3830  AVVkFrameInternal *dst_int, int idx,
3831  VkDeviceMemory mem, size_t size)
3832 {
3833  VkResult ret;
3834  VulkanDevicePriv *p = ctx->hwctx;
3835  AVVulkanDeviceContext *hwctx = &p->p;
3836  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3837 
3838 #ifdef _WIN32
3839  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3840  .type = IsWindows8OrGreater()
3841  ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3842  : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
3843  .size = size,
3844  };
3845  VkMemoryGetWin32HandleInfoKHR export_info = {
3846  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
3847  .memory = mem,
3848  .handleType = IsWindows8OrGreater()
3849  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3850  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3851  };
3852 
3853  ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
3854  &ext_desc.handle.win32.handle);
3855  if (ret != VK_SUCCESS) {
3856  av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
3857  ff_vk_ret2str(ret));
3858  return AVERROR_EXTERNAL;
3859  }
3860  dst_int->ext_mem_handle[idx] = ext_desc.handle.win32.handle;
3861 #else
3862  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3863  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
3864  .size = size,
3865  };
3866  VkMemoryGetFdInfoKHR export_info = {
3867  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3868  .memory = mem,
3869  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
3870  };
3871 
3872  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3873  &ext_desc.handle.fd);
3874  if (ret != VK_SUCCESS) {
3875  av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
3876  ff_vk_ret2str(ret));
3877  return AVERROR_EXTERNAL;
3878  }
3879 #endif
3880 
3881  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[idx], &ext_desc));
3882  if (ret < 0) {
3883 #ifndef _WIN32
3884  close(ext_desc.handle.fd);
3885 #endif
3886  return AVERROR_EXTERNAL;
3887  }
3888 
3889  return 0;
3890 }
3891 
3892 static int export_sem_to_cuda(AVHWDeviceContext *ctx,
3893  AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3894  AVVkFrameInternal *dst_int, int idx,
3895  VkSemaphore sem)
3896 {
3897  VkResult ret;
3898  VulkanDevicePriv *p = ctx->hwctx;
3899  AVVulkanDeviceContext *hwctx = &p->p;
3900  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3901 
3902 #ifdef _WIN32
3903  VkSemaphoreGetWin32HandleInfoKHR sem_export = {
3904  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
3905  .semaphore = sem,
3906  .handleType = IsWindows8OrGreater()
3907  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
3908  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3909  };
3910  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3911  .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
3912  };
3913 #else
3914  VkSemaphoreGetFdInfoKHR sem_export = {
3915  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
3916  .semaphore = sem,
3917  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
3918  };
3919  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3920  .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
3921  };
3922 #endif
3923 
3924 #ifdef _WIN32
3925  ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
3926  &ext_sem_desc.handle.win32.handle);
3927 #else
3928  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
3929  &ext_sem_desc.handle.fd);
3930 #endif
3931  if (ret != VK_SUCCESS) {
3932  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
3933  ff_vk_ret2str(ret));
3934  return AVERROR_EXTERNAL;
3935  }
3936 #ifdef _WIN32
3937  dst_int->ext_sem_handle[idx] = ext_sem_desc.handle.win32.handle;
3938 #endif
3939 
3940  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[idx],
3941  &ext_sem_desc));
3942  if (ret < 0) {
3943 #ifndef _WIN32
3944  close(ext_sem_desc.handle.fd);
3945 #endif
3946  return AVERROR_EXTERNAL;
3947  }
3948 
3949  return 0;
3950 }
3951 
3952 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
3953  AVBufferRef *cuda_hwfc,
3954  const AVFrame *frame)
3955 {
3956  int err;
3957  VkResult ret;
3958  AVVkFrame *dst_f;
3959  AVVkFrameInternal *dst_int;
3960  AVHWDeviceContext *ctx = hwfc->device_ctx;
3961  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3963  VulkanDevicePriv *p = ctx->hwctx;
3964  AVVulkanDeviceContext *hwctx = &p->p;
3965  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3966  int nb_images;
3967 
3968  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
3969  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3970  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3971  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3972  CudaFunctions *cu = cu_internal->cuda_dl;
3973  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
3974  CU_AD_FORMAT_UNSIGNED_INT8;
3975 
3976  dst_f = (AVVkFrame *)frame->data[0];
3977  dst_int = dst_f->internal;
3978 
3979  if (!dst_int->cuda_fc_ref) {
3980  size_t offsets[3] = { 0 };
3981 
3982  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
3983  if (!dst_int->cuda_fc_ref)
3984  return AVERROR(ENOMEM);
3985 
3986  nb_images = ff_vk_count_images(dst_f);
3987  for (int i = 0; i < nb_images; i++) {
3988  err = export_mem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
3989  dst_f->mem[i], dst_f->size[i]);
3990  if (err < 0)
3991  goto fail;
3992 
3993  err = export_sem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
3994  dst_f->sem[i]);
3995  if (err < 0)
3996  goto fail;
3997  }
3998 
3999  if (nb_images != planes) {
4000  for (int i = 0; i < planes; i++) {
4001  VkImageSubresource subres = {
4002  .aspectMask = i == 2 ? VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT :
4003  i == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
4004  VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
4005  };
4006  VkSubresourceLayout layout = { 0 };
4007  vk->GetImageSubresourceLayout(hwctx->act_dev, dst_f->img[FFMIN(i, nb_images - 1)],
4008  &subres, &layout);
4009  offsets[i] = layout.offset;
4010  }
4011  }
4012 
4013  for (int i = 0; i < planes; i++) {
4014  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
4015  .offset = offsets[i],
4016  .arrayDesc = {
4017  .Depth = 0,
4018  .Format = cufmt,
4019  .NumChannels = 1 + ((planes == 2) && i),
4020  .Flags = 0,
4021  },
4022  .numLevels = 1,
4023  };
4024  int p_w, p_h;
4025 
4026  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4027  tex_desc.arrayDesc.Width = p_w;
4028  tex_desc.arrayDesc.Height = p_h;
4029 
4030  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
4031  dst_int->ext_mem[FFMIN(i, nb_images - 1)],
4032  &tex_desc));
4033  if (ret < 0) {
4034  err = AVERROR_EXTERNAL;
4035  goto fail;
4036  }
4037 
4038  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
4039  dst_int->cu_mma[i], 0));
4040  if (ret < 0) {
4041  err = AVERROR_EXTERNAL;
4042  goto fail;
4043  }
4044 
4045  }
4046  }
4047 
4048  return 0;
4049 
4050 fail:
4051  vulkan_free_internal(p, dst_f);
4052  return err;
4053 }
4054 
4055 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
4056  AVFrame *dst, const AVFrame *src)
4057 {
4058  int err;
4059  CUcontext dummy;
4060  AVVkFrame *dst_f;
4061  AVVkFrameInternal *dst_int;
4062  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4063  VulkanFramesPriv *fp = hwfc->hwctx;
4064  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4066 
4067  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
4068  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4069  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4070  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4071  CudaFunctions *cu = cu_internal->cuda_dl;
4072  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4073  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4074 
4075  dst_f = (AVVkFrame *)dst->data[0];
4076 
4077  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4078  if (err < 0)
4079  return err;
4080 
4081  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4082  if (err < 0)
4083  return err;
4084 
4085  err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
4086  if (err < 0) {
4087  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4088  return err;
4089  }
4090 
4091  dst_int = dst_f->internal;
4092 
4093  for (int i = 0; i < planes; i++) {
4094  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4095  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4096  }
4097 
4098  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4099  planes, cuda_dev->stream));
4100  if (err < 0)
4101  goto fail;
4102 
4103  for (int i = 0; i < planes; i++) {
4104  CUDA_MEMCPY2D cpy = {
4105  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
4106  .srcDevice = (CUdeviceptr)src->data[i],
4107  .srcPitch = src->linesize[i],
4108  .srcY = 0,
4109 
4110  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
4111  .dstArray = dst_int->cu_array[i],
4112  };
4113 
4114  int p_w, p_h;
4115  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4116 
4117  cpy.WidthInBytes = p_w * desc->comp[i].step;
4118  cpy.Height = p_h;
4119 
4120  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4121  if (err < 0)
4122  goto fail;
4123  }
4124 
4125  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4126  planes, cuda_dev->stream));
4127  if (err < 0)
4128  goto fail;
4129 
4130  for (int i = 0; i < planes; i++)
4131  dst_f->sem_value[i]++;
4132 
4133  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4134 
4135  av_log(hwfc, AV_LOG_VERBOSE, "Transferred CUDA image to Vulkan!\n");
4136 
4137  return err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4138 
4139 fail:
4140  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4141  vulkan_free_internal(p, dst_f);
4142  av_buffer_unref(&dst->buf[0]);
4143  return err;
4144 }
4145 #endif
4146 
4148  const AVFrame *src, int flags)
4149 {
4151 
4152  switch (src->format) {
4153 #if CONFIG_LIBDRM
4154 #if CONFIG_VAAPI
4155  case AV_PIX_FMT_VAAPI:
4156  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4157  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
4158  else
4159  return AVERROR(ENOSYS);
4160 #endif
4161  case AV_PIX_FMT_DRM_PRIME:
4162  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4163  return vulkan_map_from_drm(hwfc, dst, src, flags);
4164  else
4165  return AVERROR(ENOSYS);
4166 #endif
4167  default:
4168  return AVERROR(ENOSYS);
4169  }
4170 }
4171 
4172 #if CONFIG_LIBDRM
4173 typedef struct VulkanDRMMapping {
4174  AVDRMFrameDescriptor drm_desc;
4175  AVVkFrame *source;
4176 } VulkanDRMMapping;
4177 
4178 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
4179 {
4180  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
4181 
4182  /* on unmap from DRM, make sure to import sync objects so that we are sync'd with any work that was
4183  * done on the buffer while exported. We don't know if who used the dmabuf did reads or writes, so protect against both */
4184  vulkan_map_from_drm_frame_sync(hwfc, hwmap->source, drm_desc, AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE);
4185 
4186  for (int i = 0; i < drm_desc->nb_objects; i++)
4187  close(drm_desc->objects[i].fd);
4188 
4189  av_free(drm_desc);
4190 }
4191 
4192 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
4193 {
4194  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
4195  if (vulkan_drm_format_map[i].vk_format == vkfmt)
4196  return vulkan_drm_format_map[i].drm_fourcc;
4197  return DRM_FORMAT_INVALID;
4198 }
4199 
4200 #define MAX_MEMORY_PLANES 4
4201 static VkImageAspectFlags plane_index_to_aspect(int plane) {
4202  if (plane == 0) return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4203  if (plane == 1) return VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
4204  if (plane == 2) return VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
4205  if (plane == 3) return VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
4206 
4207  av_assert2 (0 && "Invalid plane index");
4208  return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4209 }
4210 
4211 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4212 static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
4213  VulkanFramesPriv *fp, int nb_sems)
4214 {
4215  int sync_fd = -1;
4216  VkResult ret;
4217  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4218  AVVulkanDeviceContext *hwctx = &p->p;
4219  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4220 
4221  if (f->internal->drm_sync_sem == VK_NULL_HANDLE) {
4222  VkExportSemaphoreCreateInfo exp_info = {
4223  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
4224  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4225  };
4226  VkSemaphoreTypeCreateInfo type_info = {
4227  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
4228  .pNext = &exp_info,
4229  .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
4230  };
4231  VkSemaphoreCreateInfo sem_create = {
4232  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
4233  .pNext = &type_info,
4234  };
4235  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_create, hwctx->alloc,
4236  &f->internal->drm_sync_sem);
4237  if (ret != VK_SUCCESS) {
4238  av_log(hwctx, AV_LOG_ERROR, "Failed to create DRM export semaphore: %s\n",
4239  ff_vk_ret2str(ret));
4240  return AVERROR_EXTERNAL;
4241  }
4242  }
4243 
4244  /* Submit a lightweight exec that waits on the timeline semaphore
4245  * (true last operation on the frame) and signals the binary semaphore,
4246  * so any Vulkan frame can get a SYNC_FD regardless of origin. */
4247  FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
4248  if (ff_vk_exec_start(&p->vkctx, exec) >= 0) {
4249  for (int i = 0; i < nb_sems; i++)
4250  ff_vk_exec_add_dep_wait_sem(&p->vkctx, exec, f->sem[i],
4251  f->sem_value[i],
4252  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
4253  ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, &f->internal->drm_sync_sem, 1,
4254  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0);
4255  if (ff_vk_exec_submit(&p->vkctx, exec) >= 0) {
4256  VkSemaphoreGetFdInfoKHR get_fd_info = {
4257  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
4258  .semaphore = f->internal->drm_sync_sem,
4259  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4260  };
4261  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &get_fd_info, &sync_fd);
4262  if (ret != VK_SUCCESS) {
4263  av_log(hwctx, AV_LOG_WARNING,
4264  "Failed to get sync fd from DRM map export semaphore: %s\n",
4265  ff_vk_ret2str(ret));
4266  sync_fd = -1;
4267  }
4268  } else {
4269  ff_vk_exec_discard_deps(&p->vkctx, exec);
4270  }
4271  }
4272 
4273  return sync_fd;
4274 }
4275 #endif
4276 
4277 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
4278  const AVFrame *src, int flags)
4279 {
4280  int err = 0;
4281  VkResult ret;
4282  AVVkFrame *f = (AVVkFrame *)src->data[0];
4283  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4284  AVVulkanDeviceContext *hwctx = &p->p;
4285  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4286  VulkanFramesPriv *fp = hwfc->hwctx;
4287  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4288  const int nb_images = ff_vk_count_images(f);
4289  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
4290  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
4291  };
4292  const int nb_sems = nb_images;
4293  int free_drm_desc_on_err = 1;
4294  int sync_fd = -1;
4295 
4296  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
4297  if (!drm_desc)
4298  return AVERROR(ENOMEM);
4299 
4301  if (err < 0)
4302  goto end;
4303 
4304 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4305  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
4306  f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
4307  vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
4308  err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
4309  if (err < 0)
4310  goto end;
4311  sync_fd = err;
4312  err = 0;
4313  }
4314 #endif
4315 
4316  if (sync_fd < 0) {
4317  VkSemaphoreWaitInfo wait_info = {
4318  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4319  .flags = 0x0,
4320  .semaphoreCount = nb_sems,
4321  .pSemaphores = f->sem,
4322  .pValues = f->sem_value,
4323  };
4324  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
4325  }
4326 
4327  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
4328  if (err < 0)
4329  goto end;
4330 
4331  /* It will be freed in ff_hwframe_map_create callback */
4332  free_drm_desc_on_err = 0;
4333 
4334  ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
4335  &drm_mod);
4336  if (ret != VK_SUCCESS) {
4337  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
4338  err = AVERROR_EXTERNAL;
4339  goto end;
4340  }
4341 
4342  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
4343  VkMemoryGetFdInfoKHR export_info = {
4344  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
4345  .memory = f->mem[i],
4346  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
4347  };
4348 
4349  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
4350  &drm_desc->objects[i].fd);
4351  if (ret != VK_SUCCESS) {
4352  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
4353  err = AVERROR_EXTERNAL;
4354  goto end;
4355  }
4356 
4357 #if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
4358  if (sync_fd >= 0) {
4359  int dup_fd = dup(sync_fd);
4360  if (dup_fd >= 0) {
4361  struct dma_buf_import_sync_file import_info = {
4362  .flags = DMA_BUF_SYNC_WRITE,
4363  .fd = dup_fd,
4364  };
4365  if (ioctl(drm_desc->objects[i].fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_info) < 0)
4366  av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s\n", av_err2str(AVERROR(errno)));
4367  close(dup_fd);
4368  } else {
4369  av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
4370  }
4371  }
4372 #endif
4373 
4374  drm_desc->nb_objects++;
4375  drm_desc->objects[i].size = f->size[i];
4376  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
4377  }
4378 
4379  /* NV12 has 2 planes but 1 image/semaphore */
4380  drm_desc->nb_layers = FFMAX(planes, nb_images);
4381  for (int i = 0; i < drm_desc->nb_layers; i++) {
4382  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
4383 
4384  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
4385  drm_desc->layers[i].nb_planes = fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount;
4386 
4387  if (drm_desc->layers[i].nb_planes > MAX_MEMORY_PLANES) {
4388  av_log(hwfc, AV_LOG_ERROR, "Too many memory planes for DRM format!\n");
4389  err = AVERROR_EXTERNAL;
4390  goto end;
4391  }
4392 
4393  for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
4394  VkSubresourceLayout layout;
4395  int aspect_plane = (nb_images == 1) ? i : j;
4396  VkImageSubresource sub = {
4397  .aspectMask = plane_index_to_aspect(aspect_plane),
4398  };
4399 
4400  drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
4401 
4402  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[FFMIN(i, nb_images - 1)], &sub, &layout);
4403  drm_desc->layers[i].planes[j].offset = layout.offset;
4404  drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
4405  }
4406 
4407  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
4408  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
4409  err = AVERROR_PATCHWELCOME;
4410  goto end;
4411  }
4412 
4413 
4414  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
4415  continue;
4416 
4417  }
4418 
4419  dst->width = src->width;
4420  dst->height = src->height;
4421  dst->data[0] = (uint8_t *)drm_desc;
4422  dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
4423 
4424  if (sync_fd >= 0)
4425  close(sync_fd);
4426 
4427  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
4428 
4429  return 0;
4430 
4431 end:
4432  for (int i = 0; i < drm_desc->nb_objects; i++)
4433  close(drm_desc->objects[i].fd);
4434  if (free_drm_desc_on_err)
4435  av_free(drm_desc);
4436  if (sync_fd >= 0)
4437  close(sync_fd);
4438  return err;
4439 }
4440 
4441 #if CONFIG_VAAPI
4442 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
4443  const AVFrame *src, int flags)
4444 {
4445  int err;
4446  AVFrame *tmp = av_frame_alloc();
4447  if (!tmp)
4448  return AVERROR(ENOMEM);
4449 
4450  tmp->format = AV_PIX_FMT_DRM_PRIME;
4451 
4452  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
4453  if (err < 0)
4454  goto fail;
4455 
4456  err = av_hwframe_map(dst, tmp, flags);
4457  if (err < 0)
4458  goto fail;
4459 
4460  err = ff_hwframe_map_replace(dst, src);
4461 
4462 fail:
4463  av_frame_free(&tmp);
4464  return err;
4465 }
4466 #endif
4467 #endif
4468 
4470  const AVFrame *src, int flags)
4471 {
4473 
4474  switch (dst->format) {
4475 #if CONFIG_LIBDRM
4476  case AV_PIX_FMT_DRM_PRIME:
4477  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4478  return vulkan_map_to_drm(hwfc, dst, src, flags);
4479  else
4480  return AVERROR(ENOSYS);
4481 #if CONFIG_VAAPI
4482  case AV_PIX_FMT_VAAPI:
4483  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4484  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
4485  else
4486  return AVERROR(ENOSYS);
4487 #endif
4488 #endif
4489  default:
4490  break;
4491  }
4492  return AVERROR(ENOSYS);
4493 }
4494 
4496  AVFrame *swf, VkBufferImageCopy *region,
4497  int planes, int upload)
4498 {
4499  int err;
4500  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4501  FFVkBuffer *vkbuf = (FFVkBuffer *)buf->data;
4502 
4503  if (upload) {
4504  for (int i = 0; i < planes; i++)
4505  av_image_copy_plane(vkbuf->mapped_mem + region[i].bufferOffset,
4506  region[i].bufferRowLength,
4507  swf->data[i],
4508  swf->linesize[i],
4509  swf->linesize[i],
4510  region[i].imageExtent.height);
4511 
4512  err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 1);
4513  if (err != VK_SUCCESS) {
4514  av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n",
4515  av_err2str(err));
4516  return AVERROR_EXTERNAL;
4517  }
4518  } else {
4519  err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 0);
4520  if (err != VK_SUCCESS) {
4521  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n",
4522  av_err2str(err));
4523  return AVERROR_EXTERNAL;
4524  }
4525 
4526  for (int i = 0; i < planes; i++)
4527  av_image_copy_plane(swf->data[i],
4528  swf->linesize[i],
4529  vkbuf->mapped_mem + region[i].bufferOffset,
4530  region[i].bufferRowLength,
4531  swf->linesize[i],
4532  region[i].imageExtent.height);
4533  }
4534 
4535  return 0;
4536 }
4537 
4539  AVFrame *swf, VkBufferImageCopy *region, int upload)
4540 {
4541  int err;
4542  uint32_t p_w, p_h;
4543  VulkanFramesPriv *fp = hwfc->hwctx;
4544  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4545  const int planes = av_pix_fmt_count_planes(swf->format);
4546  VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4547  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4548 
4549  size_t buf_offset = 0;
4550  for (int i = 0; i < planes; i++) {
4551  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4552 
4553  region[i] = (VkBufferImageCopy) {
4554  .bufferOffset = buf_offset,
4555  .bufferRowLength = FFALIGN(swf->linesize[i],
4556  p->props.properties.limits.optimalBufferCopyRowPitchAlignment),
4557  .bufferImageHeight = p_h,
4558  .imageSubresource.layerCount = 1,
4559  .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4560  /* Rest of the fields adjusted/filled in later */
4561  };
4562 
4563  buf_offset += FFALIGN(p_h*region[i].bufferRowLength,
4564  p->props.properties.limits.optimalBufferCopyOffsetAlignment);
4565  }
4566 
4567  err = ff_vk_get_pooled_buffer(&p->vkctx, &fp->tmp, dst, buf_usage,
4568  NULL, buf_offset,
4569  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
4570  p->vkctx.host_cached_flag);
4571  if (err < 0)
4572  return err;
4573 
4574  return 0;
4575 }
4576 
4577 static int host_map_frame(AVHWFramesContext *hwfc, AVBufferRef **dst, int *nb_bufs,
4578  AVFrame *swf, VkBufferImageCopy *region, int upload)
4579 {
4580  int err;
4581  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4582 
4583  int nb_src_bufs;
4584  const int planes = av_pix_fmt_count_planes(swf->format);
4585  VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4586  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4587 
4588  /* We can't host map images with negative strides */
4589  for (int i = 0; i < planes; i++)
4590  if (swf->linesize[i] < 0)
4591  return AVERROR(EINVAL);
4592 
4593  /* Count the number of buffers in the software frame */
4594  nb_src_bufs = 0;
4595  while (swf->buf[nb_src_bufs])
4596  nb_src_bufs++;
4597 
4598  /* Single buffer contains all planes */
4599  if (nb_src_bufs == 1) {
4600  err = ff_vk_host_map_buffer(&p->vkctx, &dst[0],
4601  swf->data[0], swf->buf[0],
4602  buf_usage);
4603  if (err < 0)
4604  return err;
4605  (*nb_bufs)++;
4606 
4607  for (int i = 0; i < planes; i++)
4608  region[i].bufferOffset = ((FFVkBuffer *)dst[0]->data)->virtual_offset +
4609  swf->data[i] - swf->data[0];
4610  } else if (nb_src_bufs == planes) { /* One buffer per plane */
4611  for (int i = 0; i < planes; i++) {
4612  err = ff_vk_host_map_buffer(&p->vkctx, &dst[i],
4613  swf->data[i], swf->buf[i],
4614  buf_usage);
4615  if (err < 0)
4616  goto fail;
4617  (*nb_bufs)++;
4618 
4619  region[i].bufferOffset = ((FFVkBuffer *)dst[i]->data)->virtual_offset;
4620  }
4621  } else {
4622  /* Weird layout (3 planes, 2 buffers), patch welcome, fallback to copy */
4623  return AVERROR_PATCHWELCOME;
4624  }
4625 
4626  return 0;
4627 
4628 fail:
4629  for (int i = 0; i < (*nb_bufs); i++)
4630  av_buffer_unref(&dst[i]);
4631  return err;
4632 }
4633 
4635  AVFrame *swf, int upload)
4636 {
4637  VulkanFramesPriv *fp = hwfc->hwctx;
4638  AVVulkanFramesContext *hwfc_vk = &fp->p;
4639  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4640  AVVulkanDeviceContext *hwctx = &p->p;
4641  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4642 
4643  AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4645  const int planes = av_pix_fmt_count_planes(swf->format);
4646  const int nb_images = ff_vk_count_images(hwf_vk);
4647 
4648  VkSemaphoreWaitInfo sem_wait;
4649  VkHostImageLayoutTransitionInfoEXT layout_ch_info[AV_NUM_DATA_POINTERS];
4650  int nb_layout_ch = 0;
4651 
4652  hwfc_vk->lock_frame(hwfc, hwf_vk);
4653 
4654  for (int i = 0; i < nb_images; i++) {
4655  int compat = 0;
4656  for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount; j++) {
4657  if (hwf_vk->layout[i] == p->vkctx.host_image_props.pCopySrcLayouts[j]) {
4658  compat = 1;
4659  break;
4660  }
4661  }
4662  if (compat)
4663  continue;
4664 
4665  layout_ch_info[nb_layout_ch] = (VkHostImageLayoutTransitionInfoEXT) {
4666  .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
4667  .image = hwf_vk->img[i],
4668  .oldLayout = hwf_vk->layout[i],
4669  .newLayout = VK_IMAGE_LAYOUT_GENERAL,
4670  .subresourceRange = {
4671  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4672  .levelCount = 1,
4673  .layerCount = 1,
4674  },
4675  };
4676 
4677  hwf_vk->layout[i] = layout_ch_info[nb_layout_ch].newLayout;
4678  nb_layout_ch++;
4679  }
4680 
4681  sem_wait = (VkSemaphoreWaitInfo) {
4682  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4683  .pSemaphores = hwf_vk->sem,
4684  .pValues = hwf_vk->sem_value,
4685  .semaphoreCount = nb_images,
4686  };
4687 
4688  vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
4689 
4690  if (nb_layout_ch)
4691  vk->TransitionImageLayoutEXT(hwctx->act_dev,
4692  nb_layout_ch, layout_ch_info);
4693 
4694  if (upload) {
4695  VkMemoryToImageCopyEXT region_info = {
4696  .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
4697  .imageSubresource = {
4698  .layerCount = 1,
4699  },
4700  };
4701  VkCopyMemoryToImageInfoEXT copy_info = {
4702  .sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
4703  .regionCount = 1,
4704  .pRegions = &region_info,
4705  };
4706  for (int i = 0; i < planes; i++) {
4707  int img_idx = FFMIN(i, (nb_images - 1));
4708  uint32_t p_w, p_h;
4709  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4710 
4711  region_info.pHostPointer = swf->data[i];
4712  region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4713  region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4714  region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4715  copy_info.dstImage = hwf_vk->img[img_idx];
4716  copy_info.dstImageLayout = hwf_vk->layout[img_idx];
4717 
4718  vk->CopyMemoryToImageEXT(hwctx->act_dev, &copy_info);
4719  }
4720  } else {
4721  VkImageToMemoryCopyEXT region_info = {
4722  .sType = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT,
4723  .imageSubresource = {
4724  .layerCount = 1,
4725  },
4726  };
4727  VkCopyImageToMemoryInfoEXT copy_info = {
4728  .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
4729  .regionCount = 1,
4730  .pRegions = &region_info,
4731  };
4732  for (int i = 0; i < planes; i++) {
4733  int img_idx = FFMIN(i, (nb_images - 1));
4734  uint32_t p_w, p_h;
4735  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4736 
4737  region_info.pHostPointer = swf->data[i];
4738  region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4739  region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4740  region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4741  copy_info.srcImage = hwf_vk->img[img_idx];
4742  copy_info.srcImageLayout = hwf_vk->layout[img_idx];
4743 
4744  vk->CopyImageToMemoryEXT(hwctx->act_dev, &copy_info);
4745  }
4746  }
4747 
4748  hwfc_vk->unlock_frame(hwfc, hwf_vk);
4749 
4750  return 0;
4751 }
4752 
4754  AVFrame *swf, AVFrame *hwf,
4755  int upload)
4756 {
4757  int err;
4758  VulkanFramesPriv *fp = hwfc->hwctx;
4759  AVVulkanFramesContext *hwctx = &fp->p;
4760  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4761  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4762 
4763  int host_mapped = 0;
4764 
4765  AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4766  VkBufferImageCopy region[AV_NUM_DATA_POINTERS]; // always one per plane
4767 
4768  const int planes = av_pix_fmt_count_planes(swf->format);
4770  const int nb_images = ff_vk_count_images(hwf_vk);
4771 
4772  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
4773  int nb_img_bar = 0;
4774 
4776  int nb_bufs = 0;
4777 
4778  VkCommandBuffer cmd_buf;
4779  FFVkExecContext *exec;
4780 
4781  /* Sanity checking */
4782  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
4783  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
4784  return AVERROR(EINVAL);
4785  }
4786 
4787  if (swf->width > hwfc->width || swf->height > hwfc->height)
4788  return AVERROR(EINVAL);
4789 
4790  if (hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
4791  !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY))
4792  return vulkan_transfer_host(hwfc, hwf, swf, upload);
4793 
4794  for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
4795  uint32_t p_w, p_h;
4796  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4797 
4798  /* Buffer region for this plane */
4799  region[i] = (VkBufferImageCopy) {
4800  .bufferOffset = 0,
4801  .bufferRowLength = swf->linesize[i],
4802  .bufferImageHeight = p_h,
4803  .imageSubresource.layerCount = 1,
4804  .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4805  /* Rest of the fields adjusted/filled in later */
4806  };
4807  }
4808 
4809  /* Setup buffers first */
4810  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY && !p->avoid_host_import) {
4811  err = host_map_frame(hwfc, bufs, &nb_bufs, swf, region, upload);
4812  if (err >= 0)
4813  host_mapped = 1;
4814  }
4815 
4816  if (!host_mapped) {
4817  err = get_plane_buf(hwfc, &bufs[0], swf, region, upload);
4818  if (err < 0)
4819  goto end;
4820  nb_bufs = 1;
4821 
4822  if (upload) {
4823  err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 1);
4824  if (err < 0)
4825  goto end;
4826  }
4827  }
4828 
4829  exec = ff_vk_exec_get(&p->vkctx, &fp->upload_exec);
4830  cmd_buf = exec->buf;
4831 
4832  ff_vk_exec_start(&p->vkctx, exec);
4833 
4834  /* Prep destination Vulkan frame */
4835  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, hwf,
4836  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4837  VK_PIPELINE_STAGE_2_TRANSFER_BIT);
4838  if (err < 0)
4839  goto end;
4840 
4841  /* No need to declare buf deps for synchronous transfers (downloads) */
4842  if (upload) {
4843  /* Add the software frame backing the buffers if we're host mapping */
4844  if (host_mapped) {
4845  err = ff_vk_exec_add_dep_sw_frame(&p->vkctx, exec, swf);
4846  if (err < 0) {
4847  ff_vk_exec_discard_deps(&p->vkctx, exec);
4848  goto end;
4849  }
4850  }
4851 
4852  /* Add the buffers as a dependency */
4853  err = ff_vk_exec_add_dep_buf(&p->vkctx, exec, bufs, nb_bufs, 1);
4854  if (err < 0) {
4855  ff_vk_exec_discard_deps(&p->vkctx, exec);
4856  goto end;
4857  }
4858  }
4859 
4860  ff_vk_frame_barrier(&p->vkctx, exec, hwf, img_bar, &nb_img_bar,
4861  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4862  VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
4863  upload ? VK_ACCESS_TRANSFER_WRITE_BIT :
4864  VK_ACCESS_TRANSFER_READ_BIT,
4865  upload ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL :
4866  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4867  p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
4868 
4869  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
4870  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
4871  .pImageMemoryBarriers = img_bar,
4872  .imageMemoryBarrierCount = nb_img_bar,
4873  });
4874 
4875  for (int i = 0; i < planes; i++) {
4876  int buf_idx = FFMIN(i, (nb_bufs - 1));
4877  int img_idx = FFMIN(i, (nb_images - 1));
4878  FFVkBuffer *vkbuf = (FFVkBuffer *)bufs[buf_idx]->data;
4879 
4880  uint32_t orig_stride = region[i].bufferRowLength;
4881  region[i].bufferRowLength /= desc->comp[i].step;
4882  region[i].imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4883 
4884  if (upload)
4885  vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf,
4886  hwf_vk->img[img_idx],
4887  img_bar[img_idx].newLayout,
4888  1, &region[i]);
4889  else
4890  vk->CmdCopyImageToBuffer(cmd_buf, hwf_vk->img[img_idx],
4891  img_bar[img_idx].newLayout,
4892  vkbuf->buf,
4893  1, &region[i]);
4894 
4895  region[i].bufferRowLength = orig_stride;
4896  }
4897 
4898  err = ff_vk_exec_submit(&p->vkctx, exec);
4899  if (err < 0) {
4900  ff_vk_exec_discard_deps(&p->vkctx, exec);
4901  } else if (!upload) {
4902  ff_vk_exec_wait(&p->vkctx, exec);
4903  if (!host_mapped)
4904  err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 0);
4905  }
4906 
4907 end:
4908  for (int i = 0; i < nb_bufs; i++)
4909  av_buffer_unref(&bufs[i]);
4910 
4911  return err;
4912 }
4913 
4915  const AVFrame *src)
4916 {
4918 
4919  switch (src->format) {
4920 #if CONFIG_CUDA
4921  case AV_PIX_FMT_CUDA:
4922 #ifdef _WIN32
4923  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4924  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4925 #else
4926  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4927  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4928 #endif
4929  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
4931 #endif
4932  default:
4933  if (src->hw_frames_ctx)
4934  return AVERROR(ENOSYS);
4935  else
4936  return vulkan_transfer_frame(hwfc, (AVFrame *)src, dst, 1);
4937  }
4938 }
4939 
4940 #if CONFIG_CUDA
4941 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
4942  const AVFrame *src)
4943 {
4944  int err;
4945  CUcontext dummy;
4946  AVVkFrame *dst_f;
4947  AVVkFrameInternal *dst_int;
4948  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4949  VulkanFramesPriv *fp = hwfc->hwctx;
4950  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4952  int nb_images;
4953 
4954  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)dst->hw_frames_ctx->data;
4955  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4956  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4957  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4958  CudaFunctions *cu = cu_internal->cuda_dl;
4959  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4960  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4961 
4962  dst_f = (AVVkFrame *)src->data[0];
4963  nb_images = ff_vk_count_images(dst_f);
4964 
4965  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4966  if (err < 0)
4967  return err;
4968 
4969  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4970  if (err < 0)
4971  return err;
4972 
4973  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
4974  if (err < 0) {
4975  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4976  return err;
4977  }
4978 
4979  dst_int = dst_f->internal;
4980 
4981  for (int i = 0; i < planes; i++) {
4982  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4983  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4984  }
4985 
4986  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4987  nb_images, cuda_dev->stream));
4988  if (err < 0)
4989  goto fail;
4990 
4991  for (int i = 0; i < planes; i++) {
4992  CUDA_MEMCPY2D cpy = {
4993  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
4994  .dstDevice = (CUdeviceptr)dst->data[i],
4995  .dstPitch = dst->linesize[i],
4996  .dstY = 0,
4997 
4998  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
4999  .srcArray = dst_int->cu_array[i],
5000  };
5001 
5002  int w, h;
5003  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
5004 
5005  cpy.WidthInBytes = w * desc->comp[i].step;
5006  cpy.Height = h;
5007 
5008  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
5009  if (err < 0)
5010  goto fail;
5011  }
5012 
5013  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
5014  nb_images, cuda_dev->stream));
5015  if (err < 0)
5016  goto fail;
5017 
5018  for (int i = 0; i < planes; i++)
5019  dst_f->sem_value[i]++;
5020 
5021  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
5022 
5023  av_log(hwfc, AV_LOG_VERBOSE, "Transferred Vulkan image to CUDA!\n");
5024 
5025  return prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
5026 
5027 fail:
5028  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
5029  vulkan_free_internal(p, dst_f);
5030  av_buffer_unref(&dst->buf[0]);
5031  return err;
5032 }
5033 #endif
5034 
5036  const AVFrame *src)
5037 {
5039 
5040  switch (dst->format) {
5041 #if CONFIG_CUDA
5042  case AV_PIX_FMT_CUDA:
5043 #ifdef _WIN32
5044  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
5045  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
5046 #else
5047  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
5048  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
5049 #endif
5050  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
5052 #endif
5053  default:
5054  if (dst->hw_frames_ctx)
5055  return AVERROR(ENOSYS);
5056  else
5057  return vulkan_transfer_frame(hwfc, dst, (AVFrame *)src, 0);
5058  }
5059 }
5060 
5062  AVHWFramesContext *src_fc, int flags)
5063 {
5064  return vulkan_frames_init(dst_fc);
5065 }
5066 
5068 {
5069  int err;
5070  AVVkFrame *f = av_mallocz(sizeof(AVVkFrame));
5071  if (!f)
5072  return NULL;
5073 
5074  f->internal = av_mallocz(sizeof(*f->internal));
5075  if (!f->internal) {
5076  av_free(f);
5077  return NULL;
5078  }
5079 
5080  err = pthread_mutex_init(&f->internal->update_mutex, NULL);
5081  if (err != 0) {
5082  av_free(f->internal);
5083  av_free(f);
5084  return NULL;
5085  }
5086 
5087  return f;
5088 }
5089 
5092  .name = "Vulkan",
5093 
5094  .device_hwctx_size = sizeof(VulkanDevicePriv),
5095  .frames_hwctx_size = sizeof(VulkanFramesPriv),
5096 
5097  .device_init = &vulkan_device_init,
5098  .device_uninit = &vulkan_device_uninit,
5099  .device_create = &vulkan_device_create,
5100  .device_derive = &vulkan_device_derive,
5101 
5102  .frames_get_constraints = &vulkan_frames_get_constraints,
5103  .frames_init = vulkan_frames_init,
5104  .frames_get_buffer = vulkan_get_buffer,
5105  .frames_uninit = vulkan_frames_uninit,
5106 
5107  .transfer_get_formats = vulkan_transfer_get_formats,
5108  .transfer_data_to = vulkan_transfer_data_to,
5109  .transfer_data_from = vulkan_transfer_data_from,
5110 
5111  .map_to = vulkan_map_to,
5112  .map_from = vulkan_map_from,
5113  .frames_derive_to = &vulkan_frames_derive_to,
5114 
5115  .pix_fmts = (const enum AVPixelFormat []) {
5118  },
5119 };
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:1940
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:73
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:4577
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:217
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
SET_OLD_QF
#define SET_OLD_QF(field, nb_field, type)
vulkan_transfer_data_to
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_vulkan.c:4914
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
CHECK_QUEUE
#define CHECK_QUEUE(type, required, fidx, ctx_qf, qc)
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:2305
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:5061
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:2749
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:254
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
AVVulkanDeviceContext::queue_family_encode_index
attribute_deprecated int queue_family_encode_index
Queue family index for video encode ops, and the amount of queues enabled.
Definition: hwcontext_vulkan.h:156
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:299
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:2573
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:4469
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:189
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:2351
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:2569
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:2202
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:318
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:181
lock_frame
static void lock_frame(AVHWFramesContext *fc, AVVkFrame *vkf)
Definition: hwcontext_vulkan.c:3010
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:270
VulkanDevicePriv
Definition: hwcontext_vulkan.c:126
AVVulkanDeviceContext::nb_tx_queues
attribute_deprecated int nb_tx_queues
Definition: hwcontext_vulkan.h:139
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:331
switch_layout
static int switch_layout(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
Definition: hwcontext_vulkan.c:2608
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:223
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:1926
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
AVVulkanDeviceContext::queue_family_decode_index
attribute_deprecated int queue_family_decode_index
Queue family index for video decode ops, and the amount of queues enabled.
Definition: hwcontext_vulkan.h:166
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
planes
static const struct @594 planes[]
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
AVVulkanDeviceContext::nb_encode_queues
attribute_deprecated int nb_encode_queues
Definition: hwcontext_vulkan.h:158
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:4147
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
s
#define s(width, name)
Definition: cbs_vp9.c:198
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
AV_DRM_MAX_PLANES
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
Definition: hwcontext_drm.h:39
prepare_frame
static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
Definition: hwcontext_vulkan.c:2716
vulkan_transfer_frame
static int vulkan_transfer_frame(AVHWFramesContext *hwfc, AVFrame *swf, AVFrame *hwf, int upload)
Definition: hwcontext_vulkan.c:4753
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:1804
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:304
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:276
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:3020
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_HWFRAME_MAP_READ
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition: hwcontext.h:515
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:3283
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:2483
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:2565
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:263
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:2409
AVVulkanDeviceContext::nb_decode_queues
attribute_deprecated int nb_decode_queues
Definition: hwcontext_vulkan.h:168
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:201
ff_hwcontext_type_vulkan
const HWContextType ff_hwcontext_type_vulkan
Definition: hwcontext_vulkan.c:5090
hwcontext_vulkan.h
AVVulkanDeviceContext::queue_family_tx_index
attribute_deprecated int queue_family_tx_index
Queue family index for transfer operations and the number of queues enabled.
Definition: hwcontext_vulkan.h:137
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:284
AVVulkanFramesContext::usage
VkImageUsageFlagBits usage
Defines extra usage of output frames.
Definition: hwcontext_vulkan.h:243
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:2488
FFVkBuffer::mapped_mem
uint8_t * mapped_mem
Definition: vulkan.h:134
AVVulkanDeviceContext::qf
AVVulkanDeviceQueueFamily qf[64]
Queue families used.
Definition: hwcontext_vulkan.h:200
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:2449
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:2568
AVVkFrame::size
size_t size[AV_NUM_DATA_POINTERS]
Definition: hwcontext_vulkan.h:332
vulkan_pool_alloc
static AVBufferRef * vulkan_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_vulkan.c:2931
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:2563
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:313
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:5067
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:1781
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:5035
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
VulkanDeviceSelection::vendor_id
uint32_t vendor_id
Definition: hwcontext_vulkan.c:1333
PREP_MODE_GENERAL
@ PREP_MODE_GENERAL
Definition: hwcontext_vulkan.c:2564
AV_PIX_FMT_Y212
#define AV_PIX_FMT_Y212
Definition: pixfmt.h:607
AVVulkanDeviceContext::queue_family_index
attribute_deprecated int queue_family_index
Queue family index for graphics operations, and the number of queues enabled for it.
Definition: hwcontext_vulkan.h:128
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
AVVulkanDeviceContext::queue_family_comp_index
attribute_deprecated int queue_family_comp_index
Queue family index for compute operations and the number of queues enabled.
Definition: hwcontext_vulkan.h:146
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
vulkan_frames_init
static int vulkan_frames_init(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:3038
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
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:351
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:3269
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:4634
unlock_queue
static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
Definition: hwcontext_vulkan.c:1933
AVHWFramesConstraints::max_height
int max_height
Definition: hwcontext.h:470
AVVkFrame::internal
struct AVVkFrameInternal * internal
Internal data.
Definition: hwcontext_vulkan.h:364
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:2186
AVFrame::height
int height
Definition: frame.h:538
PREP_MODE_ENCODING_DPB
@ PREP_MODE_ENCODING_DPB
Definition: hwcontext_vulkan.c:2570
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:2671
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
AVVulkanDeviceContext::nb_graphics_queues
attribute_deprecated int nb_graphics_queues
Definition: hwcontext_vulkan.h:130
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
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:2567
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:232
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:4538
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:3015
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
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:359
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:289
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:343
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
AV_HWFRAME_MAP_WRITE
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition: hwcontext.h:519
ADD_QUEUE
#define ADD_QUEUE(ctx_qf, qc, flag)
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:2732
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:2566
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:4495
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:204
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
AVVulkanDeviceContext::nb_comp_queues
attribute_deprecated int nb_comp_queues
Definition: hwcontext_vulkan.h:148
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:1819
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:2859