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