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