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