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