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