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