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