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  av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
2886  i, has_mods ? (unsigned long long)phy_dev_mod_info.drmFormatModifier : 0ULL,
2887  ret == VK_SUCCESS ? "OK" : "FAIL");
2888  if (ret == VK_SUCCESS) {
2889  *iexp |= exp;
2890  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2891  if (exp == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
2892  VulkanFramesPriv *fp = hwfc->hwctx;
2893  fp->export_requires_dedicated = !!(eprops.externalMemoryProperties.externalMemoryFeatures &
2894  VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
2895  }
2896  }
2897  }
2898 }
2899 
2900 static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2901 {
2902  int err;
2903  AVVkFrame *f;
2904  AVBufferRef *avbuf = NULL;
2905  AVHWFramesContext *hwfc = opaque;
2906  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2907  VulkanFramesPriv *fp = hwfc->hwctx;
2908  AVVulkanFramesContext *hwctx = &fp->p;
2909  VkExternalMemoryHandleTypeFlags e = 0x0;
2910  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2911 
2912  VkExternalMemoryImageCreateInfo eiinfo = {
2913  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2914  .pNext = hwctx->create_pnext,
2915  };
2916 
2917 #ifdef _WIN32
2918  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2919  try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2920  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2921  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2922 #else
2923  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
2924  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
2925  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2926  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2927 
2928  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_DMABUF_MEMORY &&
2929  hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
2930  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2931  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2932 #endif
2933 
2934  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2935  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2936  eminfo[i].pNext = hwctx->alloc_pnext[i];
2937  eminfo[i].handleTypes = e;
2938  }
2939 
2940  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
2941  hwctx->nb_layers,
2942  eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
2943  if (err) {
2944  av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed: create_frame failed: %d\n", err);
2945  return NULL;
2946  }
2947 
2948  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2949  if (err)
2950  goto fail;
2951 
2952  if ( (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2953  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR))
2954  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DPB);
2955  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)
2956  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DST);
2957  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR)
2958  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_ENCODING_DPB);
2959  else if (hwctx->usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
2960  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_WRITE);
2961  else
2962  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_GENERAL);
2963  if (err)
2964  goto fail;
2965 
2966  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2967  vulkan_frame_free_cb, hwfc, 0);
2968  if (!avbuf)
2969  goto fail;
2970 
2971  return avbuf;
2972 
2973 fail:
2974  av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed with error %d\n", err);
2975  vulkan_frame_free(hwfc, f);
2976  return NULL;
2977 }
2978 
2980 {
2982 }
2983 
2985 {
2987 }
2988 
2990 {
2991  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
2992  VulkanFramesPriv *fp = hwfc->hwctx;
2993 
2994  if (fp->modifier_info) {
2995  if (fp->modifier_info->pDrmFormatModifiers)
2996  av_freep(&fp->modifier_info->pDrmFormatModifiers);
2997  av_freep(&fp->modifier_info);
2998  }
2999 
3000  ff_vk_exec_pool_free(&p->vkctx, &fp->compute_exec);
3001  ff_vk_exec_pool_free(&p->vkctx, &fp->upload_exec);
3002  ff_vk_exec_pool_free(&p->vkctx, &fp->download_exec);
3003 
3004  av_buffer_pool_uninit(&fp->tmp);
3005 }
3006 
3008 {
3009  int err;
3010  AVVkFrame *f;
3011  VulkanFramesPriv *fp = hwfc->hwctx;
3012  AVVulkanFramesContext *hwctx = &fp->p;
3013  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
3014  AVVulkanDeviceContext *dev_hwctx = &p->p;
3015  VkImageUsageFlags supported_usage;
3016  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3017  const struct FFVkFormatEntry *fmt;
3018  int disable_multiplane = p->disable_multiplane ||
3020  int is_lone_dpb = ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR) ||
3021  ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
3022  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)));
3023 
3024  /* Defaults */
3025  if (!hwctx->nb_layers)
3026  hwctx->nb_layers = 1;
3027 
3028  /* VK_IMAGE_TILING_OPTIMAL == 0, can't check for it really */
3029  if (p->use_linear_images &&
3030  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
3031  hwctx->tiling = VK_IMAGE_TILING_LINEAR;
3032 
3033 
3034  fmt = vk_find_format_entry(hwfc->sw_format);
3035  if (!fmt) {
3036  av_log(hwfc, AV_LOG_ERROR, "Unsupported pixel format: %s!\n",
3038  return AVERROR(ENOTSUP);
3039  }
3040 
3041  if (hwctx->format[0] != VK_FORMAT_UNDEFINED) {
3042  if (hwctx->format[0] != fmt->vkf) {
3043  for (int i = 0; i < fmt->nb_images_fallback; i++) {
3044  if (hwctx->format[i] != fmt->fallback[i]) {
3045  av_log(hwfc, AV_LOG_ERROR, "Incompatible Vulkan format given "
3046  "for the current sw_format %s!\n",
3048  return AVERROR(EINVAL);
3049  }
3050  }
3051  }
3052 
3053  /* Check if the sw_format itself is supported */
3054  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3055  hwctx->tiling, NULL,
3056  NULL, NULL, &supported_usage, 0,
3057  !hwctx->usage ||
3058  (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3059  if (err < 0) {
3060  av_log(hwfc, AV_LOG_ERROR, "Unsupported sw format: %s!\n",
3062  return AVERROR(EINVAL);
3063  }
3064  } else {
3065  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
3066  hwctx->tiling, hwctx->format, NULL,
3067  NULL, &supported_usage,
3068  disable_multiplane,
3069  !hwctx->usage ||
3070  (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT));
3071  if (err < 0)
3072  return err;
3073  }
3074 
3075  /* Lone DPB images do not need additional flags. */
3076  /* With DRM modifier + video profile the caller has already chosen a valid
3077  * usage/img_flags/chain; do not add usage or img_flags (supported_usage does
3078  * not consider the actual modifier or video profile). */
3079  int drm_mod_with_video = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
3081  VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
3082 
3083  if (!is_lone_dpb && !drm_mod_with_video) {
3084  /* Image usage flags */
3085  hwctx->usage |= supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
3086  VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
3087  VK_IMAGE_USAGE_STORAGE_BIT |
3088  VK_IMAGE_USAGE_SAMPLED_BIT);
3089 
3090  if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY &&
3091  !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) &&
3092  !(p->dprops.driverID == VK_DRIVER_ID_MOLTENVK))
3093  hwctx->usage |= supported_usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
3094 
3095  /* Enables encoding of images, if supported by format and extensions */
3096  if ((supported_usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3097  (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3098  (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1))
3099  hwctx->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
3100 
3101  /* Image creation flags.
3102  * Only fill them in automatically if the image is not going to be used as
3103  * a DPB-only image, and we have SAMPLED/STORAGE bits set. */
3104  if (!hwctx->img_flags) {
3105  int sampleable = hwctx->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
3106  VK_IMAGE_USAGE_STORAGE_BIT);
3107  hwctx->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
3108  if (sampleable) {
3109  hwctx->img_flags |= VK_IMAGE_CREATE_ALIAS_BIT;
3110  if ((fmt->vk_planes > 1) && (hwctx->format[0] == fmt->vkf))
3111  hwctx->img_flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
3112  }
3113  }
3114  }
3115 
3116  /* If the image has an ENCODE_SRC usage, and the maintenance1
3117  * extension is supported, check if it has a profile list.
3118  * If there's no profile list, or it has no encode operations,
3119  * then allow creating the image with no specific profile. */
3120  if ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
3121  (p->vkctx.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
3122  (p->vkctx.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) {
3123  const VkVideoProfileListInfoKHR *pl;
3124  pl = ff_vk_find_struct(hwctx->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
3125  if (!pl) {
3126  hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3127  } else {
3128  uint32_t i;
3129  for (i = 0; i < pl->profileCount; i++) {
3130  /* Video ops start at exactly 0x00010000 */
3131  if (pl->pProfiles[i].videoCodecOperation & 0xFFFF0000)
3132  break;
3133  }
3134  if (i == pl->profileCount)
3135  hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
3136  }
3137  }
3138 
3139  if (!hwctx->lock_frame)
3140  hwctx->lock_frame = lock_frame;
3141 
3142  if (!hwctx->unlock_frame)
3143  hwctx->unlock_frame = unlock_frame;
3144 
3145  err = ff_vk_exec_pool_init(&p->vkctx, p->compute_qf, &fp->compute_exec,
3146  p->compute_qf->num, 0, 0, 0, NULL);
3147  if (err)
3148  return err;
3149 
3150  err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->upload_exec,
3151  p->transfer_qf->num*2, 0, 0, 0, NULL);
3152  if (err)
3153  return err;
3154 
3155  err = ff_vk_exec_pool_init(&p->vkctx, p->transfer_qf, &fp->download_exec,
3156  p->transfer_qf->num, 0, 0, 0, NULL);
3157  if (err)
3158  return err;
3159 
3160  /* Test to see if allocation will fail */
3161  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
3162  hwctx->nb_layers, hwctx->create_pnext);
3163  if (err)
3164  return err;
3165 
3166  /* Collect `VkDrmFormatModifierPropertiesEXT` for each plane. Required for DRM export. */
3167  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS && hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
3168  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3169  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3170  };
3171  err = vk->GetImageDrmFormatModifierPropertiesEXT(dev_hwctx->act_dev, f->img[0],
3172  &drm_mod);
3173  if (err != VK_SUCCESS) {
3174  av_log(hwfc, AV_LOG_ERROR, "Failed to get image DRM format modifier properties");
3175  vulkan_frame_free(hwfc, f);
3176  return AVERROR_EXTERNAL;
3177  }
3178  for (int i = 0; i < fmt->vk_planes; ++i) {
3179  VkDrmFormatModifierPropertiesListEXT modp;
3180  VkFormatProperties2 fmtp;
3181  VkDrmFormatModifierPropertiesEXT *mod_props = NULL;
3182 
3183  modp = (VkDrmFormatModifierPropertiesListEXT) {
3184  .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
3185  };
3186  fmtp = (VkFormatProperties2) {
3187  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
3188  .pNext = &modp,
3189  };
3190 
3191  /* query drmFormatModifierCount by keeping pDrmFormatModifierProperties NULL */
3192  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3193 
3194  modp.pDrmFormatModifierProperties =
3195  av_calloc(modp.drmFormatModifierCount, sizeof(*modp.pDrmFormatModifierProperties));
3196  if (!modp.pDrmFormatModifierProperties) {
3197  vulkan_frame_free(hwfc, f);
3198  return AVERROR(ENOMEM);
3199  }
3200  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
3201 
3202  for (uint32_t i = 0; i < modp.drmFormatModifierCount; ++i) {
3203  VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[i];
3204  if (m->drmFormatModifier == drm_mod.drmFormatModifier) {
3205  mod_props = m;
3206  break;
3207  }
3208  }
3209 
3210  if (mod_props == NULL) {
3211  av_log(hwfc, AV_LOG_ERROR, "No DRM format modifier properties found for modifier 0x%016"PRIx64"\n",
3212  drm_mod.drmFormatModifier);
3213  av_free(modp.pDrmFormatModifierProperties);
3214  vulkan_frame_free(hwfc, f);
3215  return AVERROR_EXTERNAL;
3216  }
3217 
3218  fp->drm_format_modifier_properties[i] = *mod_props;
3219  av_free(modp.pDrmFormatModifierProperties);
3220  }
3221  }
3222 
3223  vulkan_frame_free(hwfc, f);
3224 
3225  /* If user did not specify a pool, hwfc->pool will be set to the internal one
3226  * in hwcontext.c just after this gets called */
3227  if (!hwfc->pool) {
3229  hwfc, vulkan_pool_alloc,
3230  NULL);
3231  if (!ffhwframesctx(hwfc)->pool_internal)
3232  return AVERROR(ENOMEM);
3233  }
3234 
3235  return 0;
3236 }
3237 
3239 {
3240  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
3241  if (!frame->buf[0])
3242  return AVERROR(ENOMEM);
3243 
3244  frame->data[0] = frame->buf[0]->data;
3245  frame->format = AV_PIX_FMT_VULKAN;
3246  frame->width = hwfc->width;
3247  frame->height = hwfc->height;
3248 
3249  return 0;
3250 }
3251 
3253  enum AVHWFrameTransferDirection dir,
3254  enum AVPixelFormat **formats)
3255 {
3256  enum AVPixelFormat *fmts;
3257  int n = 2;
3258 
3259 #if CONFIG_CUDA
3260  n++;
3261 #endif
3262  fmts = av_malloc_array(n, sizeof(*fmts));
3263  if (!fmts)
3264  return AVERROR(ENOMEM);
3265 
3266  n = 0;
3267  fmts[n++] = hwfc->sw_format;
3268 #if CONFIG_CUDA
3269  fmts[n++] = AV_PIX_FMT_CUDA;
3270 #endif
3271  fmts[n++] = AV_PIX_FMT_NONE;
3272 
3273  *formats = fmts;
3274  return 0;
3275 }
3276 
3277 #if CONFIG_LIBDRM
3278 static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3279 {
3280  vulkan_frame_free(hwfc, hwmap->priv);
3281 }
3282 
3283 static const struct {
3284  uint32_t drm_fourcc;
3285  VkFormat vk_format;
3286 } vulkan_drm_format_map[] = {
3287  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
3288  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
3289  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
3290  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
3291  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
3292  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
3293  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3294  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
3295  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3296  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
3297  { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3298  { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3299  { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
3300  { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 },
3301 
3302  // All these DRM_FORMATs were added in the same libdrm commit.
3303 #ifdef DRM_FORMAT_XYUV8888
3304  { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
3305  { DRM_FORMAT_XVYU2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 } ,
3306  { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 } ,
3307  { DRM_FORMAT_XVYU16161616, VK_FORMAT_R16G16B16A16_UNORM } ,
3308 #endif
3309 };
3310 
3311 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
3312 {
3313  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3314  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
3315  return vulkan_drm_format_map[i].vk_format;
3316  return VK_FORMAT_UNDEFINED;
3317 }
3318 
3319 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
3320  const AVFrame *src, int flags)
3321 {
3322  int err = 0;
3323  VkResult ret;
3324  AVVkFrame *f;
3325  int bind_counts = 0;
3326  AVHWDeviceContext *ctx = hwfc->device_ctx;
3327  VulkanDevicePriv *p = ctx->hwctx;
3328  AVVulkanDeviceContext *hwctx = &p->p;
3329  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3330  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
3331  VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
3332  VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
3333 
3334  for (int i = 0; i < desc->nb_layers; i++) {
3335  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
3336  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
3337  desc->layers[i].format);
3338  return AVERROR(EINVAL);
3339  }
3340  }
3341 
3342  if (!(f = av_vk_frame_alloc())) {
3343  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
3344  err = AVERROR(ENOMEM);
3345  goto fail;
3346  }
3347 
3348  f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
3349 
3350  for (int i = 0; i < desc->nb_layers; i++) {
3351  const int planes = desc->layers[i].nb_planes;
3352 
3353  /* Semaphore */
3354  VkSemaphoreTypeCreateInfo sem_type_info = {
3355  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3356  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
3357  .initialValue = 0,
3358  };
3359  VkSemaphoreCreateInfo sem_spawn = {
3360  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3361  .pNext = &sem_type_info,
3362  };
3363 
3364  /* Image creation */
3365  VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
3366  VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
3367  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
3368  .drmFormatModifier = desc->objects[0].format_modifier,
3369  .drmFormatModifierPlaneCount = planes,
3370  .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
3371  };
3372  VkExternalMemoryImageCreateInfo ext_img_spec = {
3373  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
3374  .pNext = &ext_img_mod_spec,
3375  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3376  };
3377  VkImageCreateInfo create_info = {
3378  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3379  .pNext = &ext_img_spec,
3380  .imageType = VK_IMAGE_TYPE_2D,
3381  .format = drm_to_vulkan_fmt(desc->layers[i].format),
3382  .extent.depth = 1,
3383  .mipLevels = 1,
3384  .arrayLayers = 1,
3385  .flags = 0x0,
3386  .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
3387  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
3388  .usage = 0x0, /* filled in below */
3389  .samples = VK_SAMPLE_COUNT_1_BIT,
3390  .pQueueFamilyIndices = p->img_qfs,
3391  .queueFamilyIndexCount = p->nb_img_qfs,
3392  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
3393  VK_SHARING_MODE_EXCLUSIVE,
3394  };
3395 
3396  /* Image format verification */
3397  VkExternalImageFormatProperties ext_props = {
3398  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
3399  };
3400  VkImageFormatProperties2 props_ret = {
3401  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
3402  .pNext = &ext_props,
3403  };
3404  VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
3405  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
3406  .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
3407  .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
3408  .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
3409  .sharingMode = create_info.sharingMode,
3410  };
3411  VkPhysicalDeviceExternalImageFormatInfo props_ext = {
3412  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
3413  .pNext = &props_drm_mod,
3414  .handleType = ext_img_spec.handleTypes,
3415  };
3416  VkPhysicalDeviceImageFormatInfo2 fmt_props;
3417 
3418  if (flags & AV_HWFRAME_MAP_READ)
3419  create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT |
3420  VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
3422  create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT |
3423  VK_IMAGE_USAGE_TRANSFER_DST_BIT;
3424 
3425  fmt_props = (VkPhysicalDeviceImageFormatInfo2) {
3426  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
3427  .pNext = &props_ext,
3428  .format = create_info.format,
3429  .type = create_info.imageType,
3430  .tiling = create_info.tiling,
3431  .usage = create_info.usage,
3432  .flags = create_info.flags,
3433  };
3434 
3435  /* Check if importing is possible for this combination of parameters */
3436  ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
3437  &fmt_props, &props_ret);
3438  if (ret != VK_SUCCESS) {
3439  av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
3440  ff_vk_ret2str(ret));
3441  err = AVERROR_EXTERNAL;
3442  goto fail;
3443  }
3444 
3445  /* Set the image width/height */
3446  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
3447  hwfc->sw_format, src->width, src->height, i);
3448 
3449  /* Set the subresource layout based on the layer properties */
3450  for (int j = 0; j < planes; j++) {
3451  ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
3452  ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
3453  ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
3454  ext_img_layouts[j].arrayPitch = 0;
3455  ext_img_layouts[j].depthPitch = 0;
3456  }
3457 
3458  /* Create image */
3459  ret = vk->CreateImage(hwctx->act_dev, &create_info,
3460  hwctx->alloc, &f->img[i]);
3461  if (ret != VK_SUCCESS) {
3462  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
3463  ff_vk_ret2str(ret));
3464  err = AVERROR(EINVAL);
3465  goto fail;
3466  }
3467 
3468  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3469  hwctx->alloc, &f->sem[i]);
3470  if (ret != VK_SUCCESS) {
3471  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3472  ff_vk_ret2str(ret));
3473  err = AVERROR_EXTERNAL;
3474  goto fail;
3475  }
3476 
3477  f->queue_family[i] = VK_QUEUE_FAMILY_EXTERNAL;
3478  f->layout[i] = create_info.initialLayout;
3479  f->access[i] = 0x0;
3480  f->sem_value[i] = 0;
3481  }
3482 
3483  for (int i = 0; i < desc->nb_layers; i++) {
3484  /* Memory requirements */
3485  VkImageMemoryRequirementsInfo2 req_desc = {
3486  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
3487  .image = f->img[i],
3488  };
3489  VkMemoryDedicatedRequirements ded_req = {
3490  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
3491  };
3492  VkMemoryRequirements2 req2 = {
3493  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3494  .pNext = &ded_req,
3495  };
3496 
3497  /* Allocation/importing */
3498  VkMemoryFdPropertiesKHR fdmp = {
3499  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
3500  };
3501  /* This assumes that a layer will never be constructed from multiple
3502  * objects. If that was to happen in the real world, this code would
3503  * need to import each plane separately.
3504  */
3505  VkImportMemoryFdInfoKHR idesc = {
3506  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
3507  .fd = dup(desc->objects[desc->layers[i].planes[0].object_index].fd),
3508  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3509  };
3510  VkMemoryDedicatedAllocateInfo ded_alloc = {
3511  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
3512  .pNext = &idesc,
3513  .image = req_desc.image,
3514  };
3515 
3516  /* Get object properties */
3517  ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
3518  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3519  idesc.fd, &fdmp);
3520  if (ret != VK_SUCCESS) {
3521  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
3522  ff_vk_ret2str(ret));
3523  err = AVERROR_EXTERNAL;
3524  close(idesc.fd);
3525  goto fail;
3526  }
3527 
3528  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
3529 
3530  /* Only a single bit must be set, not a range, and it must match */
3531  req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
3532 
3533  err = alloc_mem(ctx, &req2.memoryRequirements,
3534  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
3535  (ded_req.prefersDedicatedAllocation ||
3536  ded_req.requiresDedicatedAllocation) ?
3537  &ded_alloc : ded_alloc.pNext,
3538  &f->flags, &f->mem[i]);
3539  if (err) {
3540  close(idesc.fd);
3541  return err;
3542  }
3543 
3544  f->size[i] = req2.memoryRequirements.size;
3545  }
3546 
3547  for (int i = 0; i < desc->nb_layers; i++) {
3548  const int planes = desc->layers[i].nb_planes;
3549  for (int j = 0; j < planes; j++) {
3550  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
3551  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
3552  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
3553 
3554  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
3555  plane_info[bind_counts].pNext = NULL;
3556  plane_info[bind_counts].planeAspect = aspect;
3557 
3558  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
3559  bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
3560  bind_info[bind_counts].image = f->img[i];
3561  bind_info[bind_counts].memory = f->mem[i];
3562 
3563  /* Offset is already signalled via pPlaneLayouts above */
3564  bind_info[bind_counts].memoryOffset = 0;
3565 
3566  bind_counts++;
3567  }
3568  }
3569 
3570  /* Bind the allocated memory to the images */
3571  ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
3572  if (ret != VK_SUCCESS) {
3573  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
3574  ff_vk_ret2str(ret));
3575  err = AVERROR_EXTERNAL;
3576  goto fail;
3577  }
3578 
3579  *frame = f;
3580 
3581  return 0;
3582 
3583 fail:
3584  vulkan_frame_free(hwfc, f);
3585 
3586  return err;
3587 }
3588 
3589 static int vulkan_map_from_drm_frame_sync(AVHWFramesContext *hwfc, AVFrame *dst,
3590  const AVDRMFrameDescriptor *desc, int flags)
3591 {
3592  int err;
3593  VkResult ret;
3594  AVHWDeviceContext *ctx = hwfc->device_ctx;
3595  VulkanDevicePriv *p = ctx->hwctx;
3596  VulkanFramesPriv *fp = hwfc->hwctx;
3597  AVVulkanDeviceContext *hwctx = &p->p;
3598  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3599 
3600 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
3601  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) {
3602  VkCommandBuffer cmd_buf;
3603  FFVkExecContext *exec;
3604  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
3605  VkSemaphore drm_sync_sem[AV_DRM_MAX_PLANES] = { 0 };
3606  int nb_img_bar = 0;
3607 
3608  for (int i = 0; i < desc->nb_objects; i++) {
3609  VkSemaphoreTypeCreateInfo sem_type_info = {
3610  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
3611  .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
3612  };
3613  VkSemaphoreCreateInfo sem_spawn = {
3614  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3615  .pNext = &sem_type_info,
3616  };
3617  VkImportSemaphoreFdInfoKHR import_info;
3618  struct dma_buf_export_sync_file implicit_fd_info = {
3619  .flags = DMA_BUF_SYNC_READ,
3620  .fd = -1,
3621  };
3622 
3623  if (ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
3624  &implicit_fd_info)) {
3625  err = AVERROR(errno);
3626  av_log(hwctx, AV_LOG_ERROR, "Failed to retrieve implicit DRM sync file: %s\n",
3627  av_err2str(err));
3628  for (; i >= 0; i--)
3629  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3630  return err;
3631  }
3632 
3633  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
3634  hwctx->alloc, &drm_sync_sem[i]);
3635  if (ret != VK_SUCCESS) {
3636  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
3637  ff_vk_ret2str(ret));
3638  err = AVERROR_EXTERNAL;
3639  for (; i >= 0; i--)
3640  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3641  return err;
3642  }
3643 
3644  import_info = (VkImportSemaphoreFdInfoKHR) {
3645  .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
3646  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
3647  .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
3648  .semaphore = drm_sync_sem[i],
3649  .fd = implicit_fd_info.fd,
3650  };
3651 
3652  ret = vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info);
3653  if (ret != VK_SUCCESS) {
3654  av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n",
3655  ff_vk_ret2str(ret));
3656  err = AVERROR_EXTERNAL;
3657  for (; i >= 0; i--)
3658  vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc);
3659  return err;
3660  }
3661  }
3662 
3663  exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
3664  cmd_buf = exec->buf;
3665 
3666  ff_vk_exec_start(&p->vkctx, exec);
3667 
3668  /* Ownership of semaphores is passed */
3669  err = ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec,
3670  drm_sync_sem, desc->nb_objects,
3671  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1);
3672  if (err < 0)
3673  return err;
3674 
3675  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, dst,
3676  VK_PIPELINE_STAGE_2_NONE,
3677  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
3678  if (err < 0)
3679  return err;
3680 
3681  ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar,
3682  VK_PIPELINE_STAGE_2_NONE,
3683  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
3684  ((flags & AV_HWFRAME_MAP_READ) ?
3685  VK_ACCESS_2_SHADER_SAMPLED_READ_BIT : 0x0) |
3687  VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT : 0x0),
3688  VK_IMAGE_LAYOUT_GENERAL,
3689  p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
3690 
3691  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
3692  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
3693  .pImageMemoryBarriers = img_bar,
3694  .imageMemoryBarrierCount = nb_img_bar,
3695  });
3696 
3697  err = ff_vk_exec_submit(&p->vkctx, exec);
3698  if (err < 0)
3699  return err;
3700  } else
3701 #endif
3702  {
3703  AVVkFrame *f = (AVVkFrame *)dst->data[0];
3704  av_log(hwctx, AV_LOG_WARNING, "No support for synchronization when importing DMA-BUFs, "
3705  "image may be corrupted.\n");
3707  if (err)
3708  return err;
3709  }
3710 
3711  return 0;
3712 }
3713 
3714 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3715  const AVFrame *src, int flags)
3716 {
3717  int err = 0;
3718  AVVkFrame *f;
3719  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
3720 
3721  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src, flags)))
3722  return err;
3723 
3724  /* The unmapping function will free this */
3725  dst->data[0] = (uint8_t *)f;
3726  dst->width = src->width;
3727  dst->height = src->height;
3728 
3729  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
3730  &vulkan_unmap_from_drm, f);
3731  if (err < 0)
3732  goto fail;
3733 
3734  err = vulkan_map_from_drm_frame_sync(hwfc, dst, desc, flags);
3735  if (err < 0)
3736  return err;
3737 
3738  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
3739 
3740  return 0;
3741 
3742 fail:
3744  dst->data[0] = NULL;
3745  return err;
3746 }
3747 
3748 #if CONFIG_VAAPI
3749 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
3750  AVFrame *dst, const AVFrame *src,
3751  int flags)
3752 {
3753  int err;
3754  AVFrame *tmp = av_frame_alloc();
3755  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3756  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
3757  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
3758 
3759  if (!tmp)
3760  return AVERROR(ENOMEM);
3761 
3762  /* We have to sync since like the previous comment said, no semaphores */
3763  vaSyncSurface(vaapi_ctx->display, surface_id);
3764 
3765  tmp->format = AV_PIX_FMT_DRM_PRIME;
3766 
3767  err = av_hwframe_map(tmp, src, flags);
3768  if (err < 0)
3769  goto fail;
3770 
3771  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
3772  if (err < 0)
3773  goto fail;
3774 
3775  err = ff_hwframe_map_replace(dst, src);
3776 
3777 fail:
3778  av_frame_free(&tmp);
3779  return err;
3780 }
3781 #endif
3782 #endif
3783 
3784 #if CONFIG_CUDA
3785 static int export_mem_to_cuda(AVHWDeviceContext *ctx,
3786  AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3787  AVVkFrameInternal *dst_int, int idx,
3788  VkDeviceMemory mem, size_t size)
3789 {
3790  VkResult ret;
3791  VulkanDevicePriv *p = ctx->hwctx;
3792  AVVulkanDeviceContext *hwctx = &p->p;
3793  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3794 
3795 #ifdef _WIN32
3796  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3797  .type = IsWindows8OrGreater()
3798  ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3799  : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
3800  .size = size,
3801  };
3802  VkMemoryGetWin32HandleInfoKHR export_info = {
3803  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
3804  .memory = mem,
3805  .handleType = IsWindows8OrGreater()
3806  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3807  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3808  };
3809 
3810  ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
3811  &ext_desc.handle.win32.handle);
3812  if (ret != VK_SUCCESS) {
3813  av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
3814  ff_vk_ret2str(ret));
3815  return AVERROR_EXTERNAL;
3816  }
3817  dst_int->ext_mem_handle[idx] = ext_desc.handle.win32.handle;
3818 #else
3819  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3820  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
3821  .size = size,
3822  };
3823  VkMemoryGetFdInfoKHR export_info = {
3824  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3825  .memory = mem,
3826  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
3827  };
3828 
3829  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3830  &ext_desc.handle.fd);
3831  if (ret != VK_SUCCESS) {
3832  av_log(ctx, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
3833  ff_vk_ret2str(ret));
3834  return AVERROR_EXTERNAL;
3835  }
3836 #endif
3837 
3838  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[idx], &ext_desc));
3839  if (ret < 0) {
3840 #ifndef _WIN32
3841  close(ext_desc.handle.fd);
3842 #endif
3843  return AVERROR_EXTERNAL;
3844  }
3845 
3846  return 0;
3847 }
3848 
3849 static int export_sem_to_cuda(AVHWDeviceContext *ctx,
3850  AVHWDeviceContext *cuda_cu, CudaFunctions *cu,
3851  AVVkFrameInternal *dst_int, int idx,
3852  VkSemaphore sem)
3853 {
3854  VkResult ret;
3855  VulkanDevicePriv *p = ctx->hwctx;
3856  AVVulkanDeviceContext *hwctx = &p->p;
3857  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3858 
3859 #ifdef _WIN32
3860  VkSemaphoreGetWin32HandleInfoKHR sem_export = {
3861  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
3862  .semaphore = sem,
3863  .handleType = IsWindows8OrGreater()
3864  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
3865  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3866  };
3867  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3868  .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
3869  };
3870 #else
3871  VkSemaphoreGetFdInfoKHR sem_export = {
3872  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
3873  .semaphore = sem,
3874  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
3875  };
3876  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3877  .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
3878  };
3879 #endif
3880 
3881 #ifdef _WIN32
3882  ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
3883  &ext_sem_desc.handle.win32.handle);
3884 #else
3885  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
3886  &ext_sem_desc.handle.fd);
3887 #endif
3888  if (ret != VK_SUCCESS) {
3889  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
3890  ff_vk_ret2str(ret));
3891  return AVERROR_EXTERNAL;
3892  }
3893 #ifdef _WIN32
3894  dst_int->ext_sem_handle[idx] = ext_sem_desc.handle.win32.handle;
3895 #endif
3896 
3897  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[idx],
3898  &ext_sem_desc));
3899  if (ret < 0) {
3900 #ifndef _WIN32
3901  close(ext_sem_desc.handle.fd);
3902 #endif
3903  return AVERROR_EXTERNAL;
3904  }
3905 
3906  return 0;
3907 }
3908 
3909 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
3910  AVBufferRef *cuda_hwfc,
3911  const AVFrame *frame)
3912 {
3913  int err;
3914  VkResult ret;
3915  AVVkFrame *dst_f;
3916  AVVkFrameInternal *dst_int;
3917  AVHWDeviceContext *ctx = hwfc->device_ctx;
3918  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3920  VulkanDevicePriv *p = ctx->hwctx;
3921  AVVulkanDeviceContext *hwctx = &p->p;
3922  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3923  int nb_images;
3924 
3925  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
3926  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3927  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3928  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3929  CudaFunctions *cu = cu_internal->cuda_dl;
3930  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
3931  CU_AD_FORMAT_UNSIGNED_INT8;
3932 
3933  dst_f = (AVVkFrame *)frame->data[0];
3934  dst_int = dst_f->internal;
3935 
3936  if (!dst_int->cuda_fc_ref) {
3937  size_t offsets[3] = { 0 };
3938 
3939  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
3940  if (!dst_int->cuda_fc_ref)
3941  return AVERROR(ENOMEM);
3942 
3943  nb_images = ff_vk_count_images(dst_f);
3944  for (int i = 0; i < nb_images; i++) {
3945  err = export_mem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
3946  dst_f->mem[i], dst_f->size[i]);
3947  if (err < 0)
3948  goto fail;
3949 
3950  err = export_sem_to_cuda(ctx, cuda_cu, cu, dst_int, i,
3951  dst_f->sem[i]);
3952  if (err < 0)
3953  goto fail;
3954  }
3955 
3956  if (nb_images != planes) {
3957  for (int i = 0; i < planes; i++) {
3958  VkImageSubresource subres = {
3959  .aspectMask = i == 2 ? VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT :
3960  i == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
3961  VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
3962  };
3963  VkSubresourceLayout layout = { 0 };
3964  vk->GetImageSubresourceLayout(hwctx->act_dev, dst_f->img[FFMIN(i, nb_images - 1)],
3965  &subres, &layout);
3966  offsets[i] = layout.offset;
3967  }
3968  }
3969 
3970  for (int i = 0; i < planes; i++) {
3971  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
3972  .offset = offsets[i],
3973  .arrayDesc = {
3974  .Depth = 0,
3975  .Format = cufmt,
3976  .NumChannels = 1 + ((planes == 2) && i),
3977  .Flags = 0,
3978  },
3979  .numLevels = 1,
3980  };
3981  int p_w, p_h;
3982 
3983  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3984  tex_desc.arrayDesc.Width = p_w;
3985  tex_desc.arrayDesc.Height = p_h;
3986 
3987  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
3988  dst_int->ext_mem[FFMIN(i, nb_images - 1)],
3989  &tex_desc));
3990  if (ret < 0) {
3991  err = AVERROR_EXTERNAL;
3992  goto fail;
3993  }
3994 
3995  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
3996  dst_int->cu_mma[i], 0));
3997  if (ret < 0) {
3998  err = AVERROR_EXTERNAL;
3999  goto fail;
4000  }
4001 
4002  }
4003  }
4004 
4005  return 0;
4006 
4007 fail:
4008  vulkan_free_internal(p, dst_f);
4009  return err;
4010 }
4011 
4012 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
4013  AVFrame *dst, const AVFrame *src)
4014 {
4015  int err;
4016  CUcontext dummy;
4017  AVVkFrame *dst_f;
4018  AVVkFrameInternal *dst_int;
4019  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4020  VulkanFramesPriv *fp = hwfc->hwctx;
4021  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4023 
4024  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
4025  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4026  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4027  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4028  CudaFunctions *cu = cu_internal->cuda_dl;
4029  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4030  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4031 
4032  dst_f = (AVVkFrame *)dst->data[0];
4033 
4034  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4035  if (err < 0)
4036  return err;
4037 
4038  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4039  if (err < 0)
4040  return err;
4041 
4042  err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
4043  if (err < 0) {
4044  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4045  return err;
4046  }
4047 
4048  dst_int = dst_f->internal;
4049 
4050  for (int i = 0; i < planes; i++) {
4051  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4052  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4053  }
4054 
4055  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4056  planes, cuda_dev->stream));
4057  if (err < 0)
4058  goto fail;
4059 
4060  for (int i = 0; i < planes; i++) {
4061  CUDA_MEMCPY2D cpy = {
4062  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
4063  .srcDevice = (CUdeviceptr)src->data[i],
4064  .srcPitch = src->linesize[i],
4065  .srcY = 0,
4066 
4067  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
4068  .dstArray = dst_int->cu_array[i],
4069  };
4070 
4071  int p_w, p_h;
4072  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4073 
4074  cpy.WidthInBytes = p_w * desc->comp[i].step;
4075  cpy.Height = p_h;
4076 
4077  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4078  if (err < 0)
4079  goto fail;
4080  }
4081 
4082  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4083  planes, cuda_dev->stream));
4084  if (err < 0)
4085  goto fail;
4086 
4087  for (int i = 0; i < planes; i++)
4088  dst_f->sem_value[i]++;
4089 
4090  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4091 
4092  av_log(hwfc, AV_LOG_VERBOSE, "Transferred CUDA image to Vulkan!\n");
4093 
4094  return err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4095 
4096 fail:
4097  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4098  vulkan_free_internal(p, dst_f);
4099  av_buffer_unref(&dst->buf[0]);
4100  return err;
4101 }
4102 #endif
4103 
4105  const AVFrame *src, int flags)
4106 {
4108 
4109  switch (src->format) {
4110 #if CONFIG_LIBDRM
4111 #if CONFIG_VAAPI
4112  case AV_PIX_FMT_VAAPI:
4113  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4114  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
4115  else
4116  return AVERROR(ENOSYS);
4117 #endif
4118  case AV_PIX_FMT_DRM_PRIME:
4119  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4120  return vulkan_map_from_drm(hwfc, dst, src, flags);
4121  else
4122  return AVERROR(ENOSYS);
4123 #endif
4124  default:
4125  return AVERROR(ENOSYS);
4126  }
4127 }
4128 
4129 #if CONFIG_LIBDRM
4130 typedef struct VulkanDRMMapping {
4131  AVDRMFrameDescriptor drm_desc;
4132  AVVkFrame *source;
4133 } VulkanDRMMapping;
4134 
4135 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
4136 {
4137  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
4138 
4139  /* on unmap from DRM, make sure to import sync objects so that we are sync'd with any work that was
4140  * done on the buffer while exported. We don't know if who used the dmabuf did reads or writes, so protect against both */
4141  vulkan_map_from_drm_frame_sync(hwfc, hwmap->source, drm_desc, AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE);
4142 
4143  for (int i = 0; i < drm_desc->nb_objects; i++)
4144  close(drm_desc->objects[i].fd);
4145 
4146  av_free(drm_desc);
4147 }
4148 
4149 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
4150 {
4151  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
4152  if (vulkan_drm_format_map[i].vk_format == vkfmt)
4153  return vulkan_drm_format_map[i].drm_fourcc;
4154  return DRM_FORMAT_INVALID;
4155 }
4156 
4157 #define MAX_MEMORY_PLANES 4
4158 static VkImageAspectFlags plane_index_to_aspect(int plane) {
4159  if (plane == 0) return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4160  if (plane == 1) return VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
4161  if (plane == 2) return VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
4162  if (plane == 3) return VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
4163 
4164  av_assert2 (0 && "Invalid plane index");
4165  return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
4166 }
4167 
4168 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4169 static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
4170  VulkanFramesPriv *fp, int nb_sems)
4171 {
4172  int sync_fd = -1;
4173  VkResult ret;
4174  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4175  AVVulkanDeviceContext *hwctx = &p->p;
4176  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4177 
4178  if (f->internal->drm_sync_sem == VK_NULL_HANDLE) {
4179  VkExportSemaphoreCreateInfo exp_info = {
4180  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
4181  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4182  };
4183  VkSemaphoreTypeCreateInfo type_info = {
4184  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
4185  .pNext = &exp_info,
4186  .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
4187  };
4188  VkSemaphoreCreateInfo sem_create = {
4189  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
4190  .pNext = &type_info,
4191  };
4192  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_create, hwctx->alloc,
4193  &f->internal->drm_sync_sem);
4194  if (ret != VK_SUCCESS) {
4195  av_log(hwctx, AV_LOG_ERROR, "Failed to create DRM export semaphore: %s\n",
4196  ff_vk_ret2str(ret));
4197  return AVERROR_EXTERNAL;
4198  }
4199  }
4200 
4201  /* Submit a lightweight exec that waits on the timeline semaphore
4202  * (true last operation on the frame) and signals the binary semaphore,
4203  * so any Vulkan frame can get a SYNC_FD regardless of origin. */
4204  FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
4205  if (ff_vk_exec_start(&p->vkctx, exec) >= 0) {
4206  for (int i = 0; i < nb_sems; i++)
4207  ff_vk_exec_add_dep_wait_sem(&p->vkctx, exec, f->sem[i],
4208  f->sem_value[i],
4209  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
4210  ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, &f->internal->drm_sync_sem, 1,
4211  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0);
4212  if (ff_vk_exec_submit(&p->vkctx, exec) >= 0) {
4213  VkSemaphoreGetFdInfoKHR get_fd_info = {
4214  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
4215  .semaphore = f->internal->drm_sync_sem,
4216  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
4217  };
4218  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &get_fd_info, &sync_fd);
4219  if (ret != VK_SUCCESS) {
4220  av_log(hwctx, AV_LOG_WARNING,
4221  "Failed to get sync fd from DRM map export semaphore: %s\n",
4222  ff_vk_ret2str(ret));
4223  sync_fd = -1;
4224  }
4225  } else {
4226  ff_vk_exec_discard_deps(&p->vkctx, exec);
4227  }
4228  }
4229 
4230  return sync_fd;
4231 }
4232 #endif
4233 
4234 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
4235  const AVFrame *src, int flags)
4236 {
4237  int err = 0;
4238  VkResult ret;
4239  AVVkFrame *f = (AVVkFrame *)src->data[0];
4240  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4241  AVVulkanDeviceContext *hwctx = &p->p;
4242  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4243  VulkanFramesPriv *fp = hwfc->hwctx;
4244  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4245  const int nb_images = ff_vk_count_images(f);
4246  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
4247  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
4248  };
4249  const int nb_sems = nb_images;
4250 
4251  int sync_fd = -1;
4252 
4253  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
4254  if (!drm_desc)
4255  return AVERROR(ENOMEM);
4256 
4258  if (err < 0)
4259  goto end;
4260 
4261 #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
4262  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
4263  f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
4264  vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
4265  err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
4266  if (err < 0)
4267  goto end;
4268  sync_fd = err;
4269  err = 0;
4270  }
4271 #endif
4272 
4273  if (sync_fd < 0) {
4274  VkSemaphoreWaitInfo wait_info = {
4275  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4276  .flags = 0x0,
4277  .semaphoreCount = nb_sems,
4278  .pSemaphores = f->sem,
4279  .pValues = f->sem_value,
4280  };
4281  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
4282  }
4283 
4284  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
4285  if (err < 0)
4286  goto end;
4287 
4288  ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
4289  &drm_mod);
4290  if (ret != VK_SUCCESS) {
4291  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
4292  err = AVERROR_EXTERNAL;
4293  goto end;
4294  }
4295 
4296  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
4297  VkMemoryGetFdInfoKHR export_info = {
4298  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
4299  .memory = f->mem[i],
4300  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
4301  };
4302 
4303  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
4304  &drm_desc->objects[i].fd);
4305  if (ret != VK_SUCCESS) {
4306  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
4307  err = AVERROR_EXTERNAL;
4308  goto end;
4309  }
4310 
4311 #if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
4312  if (sync_fd >= 0) {
4313  int dup_fd = dup(sync_fd);
4314  if (dup_fd >= 0) {
4315  struct dma_buf_import_sync_file import_info = {
4316  .flags = DMA_BUF_SYNC_WRITE,
4317  .fd = dup_fd,
4318  };
4319  if (ioctl(drm_desc->objects[i].fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_info) < 0)
4320  av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s\n", av_err2str(AVERROR(errno)));
4321  close(dup_fd);
4322  } else {
4323  av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
4324  }
4325  }
4326 #endif
4327 
4328  drm_desc->nb_objects++;
4329  drm_desc->objects[i].size = f->size[i];
4330  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
4331  }
4332 
4333  /* NV12 has 2 planes but 1 image/semaphore */
4334  drm_desc->nb_layers = FFMAX(planes, nb_images);
4335  for (int i = 0; i < drm_desc->nb_layers; i++) {
4336  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
4337 
4338  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
4339  drm_desc->layers[i].nb_planes = fp->drm_format_modifier_properties[i].drmFormatModifierPlaneCount;
4340 
4341  if (drm_desc->layers[i].nb_planes > MAX_MEMORY_PLANES) {
4342  av_log(hwfc, AV_LOG_ERROR, "Too many memory planes for DRM format!\n");
4343  err = AVERROR_EXTERNAL;
4344  goto end;
4345  }
4346 
4347  for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
4348  VkSubresourceLayout layout;
4349  int aspect_plane = (nb_images == 1) ? i : j;
4350  VkImageSubresource sub = {
4351  .aspectMask = plane_index_to_aspect(aspect_plane),
4352  };
4353 
4354  drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
4355 
4356  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[FFMIN(i, nb_images - 1)], &sub, &layout);
4357  drm_desc->layers[i].planes[j].offset = layout.offset;
4358  drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
4359  }
4360 
4361  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
4362  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
4363  err = AVERROR_PATCHWELCOME;
4364  goto end;
4365  }
4366 
4367 
4368  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
4369  continue;
4370 
4371  }
4372 
4373  dst->width = src->width;
4374  dst->height = src->height;
4375  dst->data[0] = (uint8_t *)drm_desc;
4376  dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
4377 
4378  if (sync_fd >= 0)
4379  close(sync_fd);
4380 
4381  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
4382 
4383  return 0;
4384 
4385 end:
4386  for (int i = 0; i < drm_desc->nb_objects; i++)
4387  close(drm_desc->objects[i].fd);
4388  av_free(drm_desc);
4389  if (sync_fd >= 0)
4390  close(sync_fd);
4391  return err;
4392 }
4393 
4394 #if CONFIG_VAAPI
4395 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
4396  const AVFrame *src, int flags)
4397 {
4398  int err;
4399  AVFrame *tmp = av_frame_alloc();
4400  if (!tmp)
4401  return AVERROR(ENOMEM);
4402 
4403  tmp->format = AV_PIX_FMT_DRM_PRIME;
4404 
4405  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
4406  if (err < 0)
4407  goto fail;
4408 
4409  err = av_hwframe_map(dst, tmp, flags);
4410  if (err < 0)
4411  goto fail;
4412 
4413  err = ff_hwframe_map_replace(dst, src);
4414 
4415 fail:
4416  av_frame_free(&tmp);
4417  return err;
4418 }
4419 #endif
4420 #endif
4421 
4423  const AVFrame *src, int flags)
4424 {
4426 
4427  switch (dst->format) {
4428 #if CONFIG_LIBDRM
4429  case AV_PIX_FMT_DRM_PRIME:
4430  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4431  return vulkan_map_to_drm(hwfc, dst, src, flags);
4432  else
4433  return AVERROR(ENOSYS);
4434 #if CONFIG_VAAPI
4435  case AV_PIX_FMT_VAAPI:
4436  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
4437  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
4438  else
4439  return AVERROR(ENOSYS);
4440 #endif
4441 #endif
4442  default:
4443  break;
4444  }
4445  return AVERROR(ENOSYS);
4446 }
4447 
4449  AVFrame *swf, VkBufferImageCopy *region,
4450  int planes, int upload)
4451 {
4452  int err;
4453  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4454  FFVkBuffer *vkbuf = (FFVkBuffer *)buf->data;
4455 
4456  if (upload) {
4457  for (int i = 0; i < planes; i++)
4458  av_image_copy_plane(vkbuf->mapped_mem + region[i].bufferOffset,
4459  region[i].bufferRowLength,
4460  swf->data[i],
4461  swf->linesize[i],
4462  swf->linesize[i],
4463  region[i].imageExtent.height);
4464 
4465  err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 1);
4466  if (err != VK_SUCCESS) {
4467  av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n",
4468  av_err2str(err));
4469  return AVERROR_EXTERNAL;
4470  }
4471  } else {
4472  err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 0);
4473  if (err != VK_SUCCESS) {
4474  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n",
4475  av_err2str(err));
4476  return AVERROR_EXTERNAL;
4477  }
4478 
4479  for (int i = 0; i < planes; i++)
4480  av_image_copy_plane(swf->data[i],
4481  swf->linesize[i],
4482  vkbuf->mapped_mem + region[i].bufferOffset,
4483  region[i].bufferRowLength,
4484  swf->linesize[i],
4485  region[i].imageExtent.height);
4486  }
4487 
4488  return 0;
4489 }
4490 
4492  AVFrame *swf, VkBufferImageCopy *region, int upload)
4493 {
4494  int err;
4495  uint32_t p_w, p_h;
4496  VulkanFramesPriv *fp = hwfc->hwctx;
4497  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4498  const int planes = av_pix_fmt_count_planes(swf->format);
4499  VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4500  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4501 
4502  size_t buf_offset = 0;
4503  for (int i = 0; i < planes; i++) {
4504  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4505 
4506  region[i] = (VkBufferImageCopy) {
4507  .bufferOffset = buf_offset,
4508  .bufferRowLength = FFALIGN(swf->linesize[i],
4509  p->props.properties.limits.optimalBufferCopyRowPitchAlignment),
4510  .bufferImageHeight = p_h,
4511  .imageSubresource.layerCount = 1,
4512  .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4513  /* Rest of the fields adjusted/filled in later */
4514  };
4515 
4516  buf_offset += FFALIGN(p_h*region[i].bufferRowLength,
4517  p->props.properties.limits.optimalBufferCopyOffsetAlignment);
4518  }
4519 
4520  err = ff_vk_get_pooled_buffer(&p->vkctx, &fp->tmp, dst, buf_usage,
4521  NULL, buf_offset,
4522  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
4523  p->vkctx.host_cached_flag);
4524  if (err < 0)
4525  return err;
4526 
4527  return 0;
4528 }
4529 
4530 static int host_map_frame(AVHWFramesContext *hwfc, AVBufferRef **dst, int *nb_bufs,
4531  AVFrame *swf, VkBufferImageCopy *region, int upload)
4532 {
4533  int err;
4534  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4535 
4536  int nb_src_bufs;
4537  const int planes = av_pix_fmt_count_planes(swf->format);
4538  VkBufferUsageFlags buf_usage = upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT :
4539  VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4540 
4541  /* We can't host map images with negative strides */
4542  for (int i = 0; i < planes; i++)
4543  if (swf->linesize[i] < 0)
4544  return AVERROR(EINVAL);
4545 
4546  /* Count the number of buffers in the software frame */
4547  nb_src_bufs = 0;
4548  while (swf->buf[nb_src_bufs])
4549  nb_src_bufs++;
4550 
4551  /* Single buffer contains all planes */
4552  if (nb_src_bufs == 1) {
4553  err = ff_vk_host_map_buffer(&p->vkctx, &dst[0],
4554  swf->data[0], swf->buf[0],
4555  buf_usage);
4556  if (err < 0)
4557  return err;
4558  (*nb_bufs)++;
4559 
4560  for (int i = 0; i < planes; i++)
4561  region[i].bufferOffset = ((FFVkBuffer *)dst[0]->data)->virtual_offset +
4562  swf->data[i] - swf->data[0];
4563  } else if (nb_src_bufs == planes) { /* One buffer per plane */
4564  for (int i = 0; i < planes; i++) {
4565  err = ff_vk_host_map_buffer(&p->vkctx, &dst[i],
4566  swf->data[i], swf->buf[i],
4567  buf_usage);
4568  if (err < 0)
4569  goto fail;
4570  (*nb_bufs)++;
4571 
4572  region[i].bufferOffset = ((FFVkBuffer *)dst[i]->data)->virtual_offset;
4573  }
4574  } else {
4575  /* Weird layout (3 planes, 2 buffers), patch welcome, fallback to copy */
4576  return AVERROR_PATCHWELCOME;
4577  }
4578 
4579  return 0;
4580 
4581 fail:
4582  for (int i = 0; i < (*nb_bufs); i++)
4583  av_buffer_unref(&dst[i]);
4584  return err;
4585 }
4586 
4588  AVFrame *swf, int upload)
4589 {
4590  VulkanFramesPriv *fp = hwfc->hwctx;
4591  AVVulkanFramesContext *hwfc_vk = &fp->p;
4592  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4593  AVVulkanDeviceContext *hwctx = &p->p;
4594  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4595 
4596  AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4598  const int planes = av_pix_fmt_count_planes(swf->format);
4599  const int nb_images = ff_vk_count_images(hwf_vk);
4600 
4601  VkSemaphoreWaitInfo sem_wait;
4602  VkHostImageLayoutTransitionInfoEXT layout_ch_info[AV_NUM_DATA_POINTERS];
4603  int nb_layout_ch = 0;
4604 
4605  hwfc_vk->lock_frame(hwfc, hwf_vk);
4606 
4607  for (int i = 0; i < nb_images; i++) {
4608  int compat = 0;
4609  for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount; j++) {
4610  if (hwf_vk->layout[i] == p->vkctx.host_image_props.pCopySrcLayouts[j]) {
4611  compat = 1;
4612  break;
4613  }
4614  }
4615  if (compat)
4616  continue;
4617 
4618  layout_ch_info[nb_layout_ch] = (VkHostImageLayoutTransitionInfoEXT) {
4619  .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
4620  .image = hwf_vk->img[i],
4621  .oldLayout = hwf_vk->layout[i],
4622  .newLayout = VK_IMAGE_LAYOUT_GENERAL,
4623  .subresourceRange = {
4624  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4625  .levelCount = 1,
4626  .layerCount = 1,
4627  },
4628  };
4629 
4630  hwf_vk->layout[i] = layout_ch_info[nb_layout_ch].newLayout;
4631  nb_layout_ch++;
4632  }
4633 
4634  sem_wait = (VkSemaphoreWaitInfo) {
4635  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
4636  .pSemaphores = hwf_vk->sem,
4637  .pValues = hwf_vk->sem_value,
4638  .semaphoreCount = nb_images,
4639  };
4640 
4641  vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
4642 
4643  if (nb_layout_ch)
4644  vk->TransitionImageLayoutEXT(hwctx->act_dev,
4645  nb_layout_ch, layout_ch_info);
4646 
4647  if (upload) {
4648  VkMemoryToImageCopyEXT region_info = {
4649  .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
4650  .imageSubresource = {
4651  .layerCount = 1,
4652  },
4653  };
4654  VkCopyMemoryToImageInfoEXT copy_info = {
4655  .sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
4656  .regionCount = 1,
4657  .pRegions = &region_info,
4658  };
4659  for (int i = 0; i < planes; i++) {
4660  int img_idx = FFMIN(i, (nb_images - 1));
4661  uint32_t p_w, p_h;
4662  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4663 
4664  region_info.pHostPointer = swf->data[i];
4665  region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4666  region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4667  region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4668  copy_info.dstImage = hwf_vk->img[img_idx];
4669  copy_info.dstImageLayout = hwf_vk->layout[img_idx];
4670 
4671  vk->CopyMemoryToImageEXT(hwctx->act_dev, &copy_info);
4672  }
4673  } else {
4674  VkImageToMemoryCopyEXT region_info = {
4675  .sType = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT,
4676  .imageSubresource = {
4677  .layerCount = 1,
4678  },
4679  };
4680  VkCopyImageToMemoryInfoEXT copy_info = {
4681  .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
4682  .regionCount = 1,
4683  .pRegions = &region_info,
4684  };
4685  for (int i = 0; i < planes; i++) {
4686  int img_idx = FFMIN(i, (nb_images - 1));
4687  uint32_t p_w, p_h;
4688  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4689 
4690  region_info.pHostPointer = swf->data[i];
4691  region_info.memoryRowLength = swf->linesize[i] / desc->comp[i].step;
4692  region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4693  region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
4694  copy_info.srcImage = hwf_vk->img[img_idx];
4695  copy_info.srcImageLayout = hwf_vk->layout[img_idx];
4696 
4697  vk->CopyImageToMemoryEXT(hwctx->act_dev, &copy_info);
4698  }
4699  }
4700 
4701  hwfc_vk->unlock_frame(hwfc, hwf_vk);
4702 
4703  return 0;
4704 }
4705 
4707  AVFrame *swf, AVFrame *hwf,
4708  int upload)
4709 {
4710  int err;
4711  VulkanFramesPriv *fp = hwfc->hwctx;
4712  AVVulkanFramesContext *hwctx = &fp->p;
4713  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4714  FFVulkanFunctions *vk = &p->vkctx.vkfn;
4715 
4716  int host_mapped = 0;
4717 
4718  AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
4719  VkBufferImageCopy region[AV_NUM_DATA_POINTERS]; // always one per plane
4720 
4721  const int planes = av_pix_fmt_count_planes(swf->format);
4723  const int nb_images = ff_vk_count_images(hwf_vk);
4724 
4725  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
4726  int nb_img_bar = 0;
4727 
4729  int nb_bufs = 0;
4730 
4731  VkCommandBuffer cmd_buf;
4732  FFVkExecContext *exec;
4733 
4734  /* Sanity checking */
4735  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
4736  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
4737  return AVERROR(EINVAL);
4738  }
4739 
4740  if (swf->width > hwfc->width || swf->height > hwfc->height)
4741  return AVERROR(EINVAL);
4742 
4743  if (hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
4744  !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY))
4745  return vulkan_transfer_host(hwfc, hwf, swf, upload);
4746 
4747  for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
4748  uint32_t p_w, p_h;
4749  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
4750 
4751  /* Buffer region for this plane */
4752  region[i] = (VkBufferImageCopy) {
4753  .bufferOffset = 0,
4754  .bufferRowLength = swf->linesize[i],
4755  .bufferImageHeight = p_h,
4756  .imageSubresource.layerCount = 1,
4757  .imageExtent = (VkExtent3D){ p_w, p_h, 1 },
4758  /* Rest of the fields adjusted/filled in later */
4759  };
4760  }
4761 
4762  /* Setup buffers first */
4763  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY && !p->avoid_host_import) {
4764  err = host_map_frame(hwfc, bufs, &nb_bufs, swf, region, upload);
4765  if (err >= 0)
4766  host_mapped = 1;
4767  }
4768 
4769  if (!host_mapped) {
4770  err = get_plane_buf(hwfc, &bufs[0], swf, region, upload);
4771  if (err < 0)
4772  goto end;
4773  nb_bufs = 1;
4774 
4775  if (upload) {
4776  err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 1);
4777  if (err < 0)
4778  goto end;
4779  }
4780  }
4781 
4782  exec = ff_vk_exec_get(&p->vkctx, &fp->upload_exec);
4783  cmd_buf = exec->buf;
4784 
4785  ff_vk_exec_start(&p->vkctx, exec);
4786 
4787  /* Prep destination Vulkan frame */
4788  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, hwf,
4789  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4790  VK_PIPELINE_STAGE_2_TRANSFER_BIT);
4791  if (err < 0)
4792  goto end;
4793 
4794  /* No need to declare buf deps for synchronous transfers (downloads) */
4795  if (upload) {
4796  /* Add the software frame backing the buffers if we're host mapping */
4797  if (host_mapped) {
4798  err = ff_vk_exec_add_dep_sw_frame(&p->vkctx, exec, swf);
4799  if (err < 0) {
4800  ff_vk_exec_discard_deps(&p->vkctx, exec);
4801  goto end;
4802  }
4803  }
4804 
4805  /* Add the buffers as a dependency */
4806  err = ff_vk_exec_add_dep_buf(&p->vkctx, exec, bufs, nb_bufs, 1);
4807  if (err < 0) {
4808  ff_vk_exec_discard_deps(&p->vkctx, exec);
4809  goto end;
4810  }
4811  }
4812 
4813  ff_vk_frame_barrier(&p->vkctx, exec, hwf, img_bar, &nb_img_bar,
4814  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
4815  VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
4816  upload ? VK_ACCESS_TRANSFER_WRITE_BIT :
4817  VK_ACCESS_TRANSFER_READ_BIT,
4818  upload ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL :
4819  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4820  p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]);
4821 
4822  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
4823  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
4824  .pImageMemoryBarriers = img_bar,
4825  .imageMemoryBarrierCount = nb_img_bar,
4826  });
4827 
4828  for (int i = 0; i < planes; i++) {
4829  int buf_idx = FFMIN(i, (nb_bufs - 1));
4830  int img_idx = FFMIN(i, (nb_images - 1));
4831  FFVkBuffer *vkbuf = (FFVkBuffer *)bufs[buf_idx]->data;
4832 
4833  uint32_t orig_stride = region[i].bufferRowLength;
4834  region[i].bufferRowLength /= desc->comp[i].step;
4835  region[i].imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
4836 
4837  if (upload)
4838  vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf,
4839  hwf_vk->img[img_idx],
4840  img_bar[img_idx].newLayout,
4841  1, &region[i]);
4842  else
4843  vk->CmdCopyImageToBuffer(cmd_buf, hwf_vk->img[img_idx],
4844  img_bar[img_idx].newLayout,
4845  vkbuf->buf,
4846  1, &region[i]);
4847 
4848  region[i].bufferRowLength = orig_stride;
4849  }
4850 
4851  err = ff_vk_exec_submit(&p->vkctx, exec);
4852  if (err < 0) {
4853  ff_vk_exec_discard_deps(&p->vkctx, exec);
4854  } else if (!upload) {
4855  ff_vk_exec_wait(&p->vkctx, exec);
4856  if (!host_mapped)
4857  err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 0);
4858  }
4859 
4860 end:
4861  for (int i = 0; i < nb_bufs; i++)
4862  av_buffer_unref(&bufs[i]);
4863 
4864  return err;
4865 }
4866 
4868  const AVFrame *src)
4869 {
4870  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4871 
4872  switch (src->format) {
4873 #if CONFIG_CUDA
4874  case AV_PIX_FMT_CUDA:
4875 #ifdef _WIN32
4876  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4877  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4878 #else
4879  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4880  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4881 #endif
4882  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
4883 #endif
4884  default:
4885  if (src->hw_frames_ctx)
4886  return AVERROR(ENOSYS);
4887  else
4888  return vulkan_transfer_frame(hwfc, (AVFrame *)src, dst, 1);
4889  }
4890 }
4891 
4892 #if CONFIG_CUDA
4893 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
4894  const AVFrame *src)
4895 {
4896  int err;
4897  CUcontext dummy;
4898  AVVkFrame *dst_f;
4899  AVVkFrameInternal *dst_int;
4900  VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
4901  VulkanFramesPriv *fp = hwfc->hwctx;
4902  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4904  int nb_images;
4905 
4906  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)dst->hw_frames_ctx->data;
4907  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4908  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4909  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4910  CudaFunctions *cu = cu_internal->cuda_dl;
4911  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4912  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4913 
4914  dst_f = (AVVkFrame *)src->data[0];
4915  nb_images = ff_vk_count_images(dst_f);
4916 
4917  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4918  if (err < 0)
4919  return err;
4920 
4921  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4922  if (err < 0)
4923  return err;
4924 
4925  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
4926  if (err < 0) {
4927  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4928  return err;
4929  }
4930 
4931  dst_int = dst_f->internal;
4932 
4933  for (int i = 0; i < planes; i++) {
4934  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4935  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4936  }
4937 
4938  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4939  nb_images, cuda_dev->stream));
4940  if (err < 0)
4941  goto fail;
4942 
4943  for (int i = 0; i < planes; i++) {
4944  CUDA_MEMCPY2D cpy = {
4945  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
4946  .dstDevice = (CUdeviceptr)dst->data[i],
4947  .dstPitch = dst->linesize[i],
4948  .dstY = 0,
4949 
4950  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
4951  .srcArray = dst_int->cu_array[i],
4952  };
4953 
4954  int w, h;
4955  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4956 
4957  cpy.WidthInBytes = w * desc->comp[i].step;
4958  cpy.Height = h;
4959 
4960  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4961  if (err < 0)
4962  goto fail;
4963  }
4964 
4965  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4966  nb_images, cuda_dev->stream));
4967  if (err < 0)
4968  goto fail;
4969 
4970  for (int i = 0; i < planes; i++)
4971  dst_f->sem_value[i]++;
4972 
4973  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4974 
4975  av_log(hwfc, AV_LOG_VERBOSE, "Transferred Vulkan image to CUDA!\n");
4976 
4977  return prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4978 
4979 fail:
4980  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4981  vulkan_free_internal(p, dst_f);
4982  av_buffer_unref(&dst->buf[0]);
4983  return err;
4984 }
4985 #endif
4986 
4988  const AVFrame *src)
4989 {
4991 
4992  switch (dst->format) {
4993 #if CONFIG_CUDA
4994  case AV_PIX_FMT_CUDA:
4995 #ifdef _WIN32
4996  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4997  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4998 #else
4999  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
5000  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
5001 #endif
5002  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
5003 #endif
5004  default:
5005  if (dst->hw_frames_ctx)
5006  return AVERROR(ENOSYS);
5007  else
5008  return vulkan_transfer_frame(hwfc, dst, (AVFrame *)src, 0);
5009  }
5010 }
5011 
5013  AVHWFramesContext *src_fc, int flags)
5014 {
5015  return vulkan_frames_init(dst_fc);
5016 }
5017 
5019 {
5020  int err;
5021  AVVkFrame *f = av_mallocz(sizeof(AVVkFrame));
5022  if (!f)
5023  return NULL;
5024 
5025  f->internal = av_mallocz(sizeof(*f->internal));
5026  if (!f->internal) {
5027  av_free(f);
5028  return NULL;
5029  }
5030 
5031  err = pthread_mutex_init(&f->internal->update_mutex, NULL);
5032  if (err != 0) {
5033  av_free(f->internal);
5034  av_free(f);
5035  return NULL;
5036  }
5037 
5038  return f;
5039 }
5040 
5043  .name = "Vulkan",
5044 
5045  .device_hwctx_size = sizeof(VulkanDevicePriv),
5046  .frames_hwctx_size = sizeof(VulkanFramesPriv),
5047 
5048  .device_init = &vulkan_device_init,
5049  .device_uninit = &vulkan_device_uninit,
5050  .device_create = &vulkan_device_create,
5051  .device_derive = &vulkan_device_derive,
5052 
5053  .frames_get_constraints = &vulkan_frames_get_constraints,
5054  .frames_init = vulkan_frames_init,
5055  .frames_get_buffer = vulkan_get_buffer,
5056  .frames_uninit = vulkan_frames_uninit,
5057 
5058  .transfer_get_formats = vulkan_transfer_get_formats,
5059  .transfer_data_to = vulkan_transfer_data_to,
5060  .transfer_data_from = vulkan_transfer_data_from,
5061 
5062  .map_to = vulkan_map_to,
5063  .map_from = vulkan_map_from,
5064  .frames_derive_to = &vulkan_frames_derive_to,
5065 
5066  .pix_fmts = (const enum AVPixelFormat []) {
5069  },
5070 };
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:4530
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:4867
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:5012
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:4422
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:2979
fail
#define fail()
Definition: checkasm.h:223
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:4104
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:4706
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:2989
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:3252
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:5041
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:2900
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:5018
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:4987
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
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:3007
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:3238
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:4587
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:4491
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:2984
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:4448
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
planes
static const struct @584 planes[]
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