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