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