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