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