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