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