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  // Make this function safe to call repeatedly
2313  if (!internal)
2314  return;
2315 
2316 #if CONFIG_CUDA
2317  if (internal->cuda_fc_ref) {
2318  AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
2319  int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
2320  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2321  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2322  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2323  CudaFunctions *cu = cu_internal->cuda_dl;
2324 
2325  for (int i = 0; i < planes; i++) {
2326  if (internal->cu_sem[i])
2327  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
2328  if (internal->cu_mma[i])
2329  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
2330  if (internal->ext_mem[i])
2331  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
2332 #ifdef _WIN32
2333  if (internal->ext_sem_handle[i])
2334  CloseHandle(internal->ext_sem_handle[i]);
2335  if (internal->ext_mem_handle[i])
2336  CloseHandle(internal->ext_mem_handle[i]);
2337 #endif
2338  }
2339 
2340  av_buffer_unref(&internal->cuda_fc_ref);
2341  }
2342 #endif
2343 
2344  if (internal->drm_sync_sem != VK_NULL_HANDLE)
2345  p->vkctx.vkfn.DestroySemaphore(p->p.act_dev, internal->drm_sync_sem,
2346  p->p.alloc);
2347 
2348  pthread_mutex_destroy(&internal->update_mutex);
2349  av_freep(&f->internal);
2350 }
2351 
2353 {
2354  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2355  AVVulkanDeviceContext *hwctx = &p->p;
2356  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2357  int nb_images = ff_vk_count_images(f);
2358  int nb_sems = 0;
2359 
2360  while (nb_sems < FF_ARRAY_ELEMS(f->sem) && f->sem[nb_sems])
2361  nb_sems++;
2362 
2363  if (nb_sems) {
2364  VkSemaphoreWaitInfo sem_wait = {
2365  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
2366  .flags = 0x0,
2367  .pSemaphores = f->sem,
2368  .pValues = f->sem_value,
2369  .semaphoreCount = nb_sems,
2370  };
2371 
2372  vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
2373  }
2374 
2376 
2377  for (int i = 0; i < nb_images; i++) {
2378  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2379  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2380  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2381  }
2382 
2383  av_free(f);
2384 }
2385 
2386 static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
2387 {
2388  vulkan_frame_free(opaque, (AVVkFrame*)data);
2389 }
2390 
2392  void *alloc_pnext, size_t alloc_pnext_stride)
2393 {
2394  int img_cnt = 0, err;
2395  VkResult ret;
2396  AVHWDeviceContext *ctx = hwfc->device_ctx;
2397  VulkanDevicePriv *p = ctx->hwctx;
2398  AVVulkanDeviceContext *hwctx = &p->p;
2399  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2400  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
2401 
2402  while (f->img[img_cnt]) {
2403  int use_ded_mem;
2404  VkImageMemoryRequirementsInfo2 req_desc = {
2405  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2406  .image = f->img[img_cnt],
2407  };
2408  VkMemoryDedicatedAllocateInfo ded_alloc = {
2409  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2410  .pNext = (void *)(((uint8_t *)alloc_pnext) + img_cnt*alloc_pnext_stride),
2411  };
2412  VkMemoryDedicatedRequirements ded_req = {
2413  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2414  };
2415  VkMemoryRequirements2 req = {
2416  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2417  .pNext = &ded_req,
2418  };
2419 
2420  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
2421 
2422  av_log(hwfc, AV_LOG_TRACE,
2423  "plane %d: driver reports prefersDedicatedAllocation=%i requiresDedicatedAllocation=%i\n",
2424  img_cnt, ded_req.prefersDedicatedAllocation, ded_req.requiresDedicatedAllocation);
2425 
2426  if (f->tiling == VK_IMAGE_TILING_LINEAR)
2427  req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
2428  p->props.properties.limits.minMemoryMapAlignment);
2429 
2430  /* In case the implementation prefers/requires dedicated allocation */
2431  use_ded_mem = ded_req.prefersDedicatedAllocation |
2432  ded_req.requiresDedicatedAllocation;
2433  if (((VulkanFramesPriv *)hwfc->hwctx)->export_requires_dedicated)
2434  use_ded_mem = 1;
2435  if (use_ded_mem)
2436  ded_alloc.image = f->img[img_cnt];
2437 
2438  /* Allocate memory */
2439  if ((err = alloc_mem(ctx, &req.memoryRequirements,
2440  f->tiling == VK_IMAGE_TILING_LINEAR ?
2441  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
2442  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2443  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
2444  &f->flags, &f->mem[img_cnt])))
2445  return err;
2446 
2447  f->size[img_cnt] = req.memoryRequirements.size;
2448  bind_info[img_cnt].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2449  bind_info[img_cnt].image = f->img[img_cnt];
2450  bind_info[img_cnt].memory = f->mem[img_cnt];
2451 
2452  img_cnt++;
2453  }
2454 
2455  /* Bind the allocated memory to the images */
2456  ret = vk->BindImageMemory2(hwctx->act_dev, img_cnt, bind_info);
2457  if (ret != VK_SUCCESS) {
2458  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2459  ff_vk_ret2str(ret));
2460  return AVERROR_EXTERNAL;
2461  }
2462 
2463  return 0;
2464 }
2465 
2466 enum PrepMode {
2474 };
2475 
2476 static void switch_new_props(enum PrepMode pmode, VkImageLayout *new_layout,
2477  VkAccessFlags2 *new_access)
2478 {
2479  switch (pmode) {
2480  case PREP_MODE_GENERAL:
2481  *new_layout = VK_IMAGE_LAYOUT_GENERAL;
2482  *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2483  break;
2484  case PREP_MODE_WRITE:
2485  *new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2486  *new_access = VK_ACCESS_TRANSFER_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_GENERAL;
2494  *new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
2495  break;
2497  *new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR;
2498  *new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
2499  break;
2501  *new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
2502  *new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
2503  break;
2505  *new_layout = VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR;
2506  *new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
2507  break;
2508  }
2509 }
2510 
2512  AVVkFrame *frame, enum PrepMode pmode)
2513 {
2514  int err;
2515  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2516  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2517  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
2518  int nb_img_bar = 0;
2519 
2520  VkImageLayout new_layout;
2521  VkAccessFlags2 new_access;
2522  switch_new_props(pmode, &new_layout, &new_access);
2523 
2524  uint32_t dst_qf = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2525  VkPipelineStageFlagBits2 src_stage = VK_PIPELINE_STAGE_2_NONE;
2526  if (pmode == PREP_MODE_EXTERNAL_EXPORT) {
2527  dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
2528  src_stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
2529  }
2530 
2531  /* This is dirty - but it works. The vulkan.c dependency system doesn't
2532  * free non-refcounted frames, and non-refcounted hardware frames cannot
2533  * happen anywhere outside of here. */
2534  AVBufferRef tmp_ref = {
2535  .data = (uint8_t *)hwfc,
2536  };
2537  AVFrame tmp_frame = {
2538  .data[0] = (uint8_t *)frame,
2539  .hw_frames_ctx = &tmp_ref,
2540  };
2541 
2542  VkCommandBuffer cmd_buf;
2543  FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, ectx);
2544  cmd_buf = exec->buf;
2545  ff_vk_exec_start(&p->vkctx, exec);
2546 
2547  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, &tmp_frame,
2548  VK_PIPELINE_STAGE_2_NONE,
2549  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
2550  if (err < 0)
2551  return err;
2552 
2553  ff_vk_frame_barrier(&p->vkctx, exec, &tmp_frame, img_bar, &nb_img_bar,
2554  src_stage,
2555  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
2556  new_access, new_layout, dst_qf);
2557 
2558  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
2559  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
2560  .pImageMemoryBarriers = img_bar,
2561  .imageMemoryBarrierCount = nb_img_bar,
2562  });
2563 
2564  err = ff_vk_exec_submit(&p->vkctx, exec);
2565  if (err < 0)
2566  return err;
2567 
2568  /* We can do this because there are no real dependencies */
2569  ff_vk_exec_discard_deps(&p->vkctx, exec);
2570 
2571  return 0;
2572 }
2573 
2575  AVVkFrame *frame, enum PrepMode pmode)
2576 {
2577  VkResult ret;
2578  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2579  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2580  VkHostImageLayoutTransitionInfoEXT layout_change[AV_NUM_DATA_POINTERS];
2581  int nb_images = ff_vk_count_images(frame);
2582 
2583  VkImageLayout new_layout;
2584  VkAccessFlags2 new_access;
2585  switch_new_props(pmode, &new_layout, &new_access);
2586 
2587  int i;
2588  for (i = 0; i < p->vkctx.host_image_props.copyDstLayoutCount; i++) {
2589  if (p->vkctx.host_image_props.pCopyDstLayouts[i] == new_layout)
2590  break;
2591  }
2592  if (i == p->vkctx.host_image_props.copyDstLayoutCount)
2593  return AVERROR(ENOTSUP);
2594 
2595  for (i = 0; i < nb_images; i++) {
2596  layout_change[i] = (VkHostImageLayoutTransitionInfoEXT) {
2597  .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
2598  .image = frame->img[i],
2599  .oldLayout = frame->layout[i],
2600  .newLayout = new_layout,
2601  .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2602  .subresourceRange.layerCount = 1,
2603  .subresourceRange.levelCount = 1,
2604  };
2605  frame->layout[i] = new_layout;
2606  }
2607 
2608  ret = vk->TransitionImageLayoutEXT(p->vkctx.hwctx->act_dev,
2609  nb_images, layout_change);
2610  if (ret != VK_SUCCESS) {
2611  av_log(hwfc, AV_LOG_ERROR, "Unable to prepare frame: %s\n",
2612  ff_vk_ret2str(ret));
2613  return AVERROR_EXTERNAL;
2614  }
2615 
2616  return 0;
2617 }
2618 
2620  AVVkFrame *frame, enum PrepMode pmode)
2621 {
2622  int err = 0;
2623  AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
2624  if (hwfc_vk->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
2625  (pmode != PREP_MODE_EXTERNAL_EXPORT) &&
2626  (pmode != PREP_MODE_EXTERNAL_IMPORT))
2627  err = switch_layout_host(hwfc, ectx, frame, pmode);
2628 
2629  if (err != AVERROR(ENOTSUP))
2630  return err;
2631 
2632  return switch_layout(hwfc, ectx, frame, pmode);
2633 }
2634 
2635 static inline void get_plane_wh(uint32_t *w, uint32_t *h, enum AVPixelFormat format,
2636  int frame_w, int frame_h, int plane)
2637 {
2639 
2640  /* Currently always true unless gray + alpha support is added */
2641  if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB ||
2642  !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
2643  *w = frame_w;
2644  *h = frame_h;
2645  return;
2646  }
2647 
2648  *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w);
2649  *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h);
2650 }
2651 
2653  VkImageTiling tiling, VkImageUsageFlagBits usage,
2654  VkImageCreateFlags flags, int nb_layers,
2655  void *create_pnext)
2656 {
2657  int err;
2658  VkResult ret;
2659  AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
2660  AVHWDeviceContext *ctx = hwfc->device_ctx;
2661  VulkanDevicePriv *p = ctx->hwctx;
2662  AVVulkanDeviceContext *hwctx = &p->p;
2663  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2664  AVVkFrame *f;
2665 
2666  VkSemaphoreTypeCreateInfo sem_type_info = {
2667  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2668  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2669  .initialValue = 0,
2670  };
2671  VkSemaphoreCreateInfo sem_spawn = {
2672  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2673  .pNext = &sem_type_info,
2674  };
2675 
2676  VkExportSemaphoreCreateInfo ext_sem_info_opaque = {
2677  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
2678 #ifdef _WIN32
2679  .handleTypes = IsWindows8OrGreater()
2680  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2681  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2682 #else
2683  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2684 #endif
2685  };
2686 
2687  /* Check if exporting is supported before chaining any structs */
2688  if (p->ext_sem_props_opaque.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) {
2689  if (p->vkctx.extensions & (FF_VK_EXT_EXTERNAL_WIN32_SEM | FF_VK_EXT_EXTERNAL_FD_SEM))
2690  ff_vk_link_struct(&sem_type_info, &ext_sem_info_opaque);
2691  }
2692 
2693  f = av_vk_frame_alloc();
2694  if (!f) {
2695  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2696  return AVERROR(ENOMEM);
2697  }
2698 
2699  // TODO: check width and height for alignment in case of multiplanar (must be mod-2 if subsampled)
2700 
2701  /* Create the images */
2702  for (int i = 0; (hwfc_vk->format[i] != VK_FORMAT_UNDEFINED); i++) {
2703  VkImageCreateInfo create_info = {
2704  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2705  .pNext = create_pnext,
2706  .imageType = VK_IMAGE_TYPE_2D,
2707  .format = hwfc_vk->format[i],
2708  .extent.depth = 1,
2709  .mipLevels = 1,
2710  .arrayLayers = nb_layers,
2711  .flags = flags,
2712  .tiling = tiling,
2713  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2714  .usage = usage,
2715  .samples = VK_SAMPLE_COUNT_1_BIT,
2716  .pQueueFamilyIndices = p->img_qfs,
2717  .queueFamilyIndexCount = p->nb_img_qfs,
2718  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2719  VK_SHARING_MODE_EXCLUSIVE,
2720  };
2721 
2722  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2723  hwfc->sw_format, hwfc->width, hwfc->height, i);
2724 
2725  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2726  hwctx->alloc, &f->img[i]);
2727  if (ret != VK_SUCCESS) {
2728  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2729  ff_vk_ret2str(ret));
2730  err = AVERROR(EINVAL);
2731  goto fail;
2732  }
2733 
2734  /* Create semaphore */
2735  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2736  hwctx->alloc, &f->sem[i]);
2737  if (ret != VK_SUCCESS) {
2738  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2739  ff_vk_ret2str(ret));
2740  err = AVERROR_EXTERNAL;
2741  goto fail;
2742  }
2743 
2744  f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2745  f->layout[i] = create_info.initialLayout;
2746  f->access[i] = 0x0;
2747  f->sem_value[i] = 0;
2748  }
2749 
2750  f->flags = 0x0;
2751  f->tiling = tiling;
2752 
2753  *frame = f;
2754  return 0;
2755 
2756 fail:
2757  vulkan_frame_free(hwfc, f);
2758  return err;
2759 }
2760 
2761 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2763  VkExternalMemoryHandleTypeFlags *comp_handle_types,
2764  VkExternalMemoryHandleTypeFlags *iexp,
2765  VkExternalMemoryHandleTypeFlagBits exp)
2766 {
2767  VkResult ret;
2768  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2769  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2770  AVVulkanDeviceContext *dev_hwctx = &p->p;
2771  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2772 
2773  const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
2775  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2776  int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
2777  int nb_mods;
2778 
2779  VkExternalImageFormatProperties eprops = {
2780  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2781  };
2782  VkImageFormatProperties2 props = {
2783  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2784  .pNext = &eprops,
2785  };
2786  VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
2787  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2788  .pNext = NULL,
2789  .pQueueFamilyIndices = p->img_qfs,
2790  .queueFamilyIndexCount = p->nb_img_qfs,
2791  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2792  VK_SHARING_MODE_EXCLUSIVE,
2793  };
2794  VkPhysicalDeviceExternalImageFormatInfo enext = {
2795  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2796  .handleType = exp,
2797  .pNext = has_mods ? &phy_dev_mod_info : NULL,
2798  };
2799  VkPhysicalDeviceImageFormatInfo2 pinfo = {
2800  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2801  .pNext = !exp ? NULL : &enext,
2802  .format = vk_find_format_entry(hwfc->sw_format)->vkf,
2803  .type = VK_IMAGE_TYPE_2D,
2804  .tiling = hwctx->tiling,
2805  .usage = hwctx->usage,
2806  .flags = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && has_mods) ?
2807  (hwctx->img_flags) : (VkImageCreateFlags)(VK_IMAGE_CREATE_ALIAS_BIT),
2808  };
2809 
2810  nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
2811  for (int i = 0; i < nb_mods; i++) {
2812  if (has_mods)
2813  phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
2814 
2815  ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
2816  &pinfo, &props);
2817 
2818  if (has_mods)
2819  av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
2820  i, (unsigned long long)phy_dev_mod_info.drmFormatModifier,
2821  ret == VK_SUCCESS ? "OK" : "FAIL");
2822  if (ret == VK_SUCCESS) {
2823  *iexp |= exp;
2824  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2825  if (exp == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
2826  VulkanFramesPriv *fp = hwfc->hwctx;
2827  fp->export_requires_dedicated = !!(eprops.externalMemoryProperties.externalMemoryFeatures &
2828  VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
2829  }
2830  }
2831  }
2832 }
2833 
2834 static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2835 {
2836  int err;
2837  AVVkFrame *f;
2838  AVBufferRef *avbuf = NULL;
2839  AVHWFramesContext *hwfc = opaque;
2840  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2841  VulkanFramesPriv *fp = hwfc->hwctx;
2842  AVVulkanFramesContext *hwctx = &fp->p;
2843  VkExternalMemoryHandleTypeFlags e = 0x0;
2844  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2845 
2846  VkExternalMemoryImageCreateInfo eiinfo = {
2847  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2848  .pNext = hwctx->create_pnext,
2849  };
2850 
2851 #ifdef _WIN32
2852  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2853  try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2854  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2855  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2856 #else
2857  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
2858  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
2859  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2860  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2861 
2862  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_DMABUF_MEMORY &&
2863  hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
2864  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2865  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2866 #endif
2867 
2868  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2869  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2870  eminfo[i].pNext = hwctx->alloc_pnext[i];
2871  eminfo[i].handleTypes = e;
2872  }
2873 
2874  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
2875  hwctx->nb_layers,
2876  eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
2877  if (err) {
2878  av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed: create_frame failed: %d\n", err);
2879  return NULL;
2880  }
2881 
2882  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2883  if (err)
2884  goto fail;
2885 
2886  if ( (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2887  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR))
2888  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DPB);
2889  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)
2890  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DST);
2891  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR)
2892  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_ENCODING_DPB);
2893  else if (hwctx->usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
2894  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_WRITE);
2895  else
2896  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_GENERAL);
2897  if (err)
2898  goto fail;
2899 
2900  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2901  vulkan_frame_free_cb, hwfc, 0);
2902  if (!avbuf)
2903  goto fail;
2904 
2905  return avbuf;
2906 
2907 fail:
2908  av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed with error %d\n", err);
2909  vulkan_frame_free(hwfc, f);
2910  return NULL;
2911 }
2912 
2914 {
2916 }
2917 
2919 {
2921 }
2922 
2924 {
2925  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2926  VulkanFramesPriv *fp = hwfc->hwctx;
2927 
2928  if (fp->modifier_info) {
2929  if (fp->modifier_info->pDrmFormatModifiers)
2930  av_freep(&fp->modifier_info->pDrmFormatModifiers);
2931  av_freep(&fp->modifier_info);
2932  }
2933 
2934  ff_vk_exec_pool_free(&p->vkctx, &fp->compute_exec);
2935  ff_vk_exec_pool_free(&p->vkctx, &fp->upload_exec);
2936  ff_vk_exec_pool_free(&p->vkctx, &fp->download_exec);
2937 
2938  av_buffer_pool_uninit(&fp->tmp);
2939 }
2940 
2942 {
2943  int err;
2944  AVVkFrame *f;
2945  VulkanFramesPriv *fp = hwfc->hwctx;
2946  AVVulkanFramesContext *hwctx = &fp->p;
2947  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2948  AVVulkanDeviceContext *dev_hwctx = &p->p;
2949  VkImageUsageFlags supported_usage;
2950  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2951  const struct FFVkFormatEntry *fmt;
2952  int disable_multiplane = p->disable_multiplane ||
2954  int is_lone_dpb = ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR) ||
2955  ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2956  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)));
2957 
2958  /* Defaults */
2959  if (!hwctx->nb_layers)
2960  hwctx->nb_layers = 1;
2961 
2962  /* VK_IMAGE_TILING_OPTIMAL == 0, can't check for it really */
2963  if (p->use_linear_images &&
2964  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
2965  hwctx->tiling = VK_IMAGE_TILING_LINEAR;
2966 
2967 
2968  fmt = vk_find_format_entry(hwfc->sw_format);
2969  if (!fmt) {
2970  av_log(hwfc, AV_LOG_ERROR, "Unsupported pixel format: %s!\n",
2972  return AVERROR(ENOTSUP);
2973  }
2974 
2975  if (hwctx->format[0] != VK_FORMAT_UNDEFINED) {
2976  if (hwctx->format[0] != fmt->vkf) {
2977  for (int i = 0; i < fmt->nb_images_fallback; i++) {
2978  if (hwctx->format[i] != fmt->fallback[i]) {
2979  av_log(hwfc, AV_LOG_ERROR, "Incompatible Vulkan format given "
2980  "for the current sw_format %s!\n",
2982  return AVERROR(EINVAL);
2983  }
2984  }
2985  }
2986 
2987  /* Check if the sw_format itself is supported */
2988  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
2989  hwctx->tiling, NULL,
2990  NULL, NULL, &supported_usage, 0,
2991  !hwctx->usage ||
2992  (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
2993  if (err < 0) {
2994  av_log(hwfc, AV_LOG_ERROR, "Unsupported sw format: %s!\n",
2996  return AVERROR(EINVAL);
2997  }
2998  } else {
2999  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3000  hwctx->tiling, hwctx->format, NULL,
3001  NULL, &supported_usage,
3002  disable_multiplane,
3003  !hwctx->usage ||
3004  (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3005  if (err < 0)
3006  return err;
3007  }
3008 
3009  /* Lone DPB images do not need additional flags. */
3010  /* With DRM modifier + video profile the caller has already chosen a valid
3011  * usage/img_flags/chain; do not add usage or img_flags (supported_usage does
3012  * not consider the actual modifier or video profile). */
3013  int drm_mod_with_video = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
3015  VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
3016 
3017  if (!is_lone_dpb && !drm_mod_with_video) {
3018  /* Image usage flags */
3019  hwctx->usage |= supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
3020  VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
3021  VK_IMAGE_USAGE_STORAGE_BIT |
3022  VK_IMAGE_USAGE_SAMPLED_BIT);
3023 
3024  if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY &&
3025  !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) &&
3026  !(p->dprops.driverID == VK_DRIVER_ID_MOLTENVK))
3027  hwctx->usage |= supported_usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
3028 
3029  /* Enables encoding of images, if supported by format and extensions */
3030  if ((supported_usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3031  (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3032  (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1))
3033  hwctx->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
3034 
3035  /* Image creation flags.
3036  * Only fill them in automatically if the image is not going to be used as
3037  * a DPB-only image, and we have SAMPLED/STORAGE bits set. */
3038  if (!hwctx->img_flags) {
3039  int sampleable = hwctx->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
3040  VK_IMAGE_USAGE_STORAGE_BIT);
3041  hwctx->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
3042  if (sampleable) {
3043  hwctx->img_flags |= VK_IMAGE_CREATE_ALIAS_BIT;
3044  if ((fmt->vk_planes > 1) && (hwctx->format[0] == fmt->vkf))
3045  hwctx->img_flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
3046  }
3047  }
3048  }
3049 
3050  /* If the image has an ENCODE_SRC usage, and the maintenance1
3051  * extension is supported, check if it has a profile list.
3052  * If there's no profile list, or it has no encode operations,
3053  * then allow creating the image with no specific profile. */
3054  if ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3055  (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3056  (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) {
3057  const VkVideoProfileListInfoKHR *pl;
3058  pl = ff_vk_find_struct(hwctx->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
3059  if (!pl) {
3060  hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3061  } else {
3062  uint32_t i;
3063  for (i = 0; i < pl->profileCount; i++) {
3064  /* Video ops start at exactly 0x00010000 */
3065  if (pl->pProfiles[i].videoCodecOperation & 0xFFFF0000)
3066  break;
3067  }
3068  if (i == pl->profileCount)
3069  hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3070  }
3071  }
3072 
3073  if (!hwctx->lock_frame)
3074  hwctx->lock_frame = lock_frame;
3075 
3076  if (!hwctx->unlock_frame)
3077  hwctx->unlock_frame = unlock_frame;
3078 
3079  err = ff_vk_exec_pool_init(&p->vkctx, p->compute_qf, &fp->compute_exec,
3080  p->compute_qf->num, 0, 0, 0, NULL);
3081  if (err)
3082  return err;
3083 
3084  err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->upload_exec,
3085  p->transfer_qf->num*2, 0, 0, 0, NULL);
3086  if (err)
3087  return err;
3088 
3089  err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->download_exec,
3090  p->transfer_qf->num, 0, 0, 0, NULL);
3091  if (err)
3092  return err;
3093 
3094  /* Test to see if allocation will fail */
3095  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
3096  hwctx->nb_layers, hwctx->create_pnext);
3097  if (err)
3098  return err;
3099 
3100  /* Collect `VkDrmFormatModifierPropertiesEXT` for each plane. Required for DRM export. */
3101  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS && hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
3102  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3103  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3104  };
3105  err = vk->GetImageDrmFormatModifierPropertiesEXT(dev_hwctx->act_dev, f->img[0],
3106  &drm_mod);
3107  if (err != VK_SUCCESS) {
3108  av_log(hwfc, AV_LOG_ERROR, "Failed to get image DRM format modifier properties");
3109  vulkan_frame_free(hwfc, f);
3110  return AVERROR_EXTERNAL;
3111  }
3112  for (int i = 0; i < fmt->vk_planes; ++i) {
3113  VkDrmFormatModifierPropertiesListEXT modp;
3114  VkFormatProperties2 fmtp;
3115  VkDrmFormatModifierPropertiesEXT *mod_props = NULL;
3116 
3117  modp = (VkDrmFormatModifierPropertiesListEXT) {
3118  .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
3119  };
3120  fmtp = (VkFormatProperties2) {
3121  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
3122  .pNext = &modp,
3123  };
3124 
3125  /* query drmFormatModifierCount by keeping pDrmFormatModifierProperties NULL */
3126  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3127 
3128  modp.pDrmFormatModifierProperties =
3129  av_calloc(modp.drmFormatModifierCount, sizeof(*modp.pDrmFormatModifierProperties));
3130  if (!modp.pDrmFormatModifierProperties) {
3131  vulkan_frame_free(hwfc, f);
3132  return AVERROR(ENOMEM);
3133  }
3134  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3135 
3136  for (uint32_t j = 0; j < modp.drmFormatModifierCount; ++j) {
3137  VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[j];
3138  if (m->drmFormatModifier == drm_mod.drmFormatModifier) {
3139  mod_props = m;
3140  break;
3141  }
3142  }
3143 
3144  if (mod_props == NULL) {
3145  av_log(hwfc, AV_LOG_ERROR, "No DRM format modifier properties found for modifier 0x%016"PRIx64"\n",
3146  drm_mod.drmFormatModifier);
3147  av_free(modp.pDrmFormatModifierProperties);
3148  vulkan_frame_free(hwfc, f);
3149  return AVERROR_EXTERNAL;
3150  }
3151 
3152  fp->drm_format_modifier_properties[i] = *mod_props;
3153  av_free(modp.pDrmFormatModifierProperties);
3154  }
3155  }
3156 
3157  vulkan_frame_free(hwfc, f);
3158 
3159  /* If user did not specify a pool, hwfc->pool will be set to the internal one
3160  * in hwcontext.c just after this gets called */
3161  if (!hwfc->pool) {
3163  hwfc, vulkan_pool_alloc,
3164  NULL);
3165  if (!ffhwframesctx(hwfc)->pool_internal)
3166  return AVERROR(ENOMEM);
3167  }
3168 
3169  return 0;
3170 }
3171 
3173 {
3174  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
3175  if (!frame->buf[0])
3176  return AVERROR(ENOMEM);
3177 
3178  frame->data[0] = frame->buf[0]->data;
3179  frame->format = AV_PIX_FMT_VULKAN;
3180  frame->width = hwfc->width;
3181  frame->height = hwfc->height;
3182 
3183  return 0;
3184 }
3185 
3187  enum AVHWFrameTransferDirection dir,
3188  enum AVPixelFormat **formats)
3189 {
3190  enum AVPixelFormat *fmts;
3191  int n = 2;
3192 
3193 #if CONFIG_CUDA
3194  n++;
3195 #endif
3196  fmts = av_malloc_array(n, sizeof(*fmts));
3197  if (!fmts)
3198  return AVERROR(ENOMEM);
3199 
3200  n = 0;
3201  fmts[n++] = hwfc->sw_format;
3202 #if CONFIG_CUDA
3203  fmts[n++] = AV_PIX_FMT_CUDA;
3204 #endif
3205  fmts[n++] = AV_PIX_FMT_NONE;
3206 
3207  *formats = fmts;
3208  return 0;
3209 }
3210 
3211 #if CONFIG_LIBDRM
3212 static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3213 {
3214  vulkan_frame_free(hwfc, hwmap->priv);
3215 }
3216 
3217 static const struct {
3218  uint32_t drm_fourcc;
3219  VkFormat vk_format;
3220 } vulkan_drm_format_map[] = {
3221  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
3222  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
3223  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
3224  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
3225  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
3226  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
3227  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3228  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3229  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3230  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3231  { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3232  { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3233  { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3234  { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3235 
3236  // All these DRM_FORMATs were added in the same libdrm commit.
3237 #ifdef DRM_FORMAT_XYUV8888
3238  { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
3239  { DRM_FORMAT_XVYU2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 } ,
3240  { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 } ,
3241  { DRM_FORMAT_XVYU16161616, VK_FORMAT_R16G16B16A16_UNORM } ,
3242 #endif
3243 };
3244 
3245 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
3246 {
3247  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3248  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
3249  return vulkan_drm_format_map[i].vk_format;
3250  return VK_FORMAT_UNDEFINED;
3251 }
3252 
3253 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
3254  const AVFrame *src, int flags)
3255 {
3256  int err = 0;
3257  VkResult ret;
3258  AVVkFrame *f;
3259  int bind_counts = 0;
3260  AVHWDeviceContext *ctx = hwfc->device_ctx;
3261  VulkanDevicePriv *p = ctx->hwctx;
3262  AVVulkanDeviceContext *hwctx = &p->p;
3263  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3264  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
3265  VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
3266  VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
3267 
3268  for (int i = 0; i < desc->nb_layers; i++) {
3269  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
3270  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
3271  desc->layers[i].format);
3272  return AVERROR(EINVAL);
3273  }
3274  }
3275 
3276  if (!(f = av_vk_frame_alloc())) {
3277  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
3278  err = AVERROR(ENOMEM);
3279  goto fail;
3280  }
3281 
3282  f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
3283 
3284  for (int i = 0; i < desc->nb_layers; i++) {
3285  const int planes = desc->layers[i].nb_planes;
3286 
3287  /* Semaphore */
3288  VkSemaphoreTypeCreateInfo sem_type_info = {
3289  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3290  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
3291  .initialValue = 0,
3292  };
3293  VkSemaphoreCreateInfo sem_spawn = {
3294  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3295  .pNext = &sem_type_info,
3296  };
3297 
3298  /* Image creation */
3299  VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
3300  VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
3301  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
3302  .drmFormatModifier = desc->objects[0].format_modifier,
3303  .drmFormatModifierPlaneCount = planes,
3304  .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
3305  };
3306  VkExternalMemoryImageCreateInfo ext_img_spec = {
3307  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
3308  .pNext = &ext_img_mod_spec,
3309  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3310  };
3311  VkImageCreateInfo create_info = {
3312  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3313  .pNext = &ext_img_spec,
3314  .imageType = VK_IMAGE_TYPE_2D,
3315  .format = drm_to_vulkan_fmt(desc->layers[i].format),
3316  .extent.depth = 1,
3317  .mipLevels = 1,
3318  .arrayLayers = 1,
3319  .flags = 0x0,
3320  .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
3321  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
3322  .usage = 0x0, /* filled in below */
3323  .samples = VK_SAMPLE_COUNT_1_BIT,
3324  .pQueueFamilyIndices = p->img_qfs,
3325  .queueFamilyIndexCount = p->nb_img_qfs,
3326  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
3327  VK_SHARING_MODE_EXCLUSIVE,
3328  };
3329 
3330  /* The DRM fourcc fixes a specific channel order (f.ex ARGB8888 maps to
3331  * B8G8R8A8), but image views are always created from the destination
3332  * frames context sw_format (like how bgra maps to R8G8B8A8). For a
3333  * single plane layer, create the image with the sw_format's compatible
3334  * VkFormat so the image and its views agree without a mutable format
3335  * list, the format query below validates this */
3336  if (planes == 1) {
3337  const VkFormat *sw_vkfmts = av_vkfmt_from_pixfmt(hwfc->sw_format);
3338  if (sw_vkfmts && sw_vkfmts[i] != VK_FORMAT_UNDEFINED)
3339  create_info.format = sw_vkfmts[i];
3340  }
3341 
3342  /* Image format verification */
3343  VkExternalImageFormatProperties ext_props = {
3344  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
3345  };
3346  VkImageFormatProperties2 props_ret = {
3347  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
3348  .pNext = &ext_props,
3349  };
3350  VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
3351  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
3352  .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
3353  .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
3354  .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
3355  .sharingMode = create_info.sharingMode,
3356  };
3357  VkPhysicalDeviceExternalImageFormatInfo props_ext = {
3358  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
3359  .pNext = &props_drm_mod,
3360  .handleType = ext_img_spec.handleTypes,
3361  };
3362  VkPhysicalDeviceImageFormatInfo2 fmt_props;
3363 
3364  if (flags & AV_HWFRAME_MAP_READ)
3365  create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT |
3366  VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
3368  create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT |
3369  VK_IMAGE_USAGE_TRANSFER_DST_BIT;
3370 
3371  fmt_props = (VkPhysicalDeviceImageFormatInfo2) {
3372  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
3373  .pNext = &props_ext,
3374  .format = create_info.format,
3375  .type = create_info.imageType,
3376  .tiling = create_info.tiling,
3377  .usage = create_info.usage,
3378  .flags = create_info.flags,
3379  };
3380 
3381  /* Check if importing is possible for this combination of parameters */
3382  ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
3383  &fmt_props, &props_ret);
3384  if (ret != VK_SUCCESS) {
3385  av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
3386  ff_vk_ret2str(ret));
3387  err = AVERROR_EXTERNAL;
3388  goto fail;
3389  }
3390 
3391  /* Set the image width/height */
3392  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
3393  hwfc->sw_format, src->width, src->height, i);
3394 
3395  /* Set the subresource layout based on the layer properties */
3396  for (int j = 0; j < planes; j++) {
3397  ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
3398  ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
3399  ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
3400  ext_img_layouts[j].arrayPitch = 0;
3401  ext_img_layouts[j].depthPitch = 0;
3402  }
3403 
3404  /* Create image */
3405  ret = vk->CreateImage(hwctx->act_dev, &create_info,
3406  hwctx->alloc, &f->img[i]);
3407  if (ret != VK_SUCCESS) {
3408  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
3409  ff_vk_ret2str(ret));
3410  err = AVERROR(EINVAL);
3411  goto fail;
3412  }
3413 
3414  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3415  hwctx->alloc, &f->sem[i]);
3416  if (ret != VK_SUCCESS) {
3417  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3418  ff_vk_ret2str(ret));
3419  err = AVERROR_EXTERNAL;
3420  goto fail;
3421  }
3422 
3423  f->queue_family[i] = VK_QUEUE_FAMILY_EXTERNAL;
3424  f->layout[i] = create_info.initialLayout;
3425  f->access[i] = 0x0;
3426  f->sem_value[i] = 0;
3427  }
3428 
3429  for (int i = 0; i < desc->nb_layers; i++) {
3430  /* Memory requirements */
3431  VkImageMemoryRequirementsInfo2 req_desc = {
3432  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
3433  .image = f->img[i],
3434  };
3435  VkMemoryDedicatedRequirements ded_req = {
3436  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
3437  };
3438  VkMemoryRequirements2 req2 = {
3439  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3440  .pNext = &ded_req,
3441  };
3442 
3443  /* Allocation/importing */
3444  VkMemoryFdPropertiesKHR fdmp = {
3445  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
3446  };
3447  /* This assumes that a layer will never be constructed from multiple
3448  * objects. If that was to happen in the real world, this code would
3449  * need to import each plane separately.
3450  */
3451  VkImportMemoryFdInfoKHR idesc = {
3452  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
3453  .fd = dup(desc->objects[desc->layers[i].planes[0].object_index].fd),
3454  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3455  };
3456  VkMemoryDedicatedAllocateInfo ded_alloc = {
3457  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
3458  .pNext = &idesc,
3459  .image = req_desc.image,
3460  };
3461 
3462  /* Get object properties */
3463  ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
3464  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3465  idesc.fd, &fdmp);
3466  if (ret != VK_SUCCESS) {
3467  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
3468  ff_vk_ret2str(ret));
3469  err = AVERROR_EXTERNAL;
3470  close(idesc.fd);
3471  goto fail;
3472  }
3473 
3474  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
3475 
3476  /* Only a single bit must be set, not a range, and it must match */
3477  req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
3478 
3479  err = alloc_mem(ctx, &req2.memoryRequirements,
3480  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
3481  (ded_req.prefersDedicatedAllocation ||
3482  ded_req.requiresDedicatedAllocation) ?
3483  &ded_alloc : ded_alloc.pNext,
3484  &f->flags, &f->mem[i]);
3485  if (err) {
3486  close(idesc.fd);
3487  goto fail;
3488  }
3489 
3490  f->size[i] = req2.memoryRequirements.size;
3491  }
3492 
3493  for (int i = 0; i < desc->nb_layers; i++) {
3494  const int planes = desc->layers[i].nb_planes;
3495  for (int j = 0; j < planes; j++) {
3496  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
3497  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
3498  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
3499 
3500  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
3501  plane_info[bind_counts].pNext = NULL;
3502  plane_info[bind_counts].planeAspect = aspect;
3503 
3504  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
3505  bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
3506  bind_info[bind_counts].image = f->img[i];
3507  bind_info[bind_counts].memory = f->mem[i];
3508 
3509  /* Offset is already signalled via pPlaneLayouts above */
3510  bind_info[bind_counts].memoryOffset = 0;
3511 
3512  bind_counts++;
3513  }
3514  }
3515 
3516  /* Bind the allocated memory to the images */
3517  ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
3518  if (ret != VK_SUCCESS) {
3519  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
3520  ff_vk_ret2str(ret));
3521  err = AVERROR_EXTERNAL;
3522  goto fail;
3523  }
3524 
3525  *frame = f;
3526 
3527  return 0;
3528 
3529 fail:
3530  vulkan_frame_free(hwfc, f);
3531 
3532  return err;
3533 }
3534 
3535 static int vulkan_map_from_drm_frame_sync(AVHWFramesContext *hwfc, AVFrame *dst,
3536  const AVDRMFrameDescriptor *desc, int flags)
3537 {
3538  int err;
3539  VkResult ret;
3540  AVHWDeviceContext *ctx = hwfc->device_ctx;
3541  VulkanDevicePriv *p = ctx->hwctx;
3542  VulkanFramesPriv *fp = hwfc->hwctx;
3543  AVVulkanDeviceContext *hwctx = &p->p;
3544  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3545 
3546 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
3547  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) {
3548  VkCommandBuffer cmd_buf;
3549  FFVkExecContext *exec;
3550  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
3551  VkSemaphore drm_sync_sem[AV_DRM_MAX_PLANES] = { 0 };
3552  int nb_img_bar = 0;
3553 
3554  for (int i = 0; i < desc->nb_objects; i++) {
3555  VkSemaphoreTypeCreateInfo sem_type_info = {
3556  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3557  .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
3558  };
3559  VkSemaphoreCreateInfo sem_spawn = {
3560  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3561  .pNext = &sem_type_info,
3562  };
3563  VkImportSemaphoreFdInfoKHR import_info;
3564  struct dma_buf_export_sync_file implicit_fd_info = {
3565  .flags = DMA_BUF_SYNC_READ,
3566  .fd = -1,
3567  };
3568 
3569  if (ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
3570  &implicit_fd_info)) {
3571  err = AVERROR(errno);
3572  av_log(hwctx, AV_LOG_ERROR, "Failed to retrieve implicit DRM sync file: %s\n",
3573  av_err2str(err));
3574  for (; i >= 0; i--)
3575  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3576  return err;
3577  }
3578 
3579  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3580  hwctx->alloc, &drm_sync_sem[i]);
3581  if (ret != VK_SUCCESS) {
3582  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3583  ff_vk_ret2str(ret));
3584  err = AVERROR_EXTERNAL;
3585  for (; i >= 0; i--)
3586  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3587  return err;
3588  }
3589 
3590  import_info = (VkImportSemaphoreFdInfoKHR) {
3591  .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
3592  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
3593  .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
3594  .semaphore = drm_sync_sem[i],
3595  .fd = implicit_fd_info.fd,
3596  };
3597 
3598  ret = vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info);
3599  if (ret != VK_SUCCESS) {
3600  av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n",
3601  ff_vk_ret2str(ret));
3602  err = AVERROR_EXTERNAL;
3603  for (; i >= 0; i--)
3604  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3605  return err;
3606  }
3607  }
3608 
3609  exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
3610  cmd_buf = exec->buf;
3611 
3612  ff_vk_exec_start(&p->vkctx, exec);
3613 
3614  /* Ownership of semaphores is passed */
3615  err = ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec,
3616  drm_sync_sem, desc->nb_objects,
3617  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1);
3618  if (err < 0)
3619  return err;
3620 
3621  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, dst,
3622  VK_PIPELINE_STAGE_2_NONE,
3623  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
3624  if (err < 0)
3625  return err;
3626 
3627  ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar,
3628  VK_PIPELINE_STAGE_2_NONE,
3629  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
3630  ((flags & AV_HWFRAME_MAP_READ) ?
3631  VK_ACCESS_2_SHADER_SAMPLED_READ_BIT : 0x0) |
3633  VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT : 0x0),
3634  VK_IMAGE_LAYOUT_GENERAL,
3635  p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
3636 
3637  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
3638  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
3639  .pImageMemoryBarriers = img_bar,
3640  .imageMemoryBarrierCount = nb_img_bar,
3641  });
3642 
3643  err = ff_vk_exec_submit(&p->vkctx, exec);
3644  if (err < 0)
3645  return err;
3646  } else
3647 #endif
3648  {
3649  AVVkFrame *f = (AVVkFrame *)dst->data[0];
3650  av_log(hwctx, AV_LOG_WARNING, "No support for synchronization when importing DMA-BUFs, "
3651  "image may be corrupted.\n");
3653  if (err)
3654  return err;
3655  }
3656 
3657  return 0;
3658 }
3659 
3660 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3661  const AVFrame *src, int flags)
3662 {
3663  int err = 0;
3664  AVVkFrame *f;
3665  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
3666 
3667  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src, flags)))
3668  return err;
3669 
3670  /* The unmapping function will free this */
3671  dst->data[0] = (uint8_t *)f;
3672  dst->width = src->width;
3673  dst->height = src->height;
3674 
3675  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
3676  &vulkan_unmap_from_drm, f);
3677  if (err < 0)
3678  goto fail;
3679 
3680  err = vulkan_map_from_drm_frame_sync(hwfc, dst, desc, flags);
3681  if (err < 0)
3682  return err;
3683 
3684  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
3685 
3686  return 0;
3687 
3688 fail:
3690  dst->data[0] = NULL;
3691  return err;
3692 }
3693 
3694 #if CONFIG_VAAPI
3695 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
3696  AVFrame *dst, const AVFrame *src,
3697  int flags)
3698 {
3699  int err;
3700  AVFrame *tmp = av_frame_alloc();
3701  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3702  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
3703  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
3704 
3705  if (!tmp)
3706  return AVERROR(ENOMEM);
3707 
3708  /* We have to sync since like the previous comment said, no semaphores */
3709  vaSyncSurface(vaapi_ctx->display, surface_id);
3710 
3711  tmp->format = AV_PIX_FMT_DRM_PRIME;
3712 
3713  err = av_hwframe_map(tmp, src, flags);
3714  if (err < 0)
3715  goto fail;
3716 
3717  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
3718  if (err < 0)
3719  goto fail;
3720 
3721  err = ff_hwframe_map_replace(dst, src);
3722 
3723 fail:
3724  av_frame_free(&tmp);
3725  return err;
3726 }
3727 #endif
3728 #endif
3729 
3730 #if CONFIG_CUDA
3731 static int export_mem_to_cuda(AVHWDeviceContext *ctx,
3732  AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3733  AVVkFrameInternal *dst_int, int idx,
3734  VkDeviceMemory mem, size_t size)
3735 {
3736  VkResult ret;
3737  VulkanDevicePriv *p = ctx->hwctx;
3738  AVVulkanDeviceContext *hwctx = &p->p;
3739  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3740 
3741 #ifdef _WIN32
3742  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3743  .type = IsWindows8OrGreater()
3744  ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3745  : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
3746  .size = size,
3747  };
3748  VkMemoryGetWin32HandleInfoKHR export_info = {
3749  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
3750  .memory = mem,
3751  .handleType = IsWindows8OrGreater()
3752  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3753  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3754  };
3755 
3756  ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
3757  &ext_desc.handle.win32.handle);
3758  if (ret != VK_SUCCESS) {
3759  av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
3760  ff_vk_ret2str(ret));
3761  return AVERROR_EXTERNAL;
3762  }
3763  dst_int->ext_mem_handle[idx] = ext_desc.handle.win32.handle;
3764 #else
3765  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3766  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
3767  .size = size,
3768  };
3769  VkMemoryGetFdInfoKHR export_info = {
3770  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3771  .memory = mem,
3772  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
3773  };
3774 
3775  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3776  &ext_desc.handle.fd);
3777  if (ret != VK_SUCCESS) {
3778  av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
3779  ff_vk_ret2str(ret));
3780  return AVERROR_EXTERNAL;
3781  }
3782 #endif
3783 
3784  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[idx], &ext_desc));
3785  if (ret < 0) {
3786 #ifndef _WIN32
3787  close(ext_desc.handle.fd);
3788 #endif
3789  return AVERROR_EXTERNAL;
3790  }
3791 
3792  return 0;
3793 }
3794 
3795 static int export_sem_to_cuda(AVHWDeviceContext *ctx,
3796  AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3797  AVVkFrameInternal *dst_int, int idx,
3798  VkSemaphore sem)
3799 {
3800  VkResult ret;
3801  VulkanDevicePriv *p = ctx->hwctx;
3802  AVVulkanDeviceContext *hwctx = &p->p;
3803  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3804 
3805 #ifdef _WIN32
3806  VkSemaphoreGetWin32HandleInfoKHR sem_export = {
3807  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
3808  .semaphore = sem,
3809  .handleType = IsWindows8OrGreater()
3810  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
3811  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3812  };
3813  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3814  .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
3815  };
3816 #else
3817  VkSemaphoreGetFdInfoKHR sem_export = {
3818  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
3819  .semaphore = sem,
3820  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
3821  };
3822  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3823  .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
3824  };
3825 #endif
3826 
3827 #ifdef _WIN32
3828  ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
3829  &ext_sem_desc.handle.win32.handle);
3830 #else
3831  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
3832  &ext_sem_desc.handle.fd);
3833 #endif
3834  if (ret != VK_SUCCESS) {
3835  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
3836  ff_vk_ret2str(ret));
3837  return AVERROR_EXTERNAL;
3838  }
3839 #ifdef _WIN32
3840  dst_int->ext_sem_handle[idx] = ext_sem_desc.handle.win32.handle;
3841 #endif
3842 
3843  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[idx],
3844  &ext_sem_desc));
3845  if (ret < 0) {
3846 #ifndef _WIN32
3847  close(ext_sem_desc.handle.fd);
3848 #endif
3849  return AVERROR_EXTERNAL;
3850  }
3851 
3852  return 0;
3853 }
3854 
3855 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
3856  AVBufferRef *cuda_hwfc,
3857  const AVFrame *frame)
3858 {
3859  int err;
3860  VkResult ret;
3861  AVVkFrame *dst_f;
3862  AVVkFrameInternal *dst_int;
3863  AVHWDeviceContext *ctx = hwfc->device_ctx;
3864  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3866  VulkanDevicePriv *p = ctx->hwctx;
3867  AVVulkanDeviceContext *hwctx = &p->p;
3868  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3869  int nb_images;
3870 
3871  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
3872  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3873  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3874  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3875  CudaFunctions *cu = cu_internal->cuda_dl;
3876  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
3877  CU_AD_FORMAT_UNSIGNED_INT8;
3878  const int elem_size = 1 + desc->comp[0].depth > 8;
3879 
3880  dst_f = (AVVkFrame *)frame->data[0];
3881  dst_int = dst_f->internal;
3882 
3883  if (!dst_int->cuda_fc_ref) {
3884  size_t offsets[3] = { 0 };
3885 
3886  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
3887  if (!dst_int->cuda_fc_ref)
3888  return AVERROR(ENOMEM);
3889 
3890  nb_images = ff_vk_count_images(dst_f);
3891  for (int i = 0; i < nb_images; i++) {
3892  err = export_mem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
3893  dst_f->mem[i], dst_f->size[i]);
3894  if (err < 0)
3895  goto fail;
3896 
3897  err = export_sem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
3898  dst_f->sem[i]);
3899  if (err < 0)
3900  goto fail;
3901  }
3902 
3903  if (nb_images != planes) {
3904  for (int i = 0; i < planes; i++) {
3905  /* Cuda now defines array formats for semi-planar, but these are
3906  * not currently supported for imported Vulkan images. */
3907  if (desc->comp[i].step / elem_size > 1) {
3909  "Cannot map a multiplane Vulkan image (%d image(s) "
3910  "for %d plane(s)) to CUDA; create the Vulkan device "
3911  "with the disable_multiplane=1 option (one image per "
3912  "plane) for CUDA interop.\n", nb_images, planes);
3913  err = AVERROR(ENOSYS);
3914  goto fail;
3915  }
3916 
3917  VkImageSubresource subres = {
3918  .aspectMask = i == 2 ? VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT :
3919  i == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
3920  VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
3921  };
3922  VkSubresourceLayout layout = { 0 };
3923  vk->GetImageSubresourceLayout(hwctx->act_dev, dst_f->img[FFMIN(i, nb_images - 1)],
3924  &subres, &layout);
3925  offsets[i] = layout.offset;
3926  }
3927  }
3928 
3929  for (int i = 0; i < planes; i++) {
3930  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
3931  .offset = offsets[i],
3932  .arrayDesc = {
3933  .Depth = 0,
3934  .Format = cufmt,
3935  .NumChannels = desc->comp[i].step / elem_size,
3936  .Flags = 0,
3937  },
3938  .numLevels = 1,
3939  };
3940  int p_w, p_h;
3941 
3942  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3943  tex_desc.arrayDesc.Width = p_w;
3944  tex_desc.arrayDesc.Height = p_h;
3945 
3946  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
3947  dst_int->ext_mem[FFMIN(i, nb_images - 1)],
3948  &tex_desc));
3949  if (ret < 0) {
3950  err = AVERROR_EXTERNAL;
3951  goto fail;
3952  }
3953 
3954  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
3955  dst_int->cu_mma[i], 0));
3956  if (ret < 0) {
3957  err = AVERROR_EXTERNAL;
3958  goto fail;
3959  }
3960 
3961  }
3962  }
3963 
3964  return 0;
3965 
3966 fail:
3967  vulkan_free_internal(p, dst_f);
3968  return err;
3969 }
3970 
3971 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
3972  AVFrame *dst, const AVFrame *src)
3973 {
3974  int err;
3975  CUcontext dummy;
3976  AVVkFrame *dst_f;
3977  AVVkFrameInternal *dst_int;
3978  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
3979  VulkanFramesPriv *fp = hwfc->hwctx;
3980  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3982  int nb_images;
3983 
3984  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3985  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3986  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3987  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3988  CudaFunctions *cu = cu_internal->cuda_dl;
3989  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
3990  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
3991 
3992  dst_f = (AVVkFrame *)dst->data[0];
3993  nb_images = ff_vk_count_images(dst_f);
3994 
3995  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
3996  if (err < 0)
3997  return err;
3998 
3999  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4000  if (err < 0)
4001  return err;
4002 
4003  err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
4004  if (err < 0) {
4005  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4006  return err;
4007  }
4008 
4009  dst_int = dst_f->internal;
4010 
4011  for (int i = 0; i < nb_images; i++) {
4012  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4013  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4014  }
4015 
4016  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4017  nb_images, cuda_dev->stream));
4018  if (err < 0)
4019  goto fail;
4020 
4021  for (int i = 0; i < planes; i++) {
4022  CUDA_MEMCPY2D cpy = {
4023  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
4024  .srcDevice = (CUdeviceptr)src->data[i],
4025  .srcPitch = src->linesize[i],
4026  .srcY = 0,
4027 
4028  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
4029  .dstArray = dst_int->cu_array[i],
4030  };
4031 
4032  int p_w, p_h;
4033  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4034 
4035  cpy.WidthInBytes = p_w * desc->comp[i].step;
4036  cpy.Height = p_h;
4037 
4038  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4039  if (err < 0)
4040  goto fail;
4041  }
4042 
4043  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4044  nb_images, cuda_dev->stream));
4045  if (err < 0)
4046  goto fail;
4047 
4048  for (int i = 0; i < nb_images; i++)
4049  dst_f->sem_value[i]++;
4050 
4051  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4052 
4053  av_log(hwfc, AV_LOG_VERBOSE, "Transferred CUDA image to Vulkan!\n");
4054 
4055  return err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4056 
4057 fail:
4058  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4059  vulkan_free_internal(p, dst_f);
4060  av_buffer_unref(&dst->buf[0]);
4061  return err;
4062 }
4063 #endif
4064 
4066  const AVFrame *src, int flags)
4067 {
4069 
4070  switch (src->format) {
4071 #if CONFIG_LIBDRM
4072 #if CONFIG_VAAPI
4073  case AV_PIX_FMT_VAAPI:
4074  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4075  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
4076  else
4077  return AVERROR(ENOSYS);
4078 #endif
4079  case AV_PIX_FMT_DRM_PRIME:
4080  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4081  return vulkan_map_from_drm(hwfc, dst, src, flags);
4082  else
4083  return AVERROR(ENOSYS);
4084 #endif
4085  default:
4086  return AVERROR(ENOSYS);
4087  }
4088 }
4089 
4090 #if CONFIG_LIBDRM
4091 typedef struct VulkanDRMMapping {
4092  AVDRMFrameDescriptor drm_desc;
4093  AVVkFrame *source;
4094 } VulkanDRMMapping;
4095 
4096 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
4097 {
4098  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
4099 
4100  /* on unmap from DRM, make sure to import sync objects so that we are sync'd with any work that was
4101  * done on the buffer while exported. We don't know if who used the dmabuf did reads or writes, so protect against both */
4102  vulkan_map_from_drm_frame_sync(hwfc, hwmap->source, drm_desc, AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE);
4103 
4104  for (int i = 0; i < drm_desc->nb_objects; i++)
4105  close(drm_desc->objects[i].fd);
4106 
4107  av_free(drm_desc);
4108 }
4109 
4110 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
4111 {
4112  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
4113  if (vulkan_drm_format_map[i].vk_format == vkfmt)
4114  return vulkan_drm_format_map[i].drm_fourcc;
4115  return DRM_FORMAT_INVALID;
4116 }
4117 
4118 #define MAX_MEMORY_PLANES 4
4119 static VkImageAspectFlags plane_index_to_aspect(int plane) {
4120  if (plane == 0) return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4121  if (plane == 1) return VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
4122  if (plane == 2) return VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
4123  if (plane == 3) return VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
4124 
4125  av_assert2 (0 && "Invalid plane index");
4126  return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4127 }
4128 
4129 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4130 static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
4131  VulkanFramesPriv *fp, int nb_sems)
4132 {
4133  int sync_fd = -1;
4134  VkResult ret;
4135  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4136  AVVulkanDeviceContext *hwctx = &p->p;
4137  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4138 
4139  if (f->internal->drm_sync_sem == VK_NULL_HANDLE) {
4140  VkExportSemaphoreCreateInfo exp_info = {
4141  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
4142  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4143  };
4144  VkSemaphoreTypeCreateInfo type_info = {
4145  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
4146  .pNext = &exp_info,
4147  .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
4148  };
4149  VkSemaphoreCreateInfo sem_create = {
4150  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
4151  .pNext = &type_info,
4152  };
4153  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_create, hwctx->alloc,
4154  &f->internal->drm_sync_sem);
4155  if (ret != VK_SUCCESS) {
4156  av_log(hwctx, AV_LOG_ERROR, "Failed to create DRM export semaphore: %s\n",
4157  ff_vk_ret2str(ret));
4158  return AVERROR_EXTERNAL;
4159  }
4160  }
4161 
4162  /* Submit a lightweight exec that waits on the timeline semaphore
4163  * (true last operation on the frame) and signals the binary semaphore,
4164  * so any Vulkan frame can get a SYNC_FD regardless of origin. */
4165  FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
4166  if (ff_vk_exec_start(&p->vkctx, exec) >= 0) {
4167  for (int i = 0; i < nb_sems; i++)
4168  ff_vk_exec_add_dep_wait_sem(&p->vkctx, exec, f->sem[i],
4169  f->sem_value[i],
4170  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
4171  ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, &f->internal->drm_sync_sem, 1,
4172  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0);
4173  if (ff_vk_exec_submit(&p->vkctx, exec) >= 0) {
4174  VkSemaphoreGetFdInfoKHR get_fd_info = {
4175  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
4176  .semaphore = f->internal->drm_sync_sem,
4177  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4178  };
4179  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &get_fd_info, &sync_fd);
4180  if (ret != VK_SUCCESS) {
4181  av_log(hwctx, AV_LOG_WARNING,
4182  "Failed to get sync fd from DRM map export semaphore: %s\n",
4183  ff_vk_ret2str(ret));
4184  sync_fd = -1;
4185  }
4186  } else {
4187  ff_vk_exec_discard_deps(&p->vkctx, exec);
4188  }
4189  }
4190 
4191  return sync_fd;
4192 }
4193 #endif
4194 
4195 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
4196  const AVFrame *src, int flags)
4197 {
4198  int err = 0;
4199  VkResult ret;
4200  AVVkFrame *f = (AVVkFrame *)src->data[0];
4201  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4202  AVVulkanDeviceContext *hwctx = &p->p;
4203  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4204  VulkanFramesPriv *fp = hwfc->hwctx;
4205  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4206  const int nb_images = ff_vk_count_images(f);
4207  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
4208  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
4209  };
4210  const int nb_sems = nb_images;
4211  int free_drm_desc_on_err = 1;
4212  int sync_fd = -1;
4213 
4214  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
4215  if (!drm_desc)
4216  return AVERROR(ENOMEM);
4217 
4219  if (err < 0)
4220  goto end;
4221 
4222 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4223  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
4224  f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
4225  vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
4226  err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
4227  if (err < 0)
4228  goto end;
4229  sync_fd = err;
4230  err = 0;
4231  }
4232 #endif
4233 
4234  if (sync_fd < 0) {
4235  VkSemaphoreWaitInfo wait_info = {
4236  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4237  .flags = 0x0,
4238  .semaphoreCount = nb_sems,
4239  .pSemaphores = f->sem,
4240  .pValues = f->sem_value,
4241  };
4242  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
4243  }
4244 
4245  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
4246  if (err < 0)
4247  goto end;
4248 
4249  /* It will be freed in ff_hwframe_map_create callback */
4250  free_drm_desc_on_err = 0;
4251 
4252  ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
4253  &drm_mod);
4254  if (ret != VK_SUCCESS) {
4255  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
4256  err = AVERROR_EXTERNAL;
4257  goto end;
4258  }
4259 
4260  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
4261  VkMemoryGetFdInfoKHR export_info = {
4262  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
4263  .memory = f->mem[i],
4264  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
4265  };
4266 
4267  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
4268  &drm_desc->objects[i].fd);
4269  if (ret != VK_SUCCESS) {
4270  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
4271  err = AVERROR_EXTERNAL;
4272  goto end;
4273  }
4274 
4275 #if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
4276  if (sync_fd >= 0) {
4277  int dup_fd = dup(sync_fd);
4278  if (dup_fd >= 0) {
4279  struct dma_buf_import_sync_file import_info = {
4280  .flags = DMA_BUF_SYNC_WRITE,
4281  .fd = dup_fd,
4282  };
4283  if (ioctl(drm_desc->objects[i].fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_info) < 0)
4284  av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s\n", av_err2str(AVERROR(errno)));
4285  close(dup_fd);
4286  } else {
4287  av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
4288  }
4289  }
4290 #endif
4291 
4292  drm_desc->nb_objects++;
4293  drm_desc->objects[i].size = f->size[i];
4294  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
4295  }
4296 
4297  /* NV12 has 2 planes but 1 image/semaphore */
4298  drm_desc->nb_layers = FFMAX(planes, nb_images);
4299  for (int i = 0; i < drm_desc->nb_layers; i++) {
4300  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
4301 
4302  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
4303  drm_desc->layers[i].nb_planes = fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount;
4304 
4305  if (drm_desc->layers[i].nb_planes > MAX_MEMORY_PLANES) {
4306  av_log(hwfc, AV_LOG_ERROR, "Too many memory planes for DRM format!\n");
4307  err = AVERROR_EXTERNAL;
4308  goto end;
4309  }
4310 
4311  for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
4312  VkSubresourceLayout layout;
4313  int aspect_plane = (nb_images == 1) ? i : j;
4314  VkImageSubresource sub = {
4315  .aspectMask = plane_index_to_aspect(aspect_plane),
4316  };
4317 
4318  drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
4319 
4320  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[FFMIN(i, nb_images - 1)], &sub, &layout);
4321  drm_desc->layers[i].planes[j].offset = layout.offset;
4322  drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
4323  }
4324 
4325  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
4326  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
4327  err = AVERROR_PATCHWELCOME;
4328  goto end;
4329  }
4330 
4331 
4332  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
4333  continue;
4334 
4335  }
4336 
4337  dst->width = src->width;
4338  dst->height = src->height;
4339  dst->data[0] = (uint8_t *)drm_desc;
4340  dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
4341 
4342  if (sync_fd >= 0)
4343  close(sync_fd);
4344 
4345  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
4346 
4347  return 0;
4348 
4349 end:
4350  for (int i = 0; i < drm_desc->nb_objects; i++)
4351  close(drm_desc->objects[i].fd);
4352  if (free_drm_desc_on_err)
4353  av_free(drm_desc);
4354  if (sync_fd >= 0)
4355  close(sync_fd);
4356  return err;
4357 }
4358 
4359 #if CONFIG_VAAPI
4360 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
4361  const AVFrame *src, int flags)
4362 {
4363  int err;
4364  AVFrame *tmp = av_frame_alloc();
4365  if (!tmp)
4366  return AVERROR(ENOMEM);
4367 
4368  tmp->format = AV_PIX_FMT_DRM_PRIME;
4369 
4370  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
4371  if (err < 0)
4372  goto fail;
4373 
4374  err = av_hwframe_map(dst, tmp, flags);
4375  if (err < 0)
4376  goto fail;
4377 
4378  err = ff_hwframe_map_replace(dst, src);
4379 
4380 fail:
4381  av_frame_free(&tmp);
4382  return err;
4383 }
4384 #endif
4385 #endif
4386 
4388  const AVFrame *src, int flags)
4389 {
4391 
4392  switch (dst->format) {
4393 #if CONFIG_LIBDRM
4394  case AV_PIX_FMT_DRM_PRIME:
4395  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4396  return vulkan_map_to_drm(hwfc, dst, src, flags);
4397  else
4398  return AVERROR(ENOSYS);
4399 #if CONFIG_VAAPI
4400  case AV_PIX_FMT_VAAPI:
4401  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4402  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
4403  else
4404  return AVERROR(ENOSYS);
4405 #endif
4406 #endif
4407  default:
4408  break;
4409  }
4410  return AVERROR(ENOSYS);
4411 }
4412 
4414  AVFrame *swf, VkBufferImageCopy *region,
4415  int planes, int upload)
4416 {
4417  int err;
4418  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4419  FFVkBuffer *vkbuf = (FFVkBuffer *)buf->data;
4420 
4421  if (upload) {
4422  for (int i = 0; i < planes; i++)
4423  av_image_copy_plane(vkbuf->mapped_mem + region[i].bufferOffset,
4424  region[i].bufferRowLength,
4425  swf->data[i],
4426  swf->linesize[i],
4427  swf->linesize[i],
4428  region[i].imageExtent.height);
4429 
4430  err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 1);
4431  if (err != VK_SUCCESS) {
4432  av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n",
4433  av_err2str(err));
4434  return AVERROR_EXTERNAL;
4435  }
4436  } else {
4437  err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 0);
4438  if (err != VK_SUCCESS) {
4439  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n",
4440  av_err2str(err));
4441  return AVERROR_EXTERNAL;
4442  }
4443 
4444  for (int i = 0; i < planes; i++)
4445  av_image_copy_plane(swf->data[i],
4446  swf->linesize[i],
4447  vkbuf->mapped_mem + region[i].bufferOffset,
4448  region[i].bufferRowLength,
4449  swf->linesize[i],
4450  region[i].imageExtent.height);
4451  }
4452 
4453  return 0;
4454 }
4455 
4457  AVFrame *swf, VkBufferImageCopy *region, int upload)
4458 {
4459  int err;
4460  uint32_t p_w, p_h;
4461  VulkanFramesPriv *fp = hwfc->hwctx;
4462  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4463  const int planes = av_pix_fmt_count_planes(swf->format);
4464  VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4465  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4466 
4467  size_t buf_offset = 0;
4468  for (int i = 0; i < planes; i++) {
4469  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4470 
4471  region[i] = (VkBufferImageCopy) {
4472  .bufferOffset = buf_offset,
4473  .bufferRowLength = FFALIGN(swf->linesize[i],
4474  p->props.properties.limits.optimalBufferCopyRowPitchAlignment),
4475  .bufferImageHeight = p_h,
4476  .imageSubresource.layerCount = 1,
4477  .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4478  /* Rest of the fields adjusted/filled in later */
4479  };
4480 
4481  buf_offset += FFALIGN(p_h*region[i].bufferRowLength,
4482  p->props.properties.limits.optimalBufferCopyOffsetAlignment);
4483  }
4484 
4485  err = ff_vk_get_pooled_buffer(&p->vkctx, &fp->tmp, dst, buf_usage,
4486  NULL, buf_offset,
4487  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
4488  p->vkctx.host_cached_flag);
4489  if (err < 0)
4490  return err;
4491 
4492  return 0;
4493 }
4494 
4495 static int host_map_frame(AVHWFramesContext *hwfc, AVBufferRef **dst, int *nb_bufs,
4496  AVFrame *swf, VkBufferImageCopy *region, int upload)
4497 {
4498  int err;
4499  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4500 
4501  int nb_src_bufs;
4502  const int planes = av_pix_fmt_count_planes(swf->format);
4503  VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4504  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4505 
4506  /* We can't host map images with negative strides */
4507  for (int i = 0; i < planes; i++)
4508  if (swf->linesize[i] < 0)
4509  return AVERROR(EINVAL);
4510 
4511  /* Count the number of buffers in the software frame */
4512  nb_src_bufs = 0;
4513  while (swf->buf[nb_src_bufs])
4514  nb_src_bufs++;
4515 
4516  /* Single buffer contains all planes */
4517  if (nb_src_bufs == 1) {
4518  err = ff_vk_host_map_buffer(&p->vkctx, &dst[0],
4519  swf->data[0], swf->buf[0],
4520  buf_usage);
4521  if (err < 0)
4522  return err;
4523  (*nb_bufs)++;
4524 
4525  for (int i = 0; i < planes; i++)
4526  region[i].bufferOffset = ((FFVkBuffer *)dst[0]->data)->virtual_offset +
4527  swf->data[i] - swf->data[0];
4528  } else if (nb_src_bufs == planes) { /* One buffer per plane */
4529  for (int i = 0; i < planes; i++) {
4530  err = ff_vk_host_map_buffer(&p->vkctx, &dst[i],
4531  swf->data[i], swf->buf[i],
4532  buf_usage);
4533  if (err < 0)
4534  goto fail;
4535  (*nb_bufs)++;
4536 
4537  region[i].bufferOffset = ((FFVkBuffer *)dst[i]->data)->virtual_offset;
4538  }
4539  } else {
4540  /* Weird layout (3 planes, 2 buffers), patch welcome, fallback to copy */
4541  return AVERROR_PATCHWELCOME;
4542  }
4543 
4544  return 0;
4545 
4546 fail:
4547  for (int i = 0; i < (*nb_bufs); i++)
4548  av_buffer_unref(&dst[i]);
4549  return err;
4550 }
4551 
4553  AVFrame *swf, int upload)
4554 {
4555  VulkanFramesPriv *fp = hwfc->hwctx;
4556  AVVulkanFramesContext *hwfc_vk = &fp->p;
4557  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4558  AVVulkanDeviceContext *hwctx = &p->p;
4559  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4560 
4561  AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4563  const int planes = av_pix_fmt_count_planes(swf->format);
4564  const int nb_images = ff_vk_count_images(hwf_vk);
4565 
4566  VkSemaphoreWaitInfo sem_wait;
4567  VkHostImageLayoutTransitionInfoEXT layout_ch_info[AV_NUM_DATA_POINTERS];
4568  int nb_layout_ch = 0;
4569 
4570  hwfc_vk->lock_frame(hwfc, hwf_vk);
4571 
4572  for (int i = 0; i < nb_images; i++) {
4573  int compat = 0;
4574  for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount; j++) {
4575  if (hwf_vk->layout[i] == p->vkctx.host_image_props.pCopySrcLayouts[j]) {
4576  compat = 1;
4577  break;
4578  }
4579  }
4580  if (compat)
4581  continue;
4582 
4583  layout_ch_info[nb_layout_ch] = (VkHostImageLayoutTransitionInfoEXT) {
4584  .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
4585  .image = hwf_vk->img[i],
4586  .oldLayout = hwf_vk->layout[i],
4587  .newLayout = VK_IMAGE_LAYOUT_GENERAL,
4588  .subresourceRange = {
4589  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4590  .levelCount = 1,
4591  .layerCount = 1,
4592  },
4593  };
4594 
4595  hwf_vk->layout[i] = layout_ch_info[nb_layout_ch].newLayout;
4596  nb_layout_ch++;
4597  }
4598 
4599  sem_wait = (VkSemaphoreWaitInfo) {
4600  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4601  .pSemaphores = hwf_vk->sem,
4602  .pValues = hwf_vk->sem_value,
4603  .semaphoreCount = nb_images,
4604  };
4605 
4606  vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
4607 
4608  if (nb_layout_ch)
4609  vk->TransitionImageLayoutEXT(hwctx->act_dev,
4610  nb_layout_ch, layout_ch_info);
4611 
4612  if (upload) {
4613  VkMemoryToImageCopyEXT region_info = {
4614  .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
4615  .imageSubresource = {
4616  .layerCount = 1,
4617  },
4618  };
4619  VkCopyMemoryToImageInfoEXT copy_info = {
4620  .sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
4621  .regionCount = 1,
4622  .pRegions = &region_info,
4623  };
4624  for (int i = 0; i < planes; i++) {
4625  int img_idx = FFMIN(i, (nb_images - 1));
4626  uint32_t p_w, p_h;
4627  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4628 
4629  region_info.pHostPointer = swf->data[i];
4630  region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4631  region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4632  region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4633  copy_info.dstImage = hwf_vk->img[img_idx];
4634  copy_info.dstImageLayout = hwf_vk->layout[img_idx];
4635 
4636  vk->CopyMemoryToImageEXT(hwctx->act_dev, &copy_info);
4637  }
4638  } else {
4639  VkImageToMemoryCopyEXT region_info = {
4640  .sType = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT,
4641  .imageSubresource = {
4642  .layerCount = 1,
4643  },
4644  };
4645  VkCopyImageToMemoryInfoEXT copy_info = {
4646  .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
4647  .regionCount = 1,
4648  .pRegions = &region_info,
4649  };
4650  for (int i = 0; i < planes; i++) {
4651  int img_idx = FFMIN(i, (nb_images - 1));
4652  uint32_t p_w, p_h;
4653  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4654 
4655  region_info.pHostPointer = swf->data[i];
4656  region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4657  region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4658  region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4659  copy_info.srcImage = hwf_vk->img[img_idx];
4660  copy_info.srcImageLayout = hwf_vk->layout[img_idx];
4661 
4662  vk->CopyImageToMemoryEXT(hwctx->act_dev, &copy_info);
4663  }
4664  }
4665 
4666  hwfc_vk->unlock_frame(hwfc, hwf_vk);
4667 
4668  return 0;
4669 }
4670 
4672  AVFrame *swf, AVFrame *hwf,
4673  int upload)
4674 {
4675  int err;
4676  VulkanFramesPriv *fp = hwfc->hwctx;
4677  AVVulkanFramesContext *hwctx = &fp->p;
4678  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4679  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4680 
4681  int host_mapped = 0;
4682 
4683  AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4684  VkBufferImageCopy region[AV_NUM_DATA_POINTERS]; // always one per plane
4685 
4686  const int planes = av_pix_fmt_count_planes(swf->format);
4688  const int nb_images = ff_vk_count_images(hwf_vk);
4689 
4690  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
4691  int nb_img_bar = 0;
4692 
4694  int nb_bufs = 0;
4695 
4696  VkCommandBuffer cmd_buf;
4697  FFVkExecContext *exec;
4698 
4699  /* Sanity checking */
4700  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
4701  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
4702  return AVERROR(EINVAL);
4703  }
4704 
4705  if (swf->width > hwfc->width || swf->height > hwfc->height)
4706  return AVERROR(EINVAL);
4707 
4708  if (hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
4709  !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY))
4710  return vulkan_transfer_host(hwfc, hwf, swf, upload);
4711 
4712  for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
4713  uint32_t p_w, p_h;
4714  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4715 
4716  /* Buffer region for this plane */
4717  region[i] = (VkBufferImageCopy) {
4718  .bufferOffset = 0,
4719  .bufferRowLength = swf->linesize[i],
4720  .bufferImageHeight = p_h,
4721  .imageSubresource.layerCount = 1,
4722  .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4723  /* Rest of the fields adjusted/filled in later */
4724  };
4725  }
4726 
4727  /* Setup buffers first */
4728  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY && !p->avoid_host_import) {
4729  err = host_map_frame(hwfc, bufs, &nb_bufs, swf, region, upload);
4730  if (err >= 0)
4731  host_mapped = 1;
4732  }
4733 
4734  if (!host_mapped) {
4735  err = get_plane_buf(hwfc, &bufs[0], swf, region, upload);
4736  if (err < 0)
4737  goto end;
4738  nb_bufs = 1;
4739 
4740  if (upload) {
4741  err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 1);
4742  if (err < 0)
4743  goto end;
4744  }
4745  }
4746 
4747  exec = ff_vk_exec_get(&p->vkctx, &fp->upload_exec);
4748  cmd_buf = exec->buf;
4749 
4750  ff_vk_exec_start(&p->vkctx, exec);
4751 
4752  /* Prep destination Vulkan frame */
4753  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, hwf,
4754  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4755  VK_PIPELINE_STAGE_2_TRANSFER_BIT);
4756  if (err < 0)
4757  goto end;
4758 
4759  /* No need to declare buf deps for synchronous transfers (downloads) */
4760  if (upload) {
4761  /* Add the software frame backing the buffers if we're host mapping */
4762  if (host_mapped) {
4763  err = ff_vk_exec_add_dep_sw_frame(&p->vkctx, exec, swf);
4764  if (err < 0) {
4765  ff_vk_exec_discard_deps(&p->vkctx, exec);
4766  goto end;
4767  }
4768  }
4769 
4770  /* Add the buffers as a dependency */
4771  err = ff_vk_exec_add_dep_buf(&p->vkctx, exec, bufs, nb_bufs, 1);
4772  if (err < 0) {
4773  ff_vk_exec_discard_deps(&p->vkctx, exec);
4774  goto end;
4775  }
4776  }
4777 
4778  ff_vk_frame_barrier(&p->vkctx, exec, hwf, img_bar, &nb_img_bar,
4779  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4780  VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
4781  upload ? VK_ACCESS_TRANSFER_WRITE_BIT :
4782  VK_ACCESS_TRANSFER_READ_BIT,
4783  upload ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL :
4784  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4785  p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
4786 
4787  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
4788  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
4789  .pImageMemoryBarriers = img_bar,
4790  .imageMemoryBarrierCount = nb_img_bar,
4791  });
4792 
4793  for (int i = 0; i < planes; i++) {
4794  int buf_idx = FFMIN(i, (nb_bufs - 1));
4795  int img_idx = FFMIN(i, (nb_images - 1));
4796  FFVkBuffer *vkbuf = (FFVkBuffer *)bufs[buf_idx]->data;
4797 
4798  uint32_t orig_stride = region[i].bufferRowLength;
4799  region[i].bufferRowLength /= desc->comp[i].step;
4800  region[i].imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4801 
4802  if (upload)
4803  vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf,
4804  hwf_vk->img[img_idx],
4805  img_bar[img_idx].newLayout,
4806  1, &region[i]);
4807  else
4808  vk->CmdCopyImageToBuffer(cmd_buf, hwf_vk->img[img_idx],
4809  img_bar[img_idx].newLayout,
4810  vkbuf->buf,
4811  1, &region[i]);
4812 
4813  region[i].bufferRowLength = orig_stride;
4814  }
4815 
4816  err = ff_vk_exec_submit(&p->vkctx, exec);
4817  if (err < 0) {
4818  ff_vk_exec_discard_deps(&p->vkctx, exec);
4819  } else if (!upload) {
4820  ff_vk_exec_wait(&p->vkctx, exec);
4821  if (!host_mapped)
4822  err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 0);
4823  }
4824 
4825 end:
4826  for (int i = 0; i < nb_bufs; i++)
4827  av_buffer_unref(&bufs[i]);
4828 
4829  return err;
4830 }
4831 
4833  const AVFrame *src)
4834 {
4836 
4837  switch (src->format) {
4838 #if CONFIG_CUDA
4839  case AV_PIX_FMT_CUDA:
4840 #ifdef _WIN32
4841  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4842  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4843 #else
4844  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4845  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4846 #endif
4847  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
4849 #endif
4850  default:
4851  if (src->hw_frames_ctx)
4852  return AVERROR(ENOSYS);
4853  else
4854  return vulkan_transfer_frame(hwfc, (AVFrame *)src, dst, 1);
4855  }
4856 }
4857 
4858 #if CONFIG_CUDA
4859 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
4860  const AVFrame *src)
4861 {
4862  int err;
4863  CUcontext dummy;
4864  AVVkFrame *dst_f;
4865  AVVkFrameInternal *dst_int;
4866  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4867  VulkanFramesPriv *fp = hwfc->hwctx;
4868  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4870  int nb_images;
4871 
4872  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)dst->hw_frames_ctx->data;
4873  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4874  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4875  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4876  CudaFunctions *cu = cu_internal->cuda_dl;
4877  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4878  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4879 
4880  dst_f = (AVVkFrame *)src->data[0];
4881  nb_images = ff_vk_count_images(dst_f);
4882 
4883  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4884  if (err < 0)
4885  return err;
4886 
4887  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4888  if (err < 0)
4889  return err;
4890 
4891  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
4892  if (err < 0) {
4893  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4894  return err;
4895  }
4896 
4897  dst_int = dst_f->internal;
4898 
4899  for (int i = 0; i < nb_images; i++) {
4900  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4901  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4902  }
4903 
4904  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4905  nb_images, cuda_dev->stream));
4906  if (err < 0)
4907  goto fail;
4908 
4909  for (int i = 0; i < planes; i++) {
4910  CUDA_MEMCPY2D cpy = {
4911  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
4912  .dstDevice = (CUdeviceptr)dst->data[i],
4913  .dstPitch = dst->linesize[i],
4914  .dstY = 0,
4915 
4916  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
4917  .srcArray = dst_int->cu_array[i],
4918  };
4919 
4920  int w, h;
4921  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4922 
4923  cpy.WidthInBytes = w * desc->comp[i].step;
4924  cpy.Height = h;
4925 
4926  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4927  if (err < 0)
4928  goto fail;
4929  }
4930 
4931  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4932  nb_images, cuda_dev->stream));
4933  if (err < 0)
4934  goto fail;
4935 
4936  for (int i = 0; i < nb_images; i++)
4937  dst_f->sem_value[i]++;
4938 
4939  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4940 
4941  av_log(hwfc, AV_LOG_VERBOSE, "Transferred Vulkan image to CUDA!\n");
4942 
4943  return prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4944 
4945 fail:
4946  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4947  vulkan_free_internal(p, dst_f);
4948  av_buffer_unref(&dst->buf[0]);
4949  return err;
4950 }
4951 #endif
4952 
4954  const AVFrame *src)
4955 {
4957 
4958  switch (dst->format) {
4959 #if CONFIG_CUDA
4960  case AV_PIX_FMT_CUDA:
4961 #ifdef _WIN32
4962  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4963  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4964 #else
4965  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4966  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4967 #endif
4968  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
4970 #endif
4971  default:
4972  if (dst->hw_frames_ctx)
4973  return AVERROR(ENOSYS);
4974  else
4975  return vulkan_transfer_frame(hwfc, dst, (AVFrame *)src, 0);
4976  }
4977 }
4978 
4980  AVHWFramesContext *src_fc, int flags)
4981 {
4982  return vulkan_frames_init(dst_fc);
4983 }
4984 
4986 {
4987  int err;
4988  AVVkFrame *f = av_mallocz(sizeof(AVVkFrame));
4989  if (!f)
4990  return NULL;
4991 
4992  f->internal = av_mallocz(sizeof(*f->internal));
4993  if (!f->internal) {
4994  av_free(f);
4995  return NULL;
4996  }
4997 
4998  err = pthread_mutex_init(&f->internal->update_mutex, NULL);
4999  if (err != 0) {
5000  av_free(f->internal);
5001  av_free(f);
5002  return NULL;
5003  }
5004 
5005  return f;
5006 }
5007 
5010  .name = "Vulkan",
5011 
5012  .device_hwctx_size = sizeof(VulkanDevicePriv),
5013  .frames_hwctx_size = sizeof(VulkanFramesPriv),
5014 
5015  .device_init = &vulkan_device_init,
5016  .device_uninit = &vulkan_device_uninit,
5017  .device_create = &vulkan_device_create,
5018  .device_derive = &vulkan_device_derive,
5019 
5020  .frames_get_constraints = &vulkan_frames_get_constraints,
5021  .frames_init = vulkan_frames_init,
5022  .frames_get_buffer = vulkan_get_buffer,
5023  .frames_uninit = vulkan_frames_uninit,
5024 
5025  .transfer_get_formats = vulkan_transfer_get_formats,
5026  .transfer_data_to = vulkan_transfer_data_to,
5027  .transfer_data_from = vulkan_transfer_data_from,
5028 
5029  .map_to = vulkan_map_to,
5030  .map_from = vulkan_map_from,
5031  .frames_derive_to = &vulkan_frames_derive_to,
5032 
5033  .pix_fmts = (const enum AVPixelFormat []) {
5036  },
5037 };
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:4495
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:4832
FF_VK_EXT_EXTERNAL_WIN32_MEMORY
#define FF_VK_EXT_EXTERNAL_WIN32_MEMORY
Definition: vulkan_functions.h:39
FF_VK_EXT_VIDEO_QUEUE
#define FF_VK_EXT_VIDEO_QUEUE
Definition: vulkan_functions.h:59
thread.h
vk_dbg_callback
static VKAPI_ATTR VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *data, void *priv)
Definition: hwcontext_vulkan.c:791
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
pthread_mutex_init
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition: os2threads.h:104
ff_vk_exec_pool_init
int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext)
Allocates/frees an execution pool.
Definition: vulkan.c:357
FF_VK_EXT_PORTABILITY_SUBSET
#define FF_VK_EXT_PORTABILITY_SUBSET
Definition: vulkan_functions.h:74
vulkan_frames_get_constraints
static int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
Definition: hwcontext_vulkan.c:2204
FF_VK_EXT_VIDEO_MAINTENANCE_2
#define FF_VK_EXT_VIDEO_MAINTENANCE_2
Definition: vulkan_functions.h:61
AVVkFrameInternal::update_mutex
pthread_mutex_t update_mutex
Definition: hwcontext_vulkan.c:203
vulkan_frames_derive_to
static int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags)
Definition: hwcontext_vulkan.c:4979
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:2652
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:2476
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:4387
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:2472
FF_VK_EXT_EXTERNAL_FD_SEM
#define FF_VK_EXT_EXTERNAL_FD_SEM
Definition: vulkan_functions.h:35
VulkanDeviceFeatures::device
VkPhysicalDeviceFeatures2 device
Definition: hwcontext_vulkan.c:76
VulkanDeviceFeatures::video_maintenance_1
VkPhysicalDeviceVideoMaintenance1FeaturesKHR video_maintenance_1
Definition: hwcontext_vulkan.c:102
close
static av_cold void close(AVCodecParserContext *s)
Definition: apv_parser.c:197
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3496
ASPECT_3PLANE
#define ASPECT_3PLANE
Definition: hwcontext_vulkan.c:414
FF_VK_EXT_LONG_VECTOR
#define FF_VK_EXT_LONG_VECTOR
Definition: vulkan_functions.h:55
VulkanDevicePriv::hprops
VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
Definition: hwcontext_vulkan.c:142
vulkan_device_derive
static int vulkan_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:2101
VulkanOptExtension::flag
FFVulkanExtensions flag
Definition: hwcontext_vulkan.c:690
AVVulkanDeviceContext::alloc
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
Definition: hwcontext_vulkan.h:63
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:560
AVVkFrame::img
VkImage img[AV_NUM_DATA_POINTERS]
Vulkan images to which the memory is bound to.
Definition: hwcontext_vulkan.h:266
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:212
VulkanDeviceSelection::drm_minor
uint32_t drm_minor
Definition: hwcontext_vulkan.c:1329
AVVulkanDeviceContext::lock_queue
attribute_deprecated void(* lock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
Locks a queue, preventing other threads from submitting any command buffers to this queue.
Definition: hwcontext_vulkan.h:129
lock_frame
static void lock_frame(AVHWFramesContext *fc, AVVkFrame *vkf)
Definition: hwcontext_vulkan.c:2913
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:2511
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:4065
av_dict_get
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:60
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:390
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:562
AVHWFramesContext::pool
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:181
VulkanDeviceSelection::pci_device
uint32_t pci_device
Definition: hwcontext_vulkan.c:1332
AV_PIX_FMT_GBRAP14
#define AV_PIX_FMT_GBRAP14
Definition: pixfmt.h:564
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:563
AV_PIX_FMT_YUVA420P
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:108
AV_PIX_FMT_RGB96
#define AV_PIX_FMT_RGB96
Definition: pixfmt.h:629
pthread_mutex_unlock
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
Definition: os2threads.h:126
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:552
offsets
static const int offsets[]
Definition: hevc_pel.c:34
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:60
ff_vk_load_functions
static int ff_vk_load_functions(AVHWDeviceContext *ctx, FFVulkanFunctions *vk, uint64_t extensions_mask, int has_inst, int has_dev)
Function loader.
Definition: vulkan_loader.h:131
VulkanDevicePriv::ext_sem_props_opaque
VkExternalSemaphoreProperties ext_sem_props_opaque
Definition: hwcontext_vulkan.c:146
prepare_frame
static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
Definition: hwcontext_vulkan.c:2619
vulkan_transfer_frame
static int vulkan_transfer_frame(AVHWFramesContext *hwfc, AVFrame *swf, AVFrame *hwf, int upload)
Definition: hwcontext_vulkan.c:4671
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:2923
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:3186
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
VulkanDevicePriv::avoid_host_import
int avoid_host_import
Definition: hwcontext_vulkan.c:170
ff_vk_exec_pool_free
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition: vulkan.c:299
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
FFVulkanDebugMode
FFVulkanDebugMode
Definition: hwcontext_vulkan.c:864
AV_PIX_FMT_GRAYF32
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:582
LIBAVUTIL_VERSION_MINOR
#define LIBAVUTIL_VERSION_MINOR
Definition: version.h:82
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
FFVkFormatEntry::nb_images_fallback
int nb_images_fallback
Definition: hwcontext_vulkan.c:422
vulkan_frame_free_cb
static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
Definition: hwcontext_vulkan.c:2386
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:2468
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:5008
AV_DRM_MAX_PLANES
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
Definition: hwcontext_drm.h:39
hwcontext_vulkan.h
AVVulkanDeviceContext::enabled_inst_extensions
const char *const * enabled_inst_extensions
Enabled instance extensions.
Definition: hwcontext_vulkan.h:103
vk_formats_list
static const struct FFVkFormatEntry vk_formats_list[]
AVVulkanFramesContext::format
VkFormat format[AV_NUM_DATA_POINTERS]
Vulkan format for each image.
Definition: hwcontext_vulkan.h:232
AVVulkanFramesContext::usage
VkImageUsageFlagBits usage
Defines extra usage of output frames.
Definition: hwcontext_vulkan.h:191
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:265
AV_PIX_FMT_YUV422P10
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:540
alloc_bind_mem
static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, void *alloc_pnext, size_t alloc_pnext_stride)
Definition: hwcontext_vulkan.c:2391
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:2352
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:2471
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:2834
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:2466
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:4985
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:4953
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:467
FF_VK_EXT_PUSH_DESCRIPTOR
#define FF_VK_EXT_PUSH_DESCRIPTOR
Definition: vulkan_functions.h:47
VulkanDevicePriv::use_linear_images
int use_linear_images
Definition: hwcontext_vulkan.c:161
AV_PIX_FMT_YUV444P12
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:546
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:553
AV_PIX_FMT_NV16
@ AV_PIX_FMT_NV16
interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:198
planes
static const struct @602 planes[]
VulkanDeviceSelection::vendor_id
uint32_t vendor_id
Definition: hwcontext_vulkan.c:1333
PREP_MODE_GENERAL
@ PREP_MODE_GENERAL
Definition: hwcontext_vulkan.c:2467
AV_PIX_FMT_Y212
#define AV_PIX_FMT_Y212
Definition: pixfmt.h:607
AVDRMObjectDescriptor::size
size_t size
Total size of the object.
Definition: hwcontext_drm.h:58
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:174
VulkanFramesPriv::upload_exec
FFVkExecPool upload_exec
Definition: hwcontext_vulkan.c:186
AVVulkanDeviceQueueFamily::idx
int idx
Definition: hwcontext_vulkan.h:35
AV_PIX_FMT_YUVA444P10
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:592
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
AVHWFramesConstraints::max_width
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:469
FFVkExecContext
Definition: vulkan.h:145
VulkanOptExtension
Definition: hwcontext_vulkan.c:688
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:263
AV_PIX_FMT_P216
#define AV_PIX_FMT_P216
Definition: pixfmt.h:620
CHECK_CU
#define CHECK_CU(x)
Definition: cuviddec.c:117
AV_PIX_FMT_P210
#define AV_PIX_FMT_P210
Definition: pixfmt.h:616
AV_PIX_FMT_VAAPI
@ AV_PIX_FMT_VAAPI
Hardware acceleration through VA-API, data[3] contains a VASurfaceID.
Definition: pixfmt.h:126
VulkanDeviceFeatures::subgroup_rotate
VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR subgroup_rotate
Definition: hwcontext_vulkan.c:82
FF_VK_EXT_VIDEO_DECODE_QUEUE
#define FF_VK_EXT_VIDEO_DECODE_QUEUE
Definition: vulkan_functions.h:63
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
VulkanDeviceFeatures::timeline_semaphore
VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore
Definition: hwcontext_vulkan.c:81
AV_HWDEVICE_TYPE_VAAPI
@ AV_HWDEVICE_TYPE_VAAPI
Definition: hwcontext.h:31
pthread_mutex_destroy
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition: os2threads.h:112
layout
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel layout
Definition: filter_design.txt:18
FF_VK_EXT_EXTERNAL_HOST_MEMORY
#define FF_VK_EXT_EXTERNAL_HOST_MEMORY
Definition: vulkan_functions.h:36
FF_VK_EXT_INTERNAL_QUEUE_SYNC
#define FF_VK_EXT_INTERNAL_QUEUE_SYNC
Definition: vulkan_functions.h:56
FF_VK_EXT_EXPLICIT_MEM_LAYOUT
#define FF_VK_EXT_EXPLICIT_MEM_LAYOUT
Definition: vulkan_functions.h:53
AVDRMFrameDescriptor::objects
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
Definition: hwcontext_drm.h:141
AVCUDADeviceContextInternal::cuda_dl
CudaFunctions * cuda_dl
Definition: hwcontext_cuda_internal.h:32
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:68
ff_vk_exec_start
int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e)
Start/submit/wait an execution.
Definition: vulkan.c:580
FF_VK_EXT_RELAXED_EXTENDED_INSTR
#define FF_VK_EXT_RELAXED_EXTENDED_INSTR
Definition: vulkan_functions.h:48
FF_VK_EXT_VIDEO_DECODE_H264
#define FF_VK_EXT_VIDEO_DECODE_H264
Definition: vulkan_functions.h:64
VulkanFramesPriv::compute_exec
FFVkExecPool compute_exec
Definition: hwcontext_vulkan.c:183
AVDRMObjectDescriptor::format_modifier
uint64_t format_modifier
Format modifier applied to the object (DRM_FORMAT_MOD_*).
Definition: hwcontext_drm.h:65
VkFormat
enum VkFormat VkFormat
Definition: hwcontext_stub.c:25
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:559
weights
static const int weights[]
Definition: hevc_pel.c:32
AV_PIX_FMT_NV24
@ AV_PIX_FMT_NV24
planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:371
plane_info
Definition: vf_edgedetect.c:53
VulkanDevicePriv::nb_img_qfs
uint32_t nb_img_qfs
Definition: hwcontext_vulkan.c:155
s
uint8_t s
Definition: llvidencdsp.c:39
vulkan_frames_init
static int vulkan_frames_init(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:2941
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AV_PIX_FMT_X2RGB10
#define AV_PIX_FMT_X2RGB10
Definition: pixfmt.h:613
VulkanDeviceSelection::has_uuid
int has_uuid
Definition: hwcontext_vulkan.c:1327
hwcontext_drm.h
AV_HWFRAME_MAP_WRITE
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition: hwcontext.h:519
AVDRMPlaneDescriptor::object_index
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor.
Definition: hwcontext_drm.h:79
ff_hwframe_map_replace
int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src)
Replace the current hwmap of dst with the one from src, used for indirect mappings like VAAPI->(DRM)-...
Definition: hwcontext.c:948
VulkanDevicePriv::img_qfs
uint32_t img_qfs[64]
Definition: hwcontext_vulkan.c:154
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
mod
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:755
AV_PIX_FMT_P016
#define AV_PIX_FMT_P016
Definition: pixfmt.h:604
AVHWFrameTransferDirection
AVHWFrameTransferDirection
Definition: hwcontext.h:406
AVVkFrame::sem
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization timeline semaphores, one for each VkImage.
Definition: hwcontext_vulkan.h:299
create_instance
static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts, enum FFVulkanDebugMode *debug_mode)
Definition: hwcontext_vulkan.c:1188
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
FF_VK_EXT_EXTERNAL_FD_MEMORY
#define FF_VK_EXT_EXTERNAL_FD_MEMORY
Definition: vulkan_functions.h:34
AVCUDADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_cuda.h:42
hwcontext_vaapi.h
AVDRMLayerDescriptor::format
uint32_t format
Format of the layer (DRM_FORMAT_*).
Definition: hwcontext_drm.h:100
VulkanDevicePriv::transfer_qf
AVVulkanDeviceQueueFamily * transfer_qf
Definition: hwcontext_vulkan.c:137
ret
ret
Definition: filter_design.txt:187
pixfmt
enum AVPixelFormat pixfmt
Definition: kmsgrab.c:367
AVHWDeviceContext::type
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:75
AV_PIX_FMT_NV12
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:96
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
AVHWFramesContext::device_ctx
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:137
FFVulkanContext::vkfn
FFVulkanFunctions vkfn
Definition: vulkan.h:316
cuda_check.h
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:153
VulkanFramesPriv::tmp
AVBufferPool * tmp
Definition: hwcontext_vulkan.c:190
vulkan_get_buffer
static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
Definition: hwcontext_vulkan.c:3172
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:4552
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:2473
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:2574
LIBAVUTIL_VERSION_MICRO
#define LIBAVUTIL_VERSION_MICRO
Definition: version.h:83
AV_PIX_FMT_GBRAPF16
#define AV_PIX_FMT_GBRAPF16
Definition: pixfmt.h:577
find_device
static int find_device(AVHWDeviceContext *ctx, VulkanDeviceSelection *select)
Definition: hwcontext_vulkan.c:1349
FF_VK_STRUCT_EXT
#define FF_VK_STRUCT_EXT(CTX, BASE, STRUCT_P, EXT_FLAG, TYPE)
Definition: vulkan.h:397
optional_instance_exts
static const VulkanOptExtension optional_instance_exts[]
Definition: hwcontext_vulkan.c:693
AV_PIX_FMT_FLAG_PLANAR
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:132
ff_vk_map_feats_to_usage
VkImageUsageFlags ff_vk_map_feats_to_usage(VkFormatFeatureFlagBits2 feats)
Map between usage and features.
FF_VK_EXT_ATOMIC_FLOAT
#define FF_VK_EXT_ATOMIC_FLOAT
Definition: vulkan_functions.h:43
FFVkFormatEntry::fallback
const VkFormat fallback[5]
Definition: hwcontext_vulkan.c:423
AV_HWFRAME_MAP_READ
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition: hwcontext.h:515
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
PREP_MODE_EXTERNAL_IMPORT
@ PREP_MODE_EXTERNAL_IMPORT
Definition: hwcontext_vulkan.c:2470
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:4456
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:2918
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:2635
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:2469
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:4413
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:2762