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