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