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