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