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