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 #endif
31 
32 #include "thread.h"
33 #include <unistd.h>
34 
35 #include "config.h"
36 #include "pixdesc.h"
37 #include "avstring.h"
38 #include "imgutils.h"
39 #include "hwcontext.h"
40 #include "avassert.h"
41 #include "hwcontext_internal.h"
42 #include "hwcontext_vulkan.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 CONFIG_CUDA
66 #include "cuda_check.h"
67 #define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x)
68 #endif
69 
70 typedef struct VulkanQueueCtx {
71  VkFence fence;
72  VkQueue queue;
74  int qf;
75  int qidx;
76 
77  /* Buffer dependencies */
80  unsigned int buf_deps_alloc_size;
82 
83 typedef struct VulkanDevicePriv {
84  /* Vulkan library and loader functions */
85  void *libvulkan;
86 
90 
91  /* Properties */
92  VkPhysicalDeviceProperties2 props;
93  VkPhysicalDeviceMemoryProperties mprops;
94  VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops;
95 
96  /* Features */
97  VkPhysicalDeviceVulkan11Features device_features_1_1;
98  VkPhysicalDeviceVulkan12Features device_features_1_2;
99  VkPhysicalDeviceVulkan13Features device_features_1_3;
100  VkPhysicalDeviceDescriptorBufferFeaturesEXT desc_buf_features;
101  VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_features;
102  VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_matrix_features;
103 
104  /* Queues */
106  uint32_t nb_tot_qfs;
107  uint32_t img_qfs[5];
108  uint32_t nb_img_qfs;
109 
110  /* Debug callback */
111  VkDebugUtilsMessengerEXT debug_ctx;
112 
113  /* Settings */
115 
116  /* Option to allocate all image planes in a single allocation */
118 
119  /* Disable multiplane images */
121 
122  /* Nvidia */
125 
126 typedef struct VulkanFramesPriv {
127  /* Image conversions */
129 
130  /* Image transfers */
133 
134  /* Modifier info list to free at uninit */
135  VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
137 
138 typedef struct AVVkFrameInternal {
140 
141 #if CONFIG_CUDA
142  /* Importing external memory into cuda is really expensive so we keep the
143  * memory imported all the time */
144  AVBufferRef *cuda_fc_ref; /* Need to keep it around for uninit */
145  CUexternalMemory ext_mem[AV_NUM_DATA_POINTERS];
146  CUmipmappedArray cu_mma[AV_NUM_DATA_POINTERS];
147  CUarray cu_array[AV_NUM_DATA_POINTERS];
148  CUexternalSemaphore cu_sem[AV_NUM_DATA_POINTERS];
149 #ifdef _WIN32
150  HANDLE ext_mem_handle[AV_NUM_DATA_POINTERS];
151  HANDLE ext_sem_handle[AV_NUM_DATA_POINTERS];
152 #endif
153 #endif
155 
156 #define ASPECT_2PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT)
157 #define ASPECT_3PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)
158 
159 static const struct FFVkFormatEntry {
162  VkImageAspectFlags aspect;
166  const VkFormat fallback[5];
167 } vk_formats_list[] = {
168  /* Gray formats */
169  { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GRAY8, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8_UNORM } },
170  { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GRAY16, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16_UNORM } },
171  { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GRAYF32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R32_SFLOAT } },
172 
173  /* RGB formats */
174  { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
175  { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGRA, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_B8G8R8A8_UNORM } },
176  { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGBA, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
177  { VK_FORMAT_R8G8B8_UNORM, AV_PIX_FMT_RGB24, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8_UNORM } },
178  { VK_FORMAT_B8G8R8_UNORM, AV_PIX_FMT_BGR24, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_B8G8R8_UNORM } },
179  { VK_FORMAT_R16G16B16_UNORM, AV_PIX_FMT_RGB48, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16_UNORM } },
180  { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_RGBA64, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
181  { VK_FORMAT_R5G6B5_UNORM_PACK16, AV_PIX_FMT_RGB565, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R5G6B5_UNORM_PACK16 } },
182  { VK_FORMAT_B5G6R5_UNORM_PACK16, AV_PIX_FMT_BGR565, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_B5G6R5_UNORM_PACK16 } },
183  { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGR0, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_B8G8R8A8_UNORM } },
184  { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGB0, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
185  { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_X2RGB10, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 } },
186 
187  /* Planar RGB */
188  { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GBRAP, VK_IMAGE_ASPECT_COLOR_BIT, 1, 4, 4, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
189  { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAP16, VK_IMAGE_ASPECT_COLOR_BIT, 1, 4, 4, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
190  { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GBRPF32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 3, 3, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
191  { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GBRAPF32, VK_IMAGE_ASPECT_COLOR_BIT, 1, 4, 4, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
192 
193  /* Two-plane 420 YUV at 8, 10, 12 and 16 bits */
194  { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, AV_PIX_FMT_NV12, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
195  { 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 } },
196  { 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 } },
197  { VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, AV_PIX_FMT_P016, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
198 
199  /* Two-plane 422 YUV at 8, 10 and 16 bits */
200  { VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, AV_PIX_FMT_NV16, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
201  { 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 } },
202  { 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 } },
203  { VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, AV_PIX_FMT_P216, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
204 
205  /* Two-plane 444 YUV at 8, 10 and 16 bits */
206  { VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, AV_PIX_FMT_NV24, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
207  { 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 } },
208  { 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 } },
209  { VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, AV_PIX_FMT_P416, ASPECT_2PLANE, 2, 1, 2, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
210 
211  /* Three-plane 420, 422, 444 at 8, 10, 12 and 16 bits */
212  { 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 } },
213  { 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 } },
214  { 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 } },
215  { 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 } },
216  { 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 } },
217  { 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 } },
218  { 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 } },
219  { 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 } },
220  { 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 } },
221  { 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 } },
222  { 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 } },
223  { 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 } },
224 
225  /* Single plane 422 at 8, 10 and 12 bits */
226  { VK_FORMAT_G8B8G8R8_422_UNORM, AV_PIX_FMT_YUYV422, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
227  { VK_FORMAT_B8G8R8G8_422_UNORM, AV_PIX_FMT_UYVY422, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } },
228  { VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, AV_PIX_FMT_Y210, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
229  { VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, AV_PIX_FMT_Y212, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R16G16B16A16_UNORM } },
230 };
232 
234 {
235  for (int i = 0; i < nb_vk_formats_list; i++)
236  if (vk_formats_list[i].pixfmt == p)
237  return vk_formats_list[i].fallback;
238  return NULL;
239 }
240 
242 {
243  for (int i = 0; i < nb_vk_formats_list; i++)
244  if (vk_formats_list[i].pixfmt == p)
245  return &vk_formats_list[i];
246  return NULL;
247 }
248 
249 /* Malitia pura, Khronos */
250 #define FN_MAP_TO(dst_t, dst_name, src_t, src_name) \
251  static av_unused dst_t map_ ##src_name## _to_ ##dst_name(src_t src) \
252  { \
253  dst_t dst = 0x0; \
254  MAP_TO(VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT, \
255  VK_IMAGE_USAGE_SAMPLED_BIT); \
256  MAP_TO(VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT, \
257  VK_IMAGE_USAGE_TRANSFER_SRC_BIT); \
258  MAP_TO(VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT, \
259  VK_IMAGE_USAGE_TRANSFER_DST_BIT); \
260  MAP_TO(VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT, \
261  VK_IMAGE_USAGE_STORAGE_BIT); \
262  MAP_TO(VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT, \
263  VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); \
264  MAP_TO(VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR, \
265  VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR); \
266  MAP_TO(VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR, \
267  VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR); \
268  MAP_TO(VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR, \
269  VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR); \
270  MAP_TO(VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR, \
271  VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR); \
272  return dst; \
273  }
274 
275 #define MAP_TO(flag1, flag2) if (src & flag2) dst |= flag1;
276 FN_MAP_TO(VkFormatFeatureFlagBits2, feats, VkImageUsageFlags, usage)
277 #undef MAP_TO
278 #define MAP_TO(flag1, flag2) if (src & flag1) dst |= flag2;
279 FN_MAP_TO(VkImageUsageFlags, usage, VkFormatFeatureFlagBits2, feats)
280 #undef MAP_TO
281 #undef FN_MAP_TO
282 
284  VkImageTiling tiling,
286  int *nb_images, VkImageAspectFlags *aspect,
287  VkImageUsageFlags *supported_usage, int disable_multiplane)
288 {
289  AVVulkanDeviceContext *hwctx = dev_ctx->hwctx;
290  VulkanDevicePriv *priv = dev_ctx->internal->priv;
291  FFVulkanFunctions *vk = &priv->vkctx.vkfn;
292 
293  const VkFormatFeatureFlagBits2 basic_flags = VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT |
294  VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
295  VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT;
296 
297  for (int i = 0; i < nb_vk_formats_list; i++) {
298  if (vk_formats_list[i].pixfmt == p) {
299  VkFormatProperties2 prop = {
300  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
301  };
302  VkFormatFeatureFlagBits2 feats_primary, feats_secondary;
303  int basics_primary = 0, basics_secondary = 0;
304 
305  vk->GetPhysicalDeviceFormatProperties2(hwctx->phys_dev,
307  &prop);
308 
309  feats_primary = tiling == VK_IMAGE_TILING_LINEAR ?
310  prop.formatProperties.linearTilingFeatures :
311  prop.formatProperties.optimalTilingFeatures;
312  basics_primary = (feats_primary & basic_flags) == basic_flags;
313 
315  vk->GetPhysicalDeviceFormatProperties2(hwctx->phys_dev,
317  &prop);
318  feats_secondary = tiling == VK_IMAGE_TILING_LINEAR ?
319  prop.formatProperties.linearTilingFeatures :
320  prop.formatProperties.optimalTilingFeatures;
321  basics_secondary = (feats_secondary & basic_flags) == basic_flags;
322  } else {
323  basics_secondary = basics_primary;
324  }
325 
326  if (basics_primary && !(disable_multiplane && vk_formats_list[i].vk_planes > 1)) {
327  if (fmts)
328  fmts[0] = vk_formats_list[i].vkf;
329  if (nb_images)
330  *nb_images = 1;
331  if (aspect)
333  if (supported_usage)
334  *supported_usage = map_feats_to_usage(feats_primary);
335  return 0;
336  } else if (basics_secondary) {
337  if (fmts) {
338  for (int j = 0; j < vk_formats_list[i].nb_images_fallback; j++)
339  fmts[j] = vk_formats_list[i].fallback[j];
340  }
341  if (nb_images)
343  if (aspect)
345  if (supported_usage)
346  *supported_usage = map_feats_to_usage(feats_secondary);
347  return 0;
348  } else {
349  return AVERROR(ENOTSUP);
350  }
351  }
352  }
353 
354  return AVERROR(EINVAL);
355 }
356 
358 {
359  AVVulkanDeviceContext *hwctx = ctx->hwctx;
360  VulkanDevicePriv *p = ctx->internal->priv;
361 
362  static const char *lib_names[] = {
363 #if defined(_WIN32)
364  "vulkan-1.dll",
365 #elif defined(__APPLE__)
366  "libvulkan.dylib",
367  "libvulkan.1.dylib",
368  "libMoltenVK.dylib",
369 #else
370  "libvulkan.so.1",
371  "libvulkan.so",
372 #endif
373  };
374 
375  for (int i = 0; i < FF_ARRAY_ELEMS(lib_names); i++) {
376  p->libvulkan = dlopen(lib_names[i], RTLD_NOW | RTLD_LOCAL);
377  if (p->libvulkan)
378  break;
379  }
380 
381  if (!p->libvulkan) {
382  av_log(ctx, AV_LOG_ERROR, "Unable to open the libvulkan library!\n");
383  return AVERROR_UNKNOWN;
384  }
385 
386  hwctx->get_proc_addr = (PFN_vkGetInstanceProcAddr)dlsym(p->libvulkan, "vkGetInstanceProcAddr");
387 
388  return 0;
389 }
390 
391 typedef struct VulkanOptExtension {
392  const char *name;
395 
397  /* Pointless, here avoid zero-sized structs */
398  { VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
399 };
400 
402  /* Misc or required by other extensions */
403  { VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
404  { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
405  { VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
406  { VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, FF_VK_EXT_DESCRIPTOR_BUFFER, },
407  { VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, FF_VK_EXT_DEVICE_DRM },
408  { VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, FF_VK_EXT_ATOMIC_FLOAT },
409  { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, FF_VK_EXT_COOP_MATRIX },
410 
411  /* Imports/exports */
412  { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_MEMORY },
413  { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_DMABUF_MEMORY },
414  { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS },
415  { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_SEM },
416  { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_HOST_MEMORY },
417 #ifdef _WIN32
418  { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY },
419  { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM },
420 #endif
421 
422  /* Video encoding/decoding */
423  { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_QUEUE },
424  { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_QUEUE },
425  { VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H264 },
426  { VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H265 },
427  { "VK_MESA_video_decode_av1", FF_VK_EXT_VIDEO_DECODE_AV1 },
428 };
429 
430 static VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
431  VkDebugUtilsMessageTypeFlagsEXT messageType,
432  const VkDebugUtilsMessengerCallbackDataEXT *data,
433  void *priv)
434 {
435  int l;
436  AVHWDeviceContext *ctx = priv;
437 
438  switch (severity) {
439  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: l = AV_LOG_VERBOSE; break;
440  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: l = AV_LOG_INFO; break;
441  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: l = AV_LOG_WARNING; break;
442  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: l = AV_LOG_ERROR; break;
443  default: l = AV_LOG_DEBUG; break;
444  }
445 
446  av_log(ctx, l, "%s\n", data->pMessage);
447  for (int i = 0; i < data->cmdBufLabelCount; i++)
448  av_log(ctx, l, "\t%i: %s\n", i, data->pCmdBufLabels[i].pLabelName);
449 
450  return 0;
451 }
452 
453 #define ADD_VAL_TO_LIST(list, count, val) \
454  do { \
455  list = av_realloc_array(list, sizeof(*list), ++count); \
456  if (!list) { \
457  err = AVERROR(ENOMEM); \
458  goto fail; \
459  } \
460  list[count - 1] = av_strdup(val); \
461  if (!list[count - 1]) { \
462  err = AVERROR(ENOMEM); \
463  goto fail; \
464  } \
465  } while(0)
466 
467 #define RELEASE_PROPS(props, count) \
468  if (props) { \
469  for (int i = 0; i < count; i++) \
470  av_free((void *)((props)[i])); \
471  av_free((void *)props); \
472  }
473 
475  const char * const **dst, uint32_t *num, int debug)
476 {
477  const char *tstr;
478  const char **extension_names = NULL;
479  VulkanDevicePriv *p = ctx->internal->priv;
480  FFVulkanFunctions *vk = &p->vkctx.vkfn;
481  AVVulkanDeviceContext *hwctx = ctx->hwctx;
482  int err = 0, found, extensions_found = 0;
483 
484  const char *mod;
485  int optional_exts_num;
486  uint32_t sup_ext_count;
487  char *user_exts_str = NULL;
488  AVDictionaryEntry *user_exts;
489  VkExtensionProperties *sup_ext;
490  const VulkanOptExtension *optional_exts;
491 
492  if (!dev) {
493  mod = "instance";
494  optional_exts = optional_instance_exts;
495  optional_exts_num = FF_ARRAY_ELEMS(optional_instance_exts);
496  user_exts = av_dict_get(opts, "instance_extensions", NULL, 0);
497  if (user_exts) {
498  user_exts_str = av_strdup(user_exts->value);
499  if (!user_exts_str) {
500  err = AVERROR(ENOMEM);
501  goto fail;
502  }
503  }
504  vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL);
505  sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
506  if (!sup_ext)
507  return AVERROR(ENOMEM);
508  vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, sup_ext);
509  } else {
510  mod = "device";
511  optional_exts = optional_device_exts;
512  optional_exts_num = FF_ARRAY_ELEMS(optional_device_exts);
513  user_exts = av_dict_get(opts, "device_extensions", NULL, 0);
514  if (user_exts) {
515  user_exts_str = av_strdup(user_exts->value);
516  if (!user_exts_str) {
517  err = AVERROR(ENOMEM);
518  goto fail;
519  }
520  }
521  vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
522  &sup_ext_count, NULL);
523  sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
524  if (!sup_ext)
525  return AVERROR(ENOMEM);
526  vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
527  &sup_ext_count, sup_ext);
528  }
529 
530  for (int i = 0; i < optional_exts_num; i++) {
531  tstr = optional_exts[i].name;
532  found = 0;
533  for (int j = 0; j < sup_ext_count; j++) {
534  if (!strcmp(tstr, sup_ext[j].extensionName)) {
535  found = 1;
536  break;
537  }
538  }
539  if (!found)
540  continue;
541 
542  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr);
543  p->vkctx.extensions |= optional_exts[i].flag;
544  ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
545  }
546 
547  if (debug && !dev) {
548  tstr = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
549  found = 0;
550  for (int j = 0; j < sup_ext_count; j++) {
551  if (!strcmp(tstr, sup_ext[j].extensionName)) {
552  found = 1;
553  break;
554  }
555  }
556  if (found) {
557  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr);
558  ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
560  } else {
561  av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n",
562  tstr);
563  err = AVERROR(EINVAL);
564  goto fail;
565  }
566  }
567 
568  if (user_exts_str) {
569  char *save, *token = av_strtok(user_exts_str, "+", &save);
570  while (token) {
571  found = 0;
572  for (int j = 0; j < sup_ext_count; j++) {
573  if (!strcmp(token, sup_ext[j].extensionName)) {
574  found = 1;
575  break;
576  }
577  }
578  if (found) {
579  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, token);
580  ADD_VAL_TO_LIST(extension_names, extensions_found, token);
581  } else {
582  av_log(ctx, AV_LOG_WARNING, "%s extension \"%s\" not found, excluding.\n",
583  mod, token);
584  }
585  token = av_strtok(NULL, "+", &save);
586  }
587  }
588 
589  *dst = extension_names;
590  *num = extensions_found;
591 
592  av_free(user_exts_str);
593  av_free(sup_ext);
594  return 0;
595 
596 fail:
597  RELEASE_PROPS(extension_names, extensions_found);
598  av_free(user_exts_str);
599  av_free(sup_ext);
600  return err;
601 }
602 
604  const char * const **dst, uint32_t *num,
605  int *debug_mode)
606 {
607  static const char default_layer[] = { "VK_LAYER_KHRONOS_validation" };
608 
609  int found = 0, err = 0;
610  VulkanDevicePriv *priv = ctx->internal->priv;
611  FFVulkanFunctions *vk = &priv->vkctx.vkfn;
612 
613  uint32_t sup_layer_count;
614  VkLayerProperties *sup_layers;
615 
616  AVDictionaryEntry *user_layers;
617  char *user_layers_str = NULL;
618  char *save, *token;
619 
620  const char **enabled_layers = NULL;
621  uint32_t enabled_layers_count = 0;
622 
623  AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
624  int debug = debug_opt && strtol(debug_opt->value, NULL, 10);
625 
626  /* If `debug=0`, enable no layers at all. */
627  if (debug_opt && !debug)
628  return 0;
629 
630  vk->EnumerateInstanceLayerProperties(&sup_layer_count, NULL);
631  sup_layers = av_malloc_array(sup_layer_count, sizeof(VkLayerProperties));
632  if (!sup_layers)
633  return AVERROR(ENOMEM);
634  vk->EnumerateInstanceLayerProperties(&sup_layer_count, sup_layers);
635 
636  av_log(ctx, AV_LOG_VERBOSE, "Supported validation layers:\n");
637  for (int i = 0; i < sup_layer_count; i++)
638  av_log(ctx, AV_LOG_VERBOSE, "\t%s\n", sup_layers[i].layerName);
639 
640  /* If `debug=1` is specified, enable the standard validation layer extension */
641  if (debug) {
642  *debug_mode = debug;
643  for (int i = 0; i < sup_layer_count; i++) {
644  if (!strcmp(default_layer, sup_layers[i].layerName)) {
645  found = 1;
646  av_log(ctx, AV_LOG_VERBOSE, "Default validation layer %s is enabled\n",
647  default_layer);
648  ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, default_layer);
649  break;
650  }
651  }
652  }
653 
654  user_layers = av_dict_get(opts, "validation_layers", NULL, 0);
655  if (!user_layers)
656  goto end;
657 
658  user_layers_str = av_strdup(user_layers->value);
659  if (!user_layers_str) {
660  err = AVERROR(ENOMEM);
661  goto fail;
662  }
663 
664  token = av_strtok(user_layers_str, "+", &save);
665  while (token) {
666  found = 0;
667  if (!strcmp(default_layer, token)) {
668  if (debug) {
669  /* if the `debug=1`, default_layer is enabled, skip here */
670  token = av_strtok(NULL, "+", &save);
671  continue;
672  } else {
673  /* if the `debug=0`, enable debug mode to load its callback properly */
674  *debug_mode = debug;
675  }
676  }
677  for (int j = 0; j < sup_layer_count; j++) {
678  if (!strcmp(token, sup_layers[j].layerName)) {
679  found = 1;
680  break;
681  }
682  }
683  if (found) {
684  av_log(ctx, AV_LOG_VERBOSE, "Requested Validation Layer: %s\n", token);
685  ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token);
686  } else {
688  "Validation Layer \"%s\" not support.\n", token);
689  err = AVERROR(EINVAL);
690  goto fail;
691  }
692  token = av_strtok(NULL, "+", &save);
693  }
694 
695  av_free(user_layers_str);
696 
697 end:
698  av_free(sup_layers);
699 
700  *dst = enabled_layers;
701  *num = enabled_layers_count;
702 
703  return 0;
704 
705 fail:
706  RELEASE_PROPS(enabled_layers, enabled_layers_count);
707  av_free(sup_layers);
708  av_free(user_layers_str);
709  return err;
710 }
711 
712 /* Creates a VkInstance */
714 {
715  int err = 0, debug_mode = 0;
716  VkResult ret;
717  VulkanDevicePriv *p = ctx->internal->priv;
718  FFVulkanFunctions *vk = &p->vkctx.vkfn;
719  AVVulkanDeviceContext *hwctx = ctx->hwctx;
720  VkApplicationInfo application_info = {
721  .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
722  .pApplicationName = "ffmpeg",
723  .applicationVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR,
726  .pEngineName = "libavutil",
727  .apiVersion = VK_API_VERSION_1_3,
728  .engineVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR,
731  };
732  VkValidationFeaturesEXT validation_features = {
733  .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
734  };
735  VkInstanceCreateInfo inst_props = {
736  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
737  .pApplicationInfo = &application_info,
738  };
739 
740  if (!hwctx->get_proc_addr) {
741  err = load_libvulkan(ctx);
742  if (err < 0)
743  return err;
744  }
745 
746  err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 0, 0);
747  if (err < 0) {
748  av_log(ctx, AV_LOG_ERROR, "Unable to load instance enumeration functions!\n");
749  return err;
750  }
751 
752  err = check_validation_layers(ctx, opts, &inst_props.ppEnabledLayerNames,
753  &inst_props.enabledLayerCount, &debug_mode);
754  if (err)
755  goto fail;
756 
757  /* Check for present/missing extensions */
758  err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames,
759  &inst_props.enabledExtensionCount, debug_mode);
760  hwctx->enabled_inst_extensions = inst_props.ppEnabledExtensionNames;
761  hwctx->nb_enabled_inst_extensions = inst_props.enabledExtensionCount;
762  if (err < 0)
763  goto fail;
764 
765  if (debug_mode) {
766  VkValidationFeatureEnableEXT feat_list[] = {
767  VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
768  VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
769  VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
770  };
771  validation_features.pEnabledValidationFeatures = feat_list;
772  validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list);
773  inst_props.pNext = &validation_features;
774  }
775 
776  /* Try to create the instance */
777  ret = vk->CreateInstance(&inst_props, hwctx->alloc, &hwctx->inst);
778 
779  /* Check for errors */
780  if (ret != VK_SUCCESS) {
781  av_log(ctx, AV_LOG_ERROR, "Instance creation failure: %s\n",
782  ff_vk_ret2str(ret));
783  err = AVERROR_EXTERNAL;
784  goto fail;
785  }
786 
787  err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 1, 0);
788  if (err < 0) {
789  av_log(ctx, AV_LOG_ERROR, "Unable to load instance functions!\n");
790  goto fail;
791  }
792 
793  if (debug_mode) {
794  VkDebugUtilsMessengerCreateInfoEXT dbg = {
795  .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
796  .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
797  VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
798  VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
799  VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
800  .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
801  VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
802  VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
803  .pfnUserCallback = vk_dbg_callback,
804  .pUserData = ctx,
805  };
806 
807  vk->CreateDebugUtilsMessengerEXT(hwctx->inst, &dbg,
808  hwctx->alloc, &p->debug_ctx);
809  }
810 
811  err = 0;
812 
813 fail:
814  RELEASE_PROPS(inst_props.ppEnabledLayerNames, inst_props.enabledLayerCount);
815  return err;
816 }
817 
818 typedef struct VulkanDeviceSelection {
819  uint8_t uuid[VK_UUID_SIZE]; /* Will use this first unless !has_uuid */
820  int has_uuid;
821  uint32_t drm_major; /* Will use this second unless !has_drm */
822  uint32_t drm_minor; /* Will use this second unless !has_drm */
823  uint32_t has_drm; /* has drm node info */
824  const char *name; /* Will use this third unless NULL */
825  uint32_t pci_device; /* Will use this fourth unless 0x0 */
826  uint32_t vendor_id; /* Last resort to find something deterministic */
827  int index; /* Finally fall back to index */
829 
830 static const char *vk_dev_type(enum VkPhysicalDeviceType type)
831 {
832  switch (type) {
833  case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "integrated";
834  case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "discrete";
835  case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "virtual";
836  case VK_PHYSICAL_DEVICE_TYPE_CPU: return "software";
837  default: return "unknown";
838  }
839 }
840 
841 /* Finds a device */
843 {
844  int err = 0, choice = -1;
845  uint32_t num;
846  VkResult ret;
847  VulkanDevicePriv *p = ctx->internal->priv;
848  FFVulkanFunctions *vk = &p->vkctx.vkfn;
849  VkPhysicalDevice *devices = NULL;
850  VkPhysicalDeviceIDProperties *idp = NULL;
851  VkPhysicalDeviceProperties2 *prop = NULL;
852  VkPhysicalDeviceDrmPropertiesEXT *drm_prop = NULL;
853  AVVulkanDeviceContext *hwctx = ctx->hwctx;
854 
855  ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, NULL);
856  if (ret != VK_SUCCESS || !num) {
857  av_log(ctx, AV_LOG_ERROR, "No devices found: %s!\n", ff_vk_ret2str(ret));
858  return AVERROR(ENODEV);
859  }
860 
861  devices = av_malloc_array(num, sizeof(VkPhysicalDevice));
862  if (!devices)
863  return AVERROR(ENOMEM);
864 
865  ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, devices);
866  if (ret != VK_SUCCESS) {
867  av_log(ctx, AV_LOG_ERROR, "Failed enumerating devices: %s\n",
868  ff_vk_ret2str(ret));
869  err = AVERROR(ENODEV);
870  goto end;
871  }
872 
873  prop = av_calloc(num, sizeof(*prop));
874  if (!prop) {
875  err = AVERROR(ENOMEM);
876  goto end;
877  }
878 
879  idp = av_calloc(num, sizeof(*idp));
880  if (!idp) {
881  err = AVERROR(ENOMEM);
882  goto end;
883  }
884 
886  drm_prop = av_calloc(num, sizeof(*drm_prop));
887  if (!drm_prop) {
888  err = AVERROR(ENOMEM);
889  goto end;
890  }
891  }
892 
893  av_log(ctx, AV_LOG_VERBOSE, "GPU listing:\n");
894  for (int i = 0; i < num; i++) {
896  drm_prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
897  idp[i].pNext = &drm_prop[i];
898  }
899  idp[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
900  prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
901  prop[i].pNext = &idp[i];
902 
903  vk->GetPhysicalDeviceProperties2(devices[i], &prop[i]);
904  av_log(ctx, AV_LOG_VERBOSE, " %d: %s (%s) (0x%x)\n", i,
905  prop[i].properties.deviceName,
906  vk_dev_type(prop[i].properties.deviceType),
907  prop[i].properties.deviceID);
908  }
909 
910  if (select->has_uuid) {
911  for (int i = 0; i < num; i++) {
912  if (!strncmp(idp[i].deviceUUID, select->uuid, VK_UUID_SIZE)) {
913  choice = i;
914  goto end;
915  }
916  }
917  av_log(ctx, AV_LOG_ERROR, "Unable to find device by given UUID!\n");
918  err = AVERROR(ENODEV);
919  goto end;
920  } else if ((p->vkctx.extensions & FF_VK_EXT_DEVICE_DRM) && select->has_drm) {
921  for (int i = 0; i < num; i++) {
922  if ((select->drm_major == drm_prop[i].primaryMajor &&
923  select->drm_minor == drm_prop[i].primaryMinor) ||
924  (select->drm_major == drm_prop[i].renderMajor &&
925  select->drm_minor == drm_prop[i].renderMinor)) {
926  choice = i;
927  goto end;
928  }
929  }
930  av_log(ctx, AV_LOG_ERROR, "Unable to find device by given DRM node numbers %i:%i!\n",
931  select->drm_major, select->drm_minor);
932  err = AVERROR(ENODEV);
933  goto end;
934  } else if (select->name) {
935  av_log(ctx, AV_LOG_VERBOSE, "Requested device: %s\n", select->name);
936  for (int i = 0; i < num; i++) {
937  if (strstr(prop[i].properties.deviceName, select->name)) {
938  choice = i;
939  goto end;
940  }
941  }
942  av_log(ctx, AV_LOG_ERROR, "Unable to find device \"%s\"!\n",
943  select->name);
944  err = AVERROR(ENODEV);
945  goto end;
946  } else if (select->pci_device) {
947  av_log(ctx, AV_LOG_VERBOSE, "Requested device: 0x%x\n", select->pci_device);
948  for (int i = 0; i < num; i++) {
949  if (select->pci_device == prop[i].properties.deviceID) {
950  choice = i;
951  goto end;
952  }
953  }
954  av_log(ctx, AV_LOG_ERROR, "Unable to find device with PCI ID 0x%x!\n",
955  select->pci_device);
956  err = AVERROR(EINVAL);
957  goto end;
958  } else if (select->vendor_id) {
959  av_log(ctx, AV_LOG_VERBOSE, "Requested vendor: 0x%x\n", select->vendor_id);
960  for (int i = 0; i < num; i++) {
961  if (select->vendor_id == prop[i].properties.vendorID) {
962  choice = i;
963  goto end;
964  }
965  }
966  av_log(ctx, AV_LOG_ERROR, "Unable to find device with Vendor ID 0x%x!\n",
967  select->vendor_id);
968  err = AVERROR(ENODEV);
969  goto end;
970  } else {
971  if (select->index < num) {
972  choice = select->index;
973  goto end;
974  }
975  av_log(ctx, AV_LOG_ERROR, "Unable to find device with index %i!\n",
976  select->index);
977  err = AVERROR(ENODEV);
978  goto end;
979  }
980 
981 end:
982  if (choice > -1) {
983  av_log(ctx, AV_LOG_VERBOSE, "Device %d selected: %s (%s) (0x%x)\n",
984  choice, prop[choice].properties.deviceName,
985  vk_dev_type(prop[choice].properties.deviceType),
986  prop[choice].properties.deviceID);
987  hwctx->phys_dev = devices[choice];
988  }
989 
990  av_free(devices);
991  av_free(prop);
992  av_free(idp);
993  av_free(drm_prop);
994 
995  return err;
996 }
997 
998 /* Picks the least used qf with the fewest unneeded flags, or -1 if none found */
999 static inline int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf,
1000  VkQueueFlagBits flags)
1001 {
1002  int index = -1;
1003  uint32_t min_score = UINT32_MAX;
1004 
1005  for (int i = 0; i < num_qf; i++) {
1006  const VkQueueFlagBits qflags = qf[i].queueFlags;
1007  if (qflags & flags) {
1008  uint32_t score = av_popcount(qflags) + qf[i].timestampValidBits;
1009  if (score < min_score) {
1010  index = i;
1011  min_score = score;
1012  }
1013  }
1014  }
1015 
1016  if (index > -1)
1017  qf[index].timestampValidBits++;
1018 
1019  return index;
1020 }
1021 
1022 static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
1023 {
1024  uint32_t num;
1025  float *weights;
1026  VkQueueFamilyProperties *qf = NULL;
1027  VulkanDevicePriv *p = ctx->internal->priv;
1028  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1029  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1030  int graph_index, comp_index, tx_index, enc_index, dec_index;
1031 
1032  /* First get the number of queue families */
1033  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, NULL);
1034  if (!num) {
1035  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1036  return AVERROR_EXTERNAL;
1037  }
1038 
1039  /* Then allocate memory */
1040  qf = av_malloc_array(num, sizeof(VkQueueFamilyProperties));
1041  if (!qf)
1042  return AVERROR(ENOMEM);
1043 
1044  /* Finally retrieve the queue families */
1045  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, qf);
1046 
1047  av_log(ctx, AV_LOG_VERBOSE, "Queue families:\n");
1048  for (int i = 0; i < num; i++) {
1049  av_log(ctx, AV_LOG_VERBOSE, " %i:%s%s%s%s%s%s%s (queues: %i)\n", i,
1050  ((qf[i].queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? " graphics" : "",
1051  ((qf[i].queueFlags) & VK_QUEUE_COMPUTE_BIT) ? " compute" : "",
1052  ((qf[i].queueFlags) & VK_QUEUE_TRANSFER_BIT) ? " transfer" : "",
1053  ((qf[i].queueFlags) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) ? " encode" : "",
1054  ((qf[i].queueFlags) & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ? " decode" : "",
1055  ((qf[i].queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? " sparse" : "",
1056  ((qf[i].queueFlags) & VK_QUEUE_PROTECTED_BIT) ? " protected" : "",
1057  qf[i].queueCount);
1058 
1059  /* We use this field to keep a score of how many times we've used that
1060  * queue family in order to make better choices. */
1061  qf[i].timestampValidBits = 0;
1062  }
1063 
1064  /* Pick each queue family to use */
1065  graph_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT);
1066  comp_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT);
1067  tx_index = pick_queue_family(qf, num, VK_QUEUE_TRANSFER_BIT);
1068  enc_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_ENCODE_BIT_KHR);
1069  dec_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_DECODE_BIT_KHR);
1070 
1071  /* Signalling the transfer capabilities on a queue family is optional */
1072  if (tx_index < 0) {
1073  tx_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT);
1074  if (tx_index < 0)
1075  tx_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT);
1076  }
1077 
1078  hwctx->queue_family_index = -1;
1079  hwctx->queue_family_comp_index = -1;
1080  hwctx->queue_family_tx_index = -1;
1081  hwctx->queue_family_encode_index = -1;
1082  hwctx->queue_family_decode_index = -1;
1083 
1084 #define SETUP_QUEUE(qf_idx) \
1085  if (qf_idx > -1) { \
1086  int fidx = qf_idx; \
1087  int qc = qf[fidx].queueCount; \
1088  VkDeviceQueueCreateInfo *pc; \
1089  \
1090  if (fidx == graph_index) { \
1091  hwctx->queue_family_index = fidx; \
1092  hwctx->nb_graphics_queues = qc; \
1093  graph_index = -1; \
1094  } \
1095  if (fidx == comp_index) { \
1096  hwctx->queue_family_comp_index = fidx; \
1097  hwctx->nb_comp_queues = qc; \
1098  comp_index = -1; \
1099  } \
1100  if (fidx == tx_index) { \
1101  hwctx->queue_family_tx_index = fidx; \
1102  hwctx->nb_tx_queues = qc; \
1103  tx_index = -1; \
1104  } \
1105  if (fidx == enc_index) { \
1106  hwctx->queue_family_encode_index = fidx; \
1107  hwctx->nb_encode_queues = qc; \
1108  enc_index = -1; \
1109  } \
1110  if (fidx == dec_index) { \
1111  hwctx->queue_family_decode_index = fidx; \
1112  hwctx->nb_decode_queues = qc; \
1113  dec_index = -1; \
1114  } \
1115  \
1116  pc = av_realloc((void *)cd->pQueueCreateInfos, \
1117  sizeof(*pc) * (cd->queueCreateInfoCount + 1)); \
1118  if (!pc) { \
1119  av_free(qf); \
1120  return AVERROR(ENOMEM); \
1121  } \
1122  cd->pQueueCreateInfos = pc; \
1123  pc = &pc[cd->queueCreateInfoCount]; \
1124  \
1125  weights = av_malloc(qc * sizeof(float)); \
1126  if (!weights) { \
1127  av_free(qf); \
1128  return AVERROR(ENOMEM); \
1129  } \
1130  \
1131  memset(pc, 0, sizeof(*pc)); \
1132  pc->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; \
1133  pc->queueFamilyIndex = fidx; \
1134  pc->queueCount = qc; \
1135  pc->pQueuePriorities = weights; \
1136  \
1137  for (int i = 0; i < qc; i++) \
1138  weights[i] = 1.0f / qc; \
1139  \
1140  cd->queueCreateInfoCount++; \
1141  }
1142 
1143  SETUP_QUEUE(graph_index)
1144  SETUP_QUEUE(comp_index)
1145  SETUP_QUEUE(tx_index)
1146  SETUP_QUEUE(enc_index)
1147  SETUP_QUEUE(dec_index)
1148 
1149 #undef SETUP_QUEUE
1150 
1151  av_free(qf);
1152 
1153  return 0;
1154 }
1155 
1157 {
1158  VulkanDevicePriv *p = ctx->internal->priv;
1159  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1160  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1161 
1162  if (hwctx->act_dev)
1163  vk->DestroyDevice(hwctx->act_dev, hwctx->alloc);
1164 
1165  if (p->debug_ctx)
1166  vk->DestroyDebugUtilsMessengerEXT(hwctx->inst, p->debug_ctx,
1167  hwctx->alloc);
1168 
1169  if (hwctx->inst)
1170  vk->DestroyInstance(hwctx->inst, hwctx->alloc);
1171 
1172  if (p->libvulkan)
1173  dlclose(p->libvulkan);
1174 
1175  for (uint32_t i = 0; i < p->nb_tot_qfs; i++) {
1177  av_freep(&p->qf_mutex[i]);
1178  }
1179  av_freep(&p->qf_mutex);
1180 
1183 
1184  ff_vk_uninit(&p->vkctx);
1185 }
1186 
1188  VulkanDeviceSelection *dev_select,
1189  int disable_multiplane,
1190  AVDictionary *opts, int flags)
1191 {
1192  int err = 0;
1193  VkResult ret;
1194  AVDictionaryEntry *opt_d;
1195  VulkanDevicePriv *p = ctx->internal->priv;
1196  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1197  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1198 
1199  /*
1200  * VkPhysicalDeviceVulkan12Features has a timelineSemaphore field, but
1201  * MoltenVK doesn't implement VkPhysicalDeviceVulkan12Features yet, so we
1202  * use VkPhysicalDeviceTimelineSemaphoreFeatures directly.
1203  */
1204  VkPhysicalDeviceTimelineSemaphoreFeatures timeline_features = {
1205  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
1206  };
1207  VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_matrix_features = {
1208  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR,
1209  .pNext = &timeline_features,
1210  };
1211  VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_features = {
1212  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT,
1213  .pNext = &coop_matrix_features,
1214  };
1215  VkPhysicalDeviceDescriptorBufferFeaturesEXT desc_buf_features = {
1216  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT,
1217  .pNext = &atomic_float_features,
1218  };
1219  VkPhysicalDeviceVulkan13Features dev_features_1_3 = {
1220  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
1221  .pNext = &desc_buf_features,
1222  };
1223  VkPhysicalDeviceVulkan12Features dev_features_1_2 = {
1224  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
1225  .pNext = &dev_features_1_3,
1226  };
1227  VkPhysicalDeviceVulkan11Features dev_features_1_1 = {
1228  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
1229  .pNext = &dev_features_1_2,
1230  };
1231  VkPhysicalDeviceFeatures2 dev_features = {
1232  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1233  .pNext = &dev_features_1_1,
1234  };
1235 
1236  VkDeviceCreateInfo dev_info = {
1237  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1238  };
1239 
1240  hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
1241  hwctx->device_features.pNext = &p->device_features_1_1;
1242  p->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
1244  p->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
1246  p->device_features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
1247  p->device_features_1_3.pNext = &p->desc_buf_features;
1248  p->desc_buf_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT;
1250  p->atomic_float_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT;
1252  p->coop_matrix_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR;
1253  p->coop_matrix_features.pNext = NULL;
1254 
1255  ctx->free = vulkan_device_free;
1256 
1257  /* Create an instance if not given one */
1258  if ((err = create_instance(ctx, opts)))
1259  goto end;
1260 
1261  /* Find a device (if not given one) */
1262  if ((err = find_device(ctx, dev_select)))
1263  goto end;
1264 
1265  vk->GetPhysicalDeviceFeatures2(hwctx->phys_dev, &dev_features);
1266 
1267  /* Try to keep in sync with libplacebo */
1268 #define COPY_FEATURE(DST, NAME) (DST).features.NAME = dev_features.features.NAME;
1269  COPY_FEATURE(hwctx->device_features, shaderImageGatherExtended)
1270  COPY_FEATURE(hwctx->device_features, shaderStorageImageReadWithoutFormat)
1271  COPY_FEATURE(hwctx->device_features, shaderStorageImageWriteWithoutFormat)
1272  COPY_FEATURE(hwctx->device_features, fragmentStoresAndAtomics)
1273  COPY_FEATURE(hwctx->device_features, vertexPipelineStoresAndAtomics)
1274  COPY_FEATURE(hwctx->device_features, shaderInt64)
1275  COPY_FEATURE(hwctx->device_features, shaderInt16)
1276  COPY_FEATURE(hwctx->device_features, shaderFloat64)
1277 #undef COPY_FEATURE
1278 
1279  /* We require timeline semaphores */
1280  if (!timeline_features.timelineSemaphore) {
1281  av_log(ctx, AV_LOG_ERROR, "Device does not support timeline semaphores!\n");
1282  err = AVERROR(ENOSYS);
1283  goto end;
1284  }
1285 
1286  p->device_features_1_1.samplerYcbcrConversion = dev_features_1_1.samplerYcbcrConversion;
1287  p->device_features_1_1.storagePushConstant16 = dev_features_1_1.storagePushConstant16;
1288 
1289  p->device_features_1_2.timelineSemaphore = 1;
1290  p->device_features_1_2.bufferDeviceAddress = dev_features_1_2.bufferDeviceAddress;
1291  p->device_features_1_2.hostQueryReset = dev_features_1_2.hostQueryReset;
1292  p->device_features_1_2.storagePushConstant8 = dev_features_1_2.storagePushConstant8;
1293  p->device_features_1_2.shaderInt8 = dev_features_1_2.shaderInt8;
1294  p->device_features_1_2.storageBuffer8BitAccess = dev_features_1_2.storageBuffer8BitAccess;
1295  p->device_features_1_2.uniformAndStorageBuffer8BitAccess = dev_features_1_2.uniformAndStorageBuffer8BitAccess;
1296  p->device_features_1_2.shaderFloat16 = dev_features_1_2.shaderFloat16;
1297  p->device_features_1_2.shaderSharedInt64Atomics = dev_features_1_2.shaderSharedInt64Atomics;
1298  p->device_features_1_2.vulkanMemoryModel = dev_features_1_2.vulkanMemoryModel;
1299  p->device_features_1_2.vulkanMemoryModelDeviceScope = dev_features_1_2.vulkanMemoryModelDeviceScope;
1300  p->device_features_1_2.hostQueryReset = dev_features_1_2.hostQueryReset;
1301 
1302  p->device_features_1_3.dynamicRendering = dev_features_1_3.dynamicRendering;
1303  p->device_features_1_3.maintenance4 = dev_features_1_3.maintenance4;
1304  p->device_features_1_3.synchronization2 = dev_features_1_3.synchronization2;
1305  p->device_features_1_3.computeFullSubgroups = dev_features_1_3.computeFullSubgroups;
1306  p->device_features_1_3.shaderZeroInitializeWorkgroupMemory = dev_features_1_3.shaderZeroInitializeWorkgroupMemory;
1307  p->device_features_1_3.dynamicRendering = dev_features_1_3.dynamicRendering;
1308 
1309  p->desc_buf_features.descriptorBuffer = desc_buf_features.descriptorBuffer;
1310  p->desc_buf_features.descriptorBufferPushDescriptors = desc_buf_features.descriptorBufferPushDescriptors;
1311 
1312  p->atomic_float_features.shaderBufferFloat32Atomics = atomic_float_features.shaderBufferFloat32Atomics;
1313  p->atomic_float_features.shaderBufferFloat32AtomicAdd = atomic_float_features.shaderBufferFloat32AtomicAdd;
1314 
1315  p->coop_matrix_features.cooperativeMatrix = coop_matrix_features.cooperativeMatrix;
1316 
1317  dev_info.pNext = &hwctx->device_features;
1318 
1319  /* Setup queue family */
1320  if ((err = setup_queue_families(ctx, &dev_info)))
1321  goto end;
1322 
1323  if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
1324  &dev_info.enabledExtensionCount, 0))) {
1325  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1326  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1327  av_free((void *)dev_info.pQueueCreateInfos);
1328  goto end;
1329  }
1330 
1331  ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
1332  &hwctx->act_dev);
1333 
1334  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1335  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1336  av_free((void *)dev_info.pQueueCreateInfos);
1337 
1338  if (ret != VK_SUCCESS) {
1339  av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n",
1340  ff_vk_ret2str(ret));
1341  for (int i = 0; i < dev_info.enabledExtensionCount; i++)
1342  av_free((void *)dev_info.ppEnabledExtensionNames[i]);
1343  av_free((void *)dev_info.ppEnabledExtensionNames);
1344  err = AVERROR_EXTERNAL;
1345  goto end;
1346  }
1347 
1348  /* Tiled images setting, use them by default */
1349  opt_d = av_dict_get(opts, "linear_images", NULL, 0);
1350  if (opt_d)
1351  p->use_linear_images = strtol(opt_d->value, NULL, 10);
1352 
1353  /*
1354  * The disable_multiplane argument takes precedent over the option.
1355  */
1356  p->disable_multiplane = disable_multiplane;
1357  if (!p->disable_multiplane) {
1358  opt_d = av_dict_get(opts, "disable_multiplane", NULL, 0);
1359  if (opt_d)
1360  p->disable_multiplane = strtol(opt_d->value, NULL, 10);
1361  }
1362 
1363  hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames;
1364  hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount;
1365 
1366 end:
1367  return err;
1368 }
1369 
1370 static void lock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
1371 {
1372  VulkanDevicePriv *p = ctx->internal->priv;
1373  pthread_mutex_lock(&p->qf_mutex[queue_family][index]);
1374 }
1375 
1376 static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
1377 {
1378  VulkanDevicePriv *p = ctx->internal->priv;
1379  pthread_mutex_unlock(&p->qf_mutex[queue_family][index]);
1380 }
1381 
1383 {
1384  int err;
1385  uint32_t qf_num;
1386  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1387  VulkanDevicePriv *p = ctx->internal->priv;
1388  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1389  VkQueueFamilyProperties *qf;
1390  int graph_index, comp_index, tx_index, enc_index, dec_index;
1391 
1392  /* Set device extension flags */
1393  for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) {
1394  for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) {
1395  if (!strcmp(hwctx->enabled_dev_extensions[i],
1396  optional_device_exts[j].name)) {
1398  break;
1399  }
1400  }
1401  }
1402 
1403  err = ff_vk_load_functions(ctx, vk, p->vkctx.extensions, 1, 1);
1404  if (err < 0) {
1405  av_log(ctx, AV_LOG_ERROR, "Unable to load functions!\n");
1406  return err;
1407  }
1408 
1409  p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1410  p->props.pNext = &p->hprops;
1411  p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
1412 
1413  vk->GetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props);
1414  av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n",
1415  p->props.properties.deviceName);
1416  av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n");
1417  av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %"PRIu64"\n",
1418  p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
1419  av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %"SIZE_SPECIFIER"\n",
1420  p->props.properties.limits.minMemoryMapAlignment);
1421  av_log(ctx, AV_LOG_VERBOSE, " nonCoherentAtomSize: %"PRIu64"\n",
1422  p->props.properties.limits.nonCoherentAtomSize);
1424  av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %"PRIu64"\n",
1425  p->hprops.minImportedHostPointerAlignment);
1426 
1427  p->dev_is_nvidia = (p->props.properties.vendorID == 0x10de);
1428 
1429  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &qf_num, NULL);
1430  if (!qf_num) {
1431  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1432  return AVERROR_EXTERNAL;
1433  }
1434 
1435  qf = av_malloc_array(qf_num, sizeof(VkQueueFamilyProperties));
1436  if (!qf)
1437  return AVERROR(ENOMEM);
1438 
1439  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &qf_num, qf);
1440 
1441  p->qf_mutex = av_calloc(qf_num, sizeof(*p->qf_mutex));
1442  if (!p->qf_mutex) {
1443  av_free(qf);
1444  return AVERROR(ENOMEM);
1445  }
1446  p->nb_tot_qfs = qf_num;
1447 
1448  for (uint32_t i = 0; i < qf_num; i++) {
1449  p->qf_mutex[i] = av_calloc(qf[i].queueCount, sizeof(**p->qf_mutex));
1450  if (!p->qf_mutex[i]) {
1451  av_free(qf);
1452  return AVERROR(ENOMEM);
1453  }
1454  for (uint32_t j = 0; j < qf[i].queueCount; j++) {
1455  err = pthread_mutex_init(&p->qf_mutex[i][j], NULL);
1456  if (err != 0) {
1457  av_log(ctx, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n",
1458  av_err2str(err));
1459  av_free(qf);
1460  return AVERROR(err);
1461  }
1462  }
1463  }
1464 
1465  av_free(qf);
1466 
1467  graph_index = hwctx->queue_family_index;
1468  comp_index = hwctx->queue_family_comp_index;
1469  tx_index = hwctx->queue_family_tx_index;
1470  enc_index = hwctx->queue_family_encode_index;
1471  dec_index = hwctx->queue_family_decode_index;
1472 
1473 #define CHECK_QUEUE(type, required, fidx, ctx_qf, qc) \
1474  do { \
1475  if (ctx_qf < 0 && required) { \
1476  av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \
1477  " in the context!\n", type); \
1478  return AVERROR(EINVAL); \
1479  } else if (fidx < 0 || ctx_qf < 0) { \
1480  break; \
1481  } else if (ctx_qf >= qf_num) { \
1482  av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \
1483  type, ctx_qf, qf_num); \
1484  return AVERROR(EINVAL); \
1485  } \
1486  \
1487  av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \
1488  " for%s%s%s%s%s\n", \
1489  ctx_qf, qc, \
1490  ctx_qf == graph_index ? " graphics" : "", \
1491  ctx_qf == comp_index ? " compute" : "", \
1492  ctx_qf == tx_index ? " transfers" : "", \
1493  ctx_qf == enc_index ? " encode" : "", \
1494  ctx_qf == dec_index ? " decode" : ""); \
1495  graph_index = (ctx_qf == graph_index) ? -1 : graph_index; \
1496  comp_index = (ctx_qf == comp_index) ? -1 : comp_index; \
1497  tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \
1498  enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \
1499  dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \
1500  p->img_qfs[p->nb_img_qfs++] = ctx_qf; \
1501  } while (0)
1502 
1503  CHECK_QUEUE("graphics", 0, graph_index, hwctx->queue_family_index, hwctx->nb_graphics_queues);
1504  CHECK_QUEUE("upload", 1, tx_index, hwctx->queue_family_tx_index, hwctx->nb_tx_queues);
1505  CHECK_QUEUE("compute", 1, comp_index, hwctx->queue_family_comp_index, hwctx->nb_comp_queues);
1506  CHECK_QUEUE("encode", 0, enc_index, hwctx->queue_family_encode_index, hwctx->nb_encode_queues);
1507  CHECK_QUEUE("decode", 0, dec_index, hwctx->queue_family_decode_index, hwctx->nb_decode_queues);
1508 
1509 #undef CHECK_QUEUE
1510 
1511  if (!hwctx->lock_queue)
1512  hwctx->lock_queue = lock_queue;
1513  if (!hwctx->unlock_queue)
1514  hwctx->unlock_queue = unlock_queue;
1515 
1516  /* Get device capabilities */
1517  vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
1518 
1519  p->vkctx.device = ctx;
1520  p->vkctx.hwctx = hwctx;
1521 
1522  ff_vk_load_props(&p->vkctx);
1523  ff_vk_qf_init(&p->vkctx, &p->compute_qf, VK_QUEUE_COMPUTE_BIT);
1524  ff_vk_qf_init(&p->vkctx, &p->transfer_qf, VK_QUEUE_TRANSFER_BIT);
1525 
1526  return 0;
1527 }
1528 
1529 static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device,
1530  AVDictionary *opts, int flags)
1531 {
1532  VulkanDeviceSelection dev_select = { 0 };
1533  if (device && device[0]) {
1534  char *end = NULL;
1535  dev_select.index = strtol(device, &end, 10);
1536  if (end == device) {
1537  dev_select.index = 0;
1538  dev_select.name = device;
1539  }
1540  }
1541 
1542  return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
1543 }
1544 
1546  AVHWDeviceContext *src_ctx,
1547  AVDictionary *opts, int flags)
1548 {
1549  av_unused VulkanDeviceSelection dev_select = { 0 };
1550 
1551  /* If there's only one device on the system, then even if its not covered
1552  * by the following checks (e.g. non-PCIe ARM GPU), having an empty
1553  * dev_select will mean it'll get picked. */
1554  switch(src_ctx->type) {
1555 #if CONFIG_VAAPI
1556  case AV_HWDEVICE_TYPE_VAAPI: {
1557  AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
1558 
1559  const char *vendor = vaQueryVendorString(src_hwctx->display);
1560  if (!vendor) {
1561  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n");
1562  return AVERROR_EXTERNAL;
1563  }
1564 
1565  if (strstr(vendor, "AMD"))
1566  dev_select.vendor_id = 0x1002;
1567 
1568  return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
1569  }
1570 #endif
1571 #if CONFIG_LIBDRM
1572  case AV_HWDEVICE_TYPE_DRM: {
1573  int err;
1574  struct stat drm_node_info;
1575  drmDevice *drm_dev_info;
1576  AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1577 
1578  err = fstat(src_hwctx->fd, &drm_node_info);
1579  if (err) {
1580  av_log(ctx, AV_LOG_ERROR, "Unable to get node info from DRM fd: %s!\n",
1581  av_err2str(AVERROR(errno)));
1582  return AVERROR_EXTERNAL;
1583  }
1584 
1585  dev_select.drm_major = major(drm_node_info.st_dev);
1586  dev_select.drm_minor = minor(drm_node_info.st_dev);
1587  dev_select.has_drm = 1;
1588 
1589  err = drmGetDevice(src_hwctx->fd, &drm_dev_info);
1590  if (err) {
1591  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd: %s!\n",
1592  av_err2str(AVERROR(errno)));
1593  return AVERROR_EXTERNAL;
1594  }
1595 
1596  if (drm_dev_info->bustype == DRM_BUS_PCI)
1597  dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id;
1598 
1599  drmFreeDevice(&drm_dev_info);
1600 
1601  return vulkan_device_create_internal(ctx, &dev_select, 0, opts, flags);
1602  }
1603 #endif
1604 #if CONFIG_CUDA
1605  case AV_HWDEVICE_TYPE_CUDA: {
1606  AVHWDeviceContext *cuda_cu = src_ctx;
1607  AVCUDADeviceContext *src_hwctx = src_ctx->hwctx;
1608  AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal;
1609  CudaFunctions *cu = cu_internal->cuda_dl;
1610 
1611  int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid,
1612  cu_internal->cuda_device));
1613  if (ret < 0) {
1614  av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n");
1615  return AVERROR_EXTERNAL;
1616  }
1617 
1618  dev_select.has_uuid = 1;
1619 
1620  /*
1621  * CUDA is not able to import multiplane images, so always derive a
1622  * Vulkan device with multiplane disabled.
1623  */
1624  return vulkan_device_create_internal(ctx, &dev_select, 1, opts, flags);
1625  }
1626 #endif
1627  default:
1628  return AVERROR(ENOSYS);
1629  }
1630 }
1631 
1633  const void *hwconfig,
1634  AVHWFramesConstraints *constraints)
1635 {
1636  int count = 0;
1637  VulkanDevicePriv *p = ctx->internal->priv;
1638 
1639  for (enum AVPixelFormat i = 0; i < nb_vk_formats_list; i++) {
1641  p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
1642  VK_IMAGE_TILING_OPTIMAL,
1643  NULL, NULL, NULL, NULL, 0) >= 0;
1644  }
1645 
1646 #if CONFIG_CUDA
1647  if (p->dev_is_nvidia)
1648  count++;
1649 #endif
1650 
1651  constraints->valid_sw_formats = av_malloc_array(count + 1,
1652  sizeof(enum AVPixelFormat));
1653  if (!constraints->valid_sw_formats)
1654  return AVERROR(ENOMEM);
1655 
1656  count = 0;
1657  for (enum AVPixelFormat i = 0; i < nb_vk_formats_list; i++) {
1659  p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
1660  VK_IMAGE_TILING_OPTIMAL,
1661  NULL, NULL, NULL, NULL, 0) >= 0) {
1662  constraints->valid_sw_formats[count++] = vk_formats_list[i].pixfmt;
1663  }
1664  }
1665 
1666 #if CONFIG_CUDA
1667  if (p->dev_is_nvidia)
1668  constraints->valid_sw_formats[count++] = AV_PIX_FMT_CUDA;
1669 #endif
1670  constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE;
1671 
1672  constraints->min_width = 1;
1673  constraints->min_height = 1;
1674  constraints->max_width = p->props.properties.limits.maxImageDimension2D;
1675  constraints->max_height = p->props.properties.limits.maxImageDimension2D;
1676 
1677  constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat));
1678  if (!constraints->valid_hw_formats)
1679  return AVERROR(ENOMEM);
1680 
1681  constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN;
1682  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1683 
1684  return 0;
1685 }
1686 
1687 static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
1688  VkMemoryPropertyFlagBits req_flags, const void *alloc_extension,
1689  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
1690 {
1691  VkResult ret;
1692  int index = -1;
1693  VulkanDevicePriv *p = ctx->internal->priv;
1694  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1695  AVVulkanDeviceContext *dev_hwctx = ctx->hwctx;
1696  VkMemoryAllocateInfo alloc_info = {
1697  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1698  .pNext = alloc_extension,
1699  .allocationSize = req->size,
1700  };
1701 
1702  /* The vulkan spec requires memory types to be sorted in the "optimal"
1703  * order, so the first matching type we find will be the best/fastest one */
1704  for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
1705  const VkMemoryType *type = &p->mprops.memoryTypes[i];
1706 
1707  /* The memory type must be supported by the requirements (bitfield) */
1708  if (!(req->memoryTypeBits & (1 << i)))
1709  continue;
1710 
1711  /* The memory type flags must include our properties */
1712  if ((type->propertyFlags & req_flags) != req_flags)
1713  continue;
1714 
1715  /* The memory type must be large enough */
1716  if (req->size > p->mprops.memoryHeaps[type->heapIndex].size)
1717  continue;
1718 
1719  /* Found a suitable memory type */
1720  index = i;
1721  break;
1722  }
1723 
1724  if (index < 0) {
1725  av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
1726  req_flags);
1727  return AVERROR(EINVAL);
1728  }
1729 
1730  alloc_info.memoryTypeIndex = index;
1731 
1732  ret = vk->AllocateMemory(dev_hwctx->act_dev, &alloc_info,
1733  dev_hwctx->alloc, mem);
1734  if (ret != VK_SUCCESS) {
1735  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
1736  ff_vk_ret2str(ret));
1737  return AVERROR(ENOMEM);
1738  }
1739 
1740  *mem_flags |= p->mprops.memoryTypes[index].propertyFlags;
1741 
1742  return 0;
1743 }
1744 
1746 {
1747  av_unused AVVkFrameInternal *internal = f->internal;
1748 
1749 #if CONFIG_CUDA
1750  if (internal->cuda_fc_ref) {
1751  AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
1752  int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
1753  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
1754  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
1755  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
1756  CudaFunctions *cu = cu_internal->cuda_dl;
1757 
1758  for (int i = 0; i < planes; i++) {
1759  if (internal->cu_sem[i])
1760  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
1761  if (internal->cu_mma[i])
1762  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
1763  if (internal->ext_mem[i])
1764  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
1765 #ifdef _WIN32
1766  if (internal->ext_sem_handle[i])
1767  CloseHandle(internal->ext_sem_handle[i]);
1768  if (internal->ext_mem_handle[i])
1769  CloseHandle(internal->ext_mem_handle[i]);
1770 #endif
1771  }
1772 
1773  av_buffer_unref(&internal->cuda_fc_ref);
1774  }
1775 #endif
1776 
1777  pthread_mutex_destroy(&internal->update_mutex);
1778  av_freep(&f->internal);
1779 }
1780 
1782 {
1783  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1785  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1786  int nb_images = ff_vk_count_images(f);
1787 
1788  VkSemaphoreWaitInfo sem_wait = {
1789  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
1790  .flags = 0x0,
1791  .pSemaphores = f->sem,
1792  .pValues = f->sem_value,
1793  .semaphoreCount = nb_images,
1794  };
1795 
1796  vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
1797 
1799 
1800  for (int i = 0; i < nb_images; i++) {
1801  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
1802  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
1803  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
1804  }
1805 
1806  av_free(f);
1807 }
1808 
1809 static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
1810 {
1811  vulkan_frame_free(opaque, (AVVkFrame*)data);
1812 }
1813 
1815  void *alloc_pnext, size_t alloc_pnext_stride)
1816 {
1817  int img_cnt = 0, err;
1818  VkResult ret;
1819  AVHWDeviceContext *ctx = hwfc->device_ctx;
1820  VulkanDevicePriv *p = ctx->internal->priv;
1821  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1822  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
1823 
1824  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1825 
1826  while (f->img[img_cnt]) {
1827  int use_ded_mem;
1828  VkImageMemoryRequirementsInfo2 req_desc = {
1829  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
1830  .image = f->img[img_cnt],
1831  };
1832  VkMemoryDedicatedAllocateInfo ded_alloc = {
1833  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1834  .pNext = (void *)(((uint8_t *)alloc_pnext) + img_cnt*alloc_pnext_stride),
1835  };
1836  VkMemoryDedicatedRequirements ded_req = {
1837  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
1838  };
1839  VkMemoryRequirements2 req = {
1840  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
1841  .pNext = &ded_req,
1842  };
1843 
1844  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
1845 
1846  if (f->tiling == VK_IMAGE_TILING_LINEAR)
1847  req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
1848  p->props.properties.limits.minMemoryMapAlignment);
1849 
1850  /* In case the implementation prefers/requires dedicated allocation */
1851  use_ded_mem = ded_req.prefersDedicatedAllocation |
1852  ded_req.requiresDedicatedAllocation;
1853  if (use_ded_mem)
1854  ded_alloc.image = f->img[img_cnt];
1855 
1856  /* Allocate memory */
1857  if ((err = alloc_mem(ctx, &req.memoryRequirements,
1858  f->tiling == VK_IMAGE_TILING_LINEAR ?
1859  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1860  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1861  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
1862  &f->flags, &f->mem[img_cnt])))
1863  return err;
1864 
1865  f->size[img_cnt] = req.memoryRequirements.size;
1866  bind_info[img_cnt].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1867  bind_info[img_cnt].image = f->img[img_cnt];
1868  bind_info[img_cnt].memory = f->mem[img_cnt];
1869 
1870  img_cnt++;
1871  }
1872 
1873  /* Bind the allocated memory to the images */
1874  ret = vk->BindImageMemory2(hwctx->act_dev, img_cnt, bind_info);
1875  if (ret != VK_SUCCESS) {
1876  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
1877  ff_vk_ret2str(ret));
1878  return AVERROR_EXTERNAL;
1879  }
1880 
1881  return 0;
1882 }
1883 
1884 enum PrepMode {
1890 };
1891 
1893  AVVkFrame *frame, enum PrepMode pmode)
1894 {
1895  int err;
1897  FFVulkanFunctions *vk = &p->vkctx.vkfn;
1898  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
1899  int nb_img_bar = 0;
1900 
1901  uint32_t dst_qf = VK_QUEUE_FAMILY_IGNORED;
1902  VkImageLayout new_layout;
1903  VkAccessFlags2 new_access;
1904  VkPipelineStageFlagBits2 src_stage = VK_PIPELINE_STAGE_2_NONE;
1905 
1906  /* This is dirty - but it works. The vulkan.c dependency system doesn't
1907  * free non-refcounted frames, and non-refcounted hardware frames cannot
1908  * happen anywhere outside of here. */
1909  AVBufferRef tmp_ref = {
1910  .data = (uint8_t *)hwfc,
1911  };
1912  AVFrame tmp_frame = {
1913  .data[0] = (uint8_t *)frame,
1914  .hw_frames_ctx = &tmp_ref,
1915  };
1916 
1917  VkCommandBuffer cmd_buf;
1918  FFVkExecContext *exec = ff_vk_exec_get(ectx);
1919  cmd_buf = exec->buf;
1920  ff_vk_exec_start(&p->vkctx, exec);
1921 
1922  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, &tmp_frame,
1923  VK_PIPELINE_STAGE_2_NONE,
1924  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
1925  if (err < 0)
1926  return err;
1927 
1928  switch (pmode) {
1929  case PREP_MODE_WRITE:
1930  new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1931  new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
1932  break;
1934  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1935  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1936  break;
1938  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1939  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1940  dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
1941  src_stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
1942  break;
1944  new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR;
1945  new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
1946  break;
1948  new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
1949  new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
1950  break;
1951  }
1952 
1953  ff_vk_frame_barrier(&p->vkctx, exec, &tmp_frame, img_bar, &nb_img_bar,
1954  src_stage,
1955  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
1956  new_access, new_layout, dst_qf);
1957 
1958  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
1959  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1960  .pImageMemoryBarriers = img_bar,
1961  .imageMemoryBarrierCount = nb_img_bar,
1962  });
1963 
1964  err = ff_vk_exec_submit(&p->vkctx, exec);
1965  if (err < 0)
1966  return err;
1967 
1968  /* We can do this because there are no real dependencies */
1969  ff_vk_exec_discard_deps(&p->vkctx, exec);
1970 
1971  return 0;
1972 }
1973 
1974 static inline void get_plane_wh(uint32_t *w, uint32_t *h, enum AVPixelFormat format,
1975  int frame_w, int frame_h, int plane)
1976 {
1978 
1979  /* Currently always true unless gray + alpha support is added */
1980  if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB ||
1981  !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
1982  *w = frame_w;
1983  *h = frame_h;
1984  return;
1985  }
1986 
1987  *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w);
1988  *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h);
1989 }
1990 
1992  VkImageTiling tiling, VkImageUsageFlagBits usage,
1993  VkImageCreateFlags flags, int nb_layers,
1994  void *create_pnext)
1995 {
1996  int err;
1997  VkResult ret;
1998  AVVulkanFramesContext *hwfc_vk = hwfc->hwctx;
1999  AVHWDeviceContext *ctx = hwfc->device_ctx;
2000  VulkanDevicePriv *p = ctx->internal->priv;
2001  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2002  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2003 
2004  VkExportSemaphoreCreateInfo ext_sem_info = {
2005  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
2006 #ifdef _WIN32
2007  .handleTypes = IsWindows8OrGreater()
2008  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2009  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2010 #else
2011  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2012 #endif
2013  };
2014 
2015  VkSemaphoreTypeCreateInfo sem_type_info = {
2016  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2017 #ifdef _WIN32
2018  .pNext = p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM ? &ext_sem_info : NULL,
2019 #else
2020  .pNext = p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL,
2021 #endif
2022  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2023  .initialValue = 0,
2024  };
2025 
2026  VkSemaphoreCreateInfo sem_spawn = {
2027  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2028  .pNext = &sem_type_info,
2029  };
2030 
2032  if (!f) {
2033  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2034  return AVERROR(ENOMEM);
2035  }
2036 
2037  // TODO: check witdh and height for alignment in case of multiplanar (must be mod-2 if subsampled)
2038 
2039  /* Create the images */
2040  for (int i = 0; (hwfc_vk->format[i] != VK_FORMAT_UNDEFINED); i++) {
2041  VkImageCreateInfo create_info = {
2042  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2043  .pNext = create_pnext,
2044  .imageType = VK_IMAGE_TYPE_2D,
2045  .format = hwfc_vk->format[i],
2046  .extent.depth = 1,
2047  .mipLevels = 1,
2048  .arrayLayers = nb_layers,
2049  .flags = flags,
2050  .tiling = tiling,
2051  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2052  .usage = usage,
2053  .samples = VK_SAMPLE_COUNT_1_BIT,
2054  .pQueueFamilyIndices = p->img_qfs,
2055  .queueFamilyIndexCount = p->nb_img_qfs,
2056  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2057  VK_SHARING_MODE_EXCLUSIVE,
2058  };
2059 
2060  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2061  hwfc->sw_format, hwfc->width, hwfc->height, i);
2062 
2063  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2064  hwctx->alloc, &f->img[i]);
2065  if (ret != VK_SUCCESS) {
2066  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2067  ff_vk_ret2str(ret));
2068  err = AVERROR(EINVAL);
2069  goto fail;
2070  }
2071 
2072  /* Create semaphore */
2073  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2074  hwctx->alloc, &f->sem[i]);
2075  if (ret != VK_SUCCESS) {
2076  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2077  ff_vk_ret2str(ret));
2078  return AVERROR_EXTERNAL;
2079  }
2080 
2081  f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2082  f->layout[i] = create_info.initialLayout;
2083  f->access[i] = 0x0;
2084  f->sem_value[i] = 0;
2085  }
2086 
2087  f->flags = 0x0;
2088  f->tiling = tiling;
2089 
2090  *frame = f;
2091  return 0;
2092 
2093 fail:
2094  vulkan_frame_free(hwfc, f);
2095  return err;
2096 }
2097 
2098 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2100  VkExternalMemoryHandleTypeFlags *comp_handle_types,
2101  VkExternalMemoryHandleTypeFlagBits *iexp,
2102  VkExternalMemoryHandleTypeFlagBits exp)
2103 {
2104  VkResult ret;
2105  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2106  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
2108  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2109 
2110  const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
2112  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2113  int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
2114  int nb_mods;
2115 
2116  VkExternalImageFormatProperties eprops = {
2117  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2118  };
2119  VkImageFormatProperties2 props = {
2120  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2121  .pNext = &eprops,
2122  };
2123  VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
2124  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2125  .pNext = NULL,
2126  .pQueueFamilyIndices = p->img_qfs,
2127  .queueFamilyIndexCount = p->nb_img_qfs,
2128  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2129  VK_SHARING_MODE_EXCLUSIVE,
2130  };
2131  VkPhysicalDeviceExternalImageFormatInfo enext = {
2132  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2133  .handleType = exp,
2134  .pNext = has_mods ? &phy_dev_mod_info : NULL,
2135  };
2136  VkPhysicalDeviceImageFormatInfo2 pinfo = {
2137  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2138  .pNext = !exp ? NULL : &enext,
2139  .format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0],
2140  .type = VK_IMAGE_TYPE_2D,
2141  .tiling = hwctx->tiling,
2142  .usage = hwctx->usage,
2143  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2144  };
2145 
2146  nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
2147  for (int i = 0; i < nb_mods; i++) {
2148  if (has_mods)
2149  phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
2150 
2151  ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
2152  &pinfo, &props);
2153 
2154  if (ret == VK_SUCCESS) {
2155  *iexp |= exp;
2156  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2157  }
2158  }
2159 }
2160 
2161 static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2162 {
2163  int err;
2164  AVVkFrame *f;
2165  AVBufferRef *avbuf = NULL;
2166  AVHWFramesContext *hwfc = opaque;
2167  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2169  VulkanFramesPriv *fp = hwfc->internal->priv;
2170  VkExternalMemoryHandleTypeFlags e = 0x0;
2171  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2172 
2173  VkExternalMemoryImageCreateInfo eiinfo = {
2174  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2175  .pNext = hwctx->create_pnext,
2176  };
2177 
2178 #ifdef _WIN32
2179  if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2180  try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2181  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2182  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2183 #else
2185  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2186  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2187 #endif
2188 
2189  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2190  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2191  eminfo[i].pNext = hwctx->alloc_pnext[i];
2192  eminfo[i].handleTypes = e;
2193  }
2194 
2195  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
2196  hwctx->nb_layers,
2197  eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
2198  if (err)
2199  return NULL;
2200 
2201  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2202  if (err)
2203  goto fail;
2204 
2205  if ( (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2206  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR))
2207  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DPB);
2208  else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR)
2209  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DST);
2210  else
2211  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_WRITE);
2212  if (err)
2213  goto fail;
2214 
2215  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2216  vulkan_frame_free_cb, hwfc, 0);
2217  if (!avbuf)
2218  goto fail;
2219 
2220  return avbuf;
2221 
2222 fail:
2223  vulkan_frame_free(hwfc, f);
2224  return NULL;
2225 }
2226 
2228 {
2230 }
2231 
2233 {
2235 }
2236 
2238 {
2240  VulkanFramesPriv *fp = hwfc->internal->priv;
2241 
2242  if (fp->modifier_info) {
2243  if (fp->modifier_info->pDrmFormatModifiers)
2244  av_freep(&fp->modifier_info->pDrmFormatModifiers);
2245  av_freep(&fp->modifier_info);
2246  }
2247 
2248  ff_vk_exec_pool_free(&p->vkctx, &fp->compute_exec);
2249  ff_vk_exec_pool_free(&p->vkctx, &fp->upload_exec);
2250  ff_vk_exec_pool_free(&p->vkctx, &fp->download_exec);
2251 }
2252 
2254 {
2255  int err;
2256  AVVkFrame *f;
2257  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2258  VulkanFramesPriv *fp = hwfc->internal->priv;
2260  VkImageUsageFlagBits supported_usage;
2261  const struct FFVkFormatEntry *fmt;
2262  int disable_multiplane = p->disable_multiplane ||
2264 
2265  /* Defaults */
2266  if (!hwctx->nb_layers)
2267  hwctx->nb_layers = 1;
2268 
2269  /* VK_IMAGE_TILING_OPTIMAL == 0, can't check for it really */
2270  if (p->use_linear_images &&
2271  (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
2272  hwctx->tiling = VK_IMAGE_TILING_LINEAR;
2273 
2274 
2275  fmt = vk_find_format_entry(hwfc->sw_format);
2276  if (!fmt) {
2277  av_log(hwfc, AV_LOG_ERROR, "Unsupported pixel format: %s!\n",
2279  return AVERROR(EINVAL);
2280  }
2281 
2282  if (hwctx->format[0] != VK_FORMAT_UNDEFINED) {
2283  if (hwctx->format[0] != fmt->vkf) {
2284  for (int i = 0; i < fmt->nb_images_fallback; i++) {
2285  if (hwctx->format[i] != fmt->fallback[i]) {
2286  av_log(hwfc, AV_LOG_ERROR, "Incompatible Vulkan format given "
2287  "for the current sw_format %s!\n",
2289  return AVERROR(EINVAL);
2290  }
2291  }
2292  }
2293 
2294  /* Check if the sw_format itself is supported */
2295  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
2296  hwctx->tiling, NULL,
2297  NULL, NULL, &supported_usage, 0);
2298  if (err < 0) {
2299  av_log(hwfc, AV_LOG_ERROR, "Unsupported sw format: %s!\n",
2301  return AVERROR(EINVAL);
2302  }
2303  } else {
2304  err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format,
2305  hwctx->tiling, hwctx->format, NULL,
2306  NULL, &supported_usage,
2307  disable_multiplane);
2308  if (err < 0)
2309  return err;
2310  }
2311 
2312  /* Image usage flags */
2313  if (!hwctx->usage) {
2314  hwctx->usage = supported_usage & (VK_BUFFER_USAGE_TRANSFER_DST_BIT |
2315  VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
2316  VK_IMAGE_USAGE_STORAGE_BIT |
2317  VK_IMAGE_USAGE_SAMPLED_BIT |
2318  VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR);
2319  }
2320 
2321  /* Image creation flags.
2322  * Only fill them in automatically if the image is not going to be used as
2323  * a DPB-only image, and we have SAMPLED/STORAGE bits set. */
2324  if (!hwctx->img_flags) {
2325  int is_lone_dpb = (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) &&
2326  !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR);
2327  int sampleable = hwctx->usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
2328  VK_IMAGE_USAGE_STORAGE_BIT);
2329  if (sampleable && !is_lone_dpb) {
2330  hwctx->img_flags = VK_IMAGE_CREATE_ALIAS_BIT;
2331  if ((fmt->vk_planes > 1) && (hwctx->format[0] == fmt->vkf))
2332  hwctx->img_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |
2333  VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
2334  }
2335  }
2336 
2337  if (!hwctx->lock_frame)
2338  hwctx->lock_frame = lock_frame;
2339 
2340  if (!hwctx->unlock_frame)
2341  hwctx->unlock_frame = unlock_frame;
2342 
2343  err = ff_vk_exec_pool_init(&p->vkctx, &p->compute_qf, &fp->compute_exec,
2344  p->compute_qf.nb_queues, 0, 0, 0, NULL);
2345  if (err)
2346  return err;
2347 
2348  err = ff_vk_exec_pool_init(&p->vkctx, &p->transfer_qf, &fp->upload_exec,
2349  p->transfer_qf.nb_queues*2, 0, 0, 0, NULL);
2350  if (err)
2351  return err;
2352 
2353  err = ff_vk_exec_pool_init(&p->vkctx, &p->transfer_qf, &fp->download_exec,
2354  p->transfer_qf.nb_queues, 0, 0, 0, NULL);
2355  if (err)
2356  return err;
2357 
2358  /* Test to see if allocation will fail */
2359  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
2360  hwctx->nb_layers, hwctx->create_pnext);
2361  if (err)
2362  return err;
2363 
2364  vulkan_frame_free(hwfc, f);
2365 
2366  /* If user did not specify a pool, hwfc->pool will be set to the internal one
2367  * in hwcontext.c just after this gets called */
2368  if (!hwfc->pool) {
2370  hwfc, vulkan_pool_alloc,
2371  NULL);
2372  if (!hwfc->internal->pool_internal)
2373  return AVERROR(ENOMEM);
2374  }
2375 
2376  return 0;
2377 }
2378 
2380 {
2381  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
2382  if (!frame->buf[0])
2383  return AVERROR(ENOMEM);
2384 
2385  frame->data[0] = frame->buf[0]->data;
2386  frame->format = AV_PIX_FMT_VULKAN;
2387  frame->width = hwfc->width;
2388  frame->height = hwfc->height;
2389 
2390  return 0;
2391 }
2392 
2394  enum AVHWFrameTransferDirection dir,
2395  enum AVPixelFormat **formats)
2396 {
2397  enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
2398  if (!fmts)
2399  return AVERROR(ENOMEM);
2400 
2401  fmts[0] = hwfc->sw_format;
2402  fmts[1] = AV_PIX_FMT_NONE;
2403 
2404  *formats = fmts;
2405  return 0;
2406 }
2407 
2408 #if CONFIG_LIBDRM
2409 static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
2410 {
2411  vulkan_frame_free(hwfc, hwmap->priv);
2412 }
2413 
2414 static const struct {
2415  uint32_t drm_fourcc;
2416  VkFormat vk_format;
2417 } vulkan_drm_format_map[] = {
2418  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
2419  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
2420  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
2421  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
2422  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
2423  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
2424  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
2425  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
2426  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
2427  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
2428 
2429  // All these DRM_FORMATs were added in the same libdrm commit.
2430 #ifdef DRM_FORMAT_XYUV8888
2431  { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
2432  { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R16G16B16A16_UNORM} ,
2433  // As we had to map XV36 to a 16bit Vulkan format, reverse mapping will
2434  // end up yielding Y416 as the DRM format, so we need to recognise it.
2435  { DRM_FORMAT_Y416, VK_FORMAT_R16G16B16A16_UNORM },
2436 #endif
2437 };
2438 
2439 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
2440 {
2441  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
2442  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
2443  return vulkan_drm_format_map[i].vk_format;
2444  return VK_FORMAT_UNDEFINED;
2445 }
2446 
2447 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
2448  const AVFrame *src)
2449 {
2450  int err = 0;
2451  VkResult ret;
2452  AVVkFrame *f;
2453  int bind_counts = 0;
2454  AVHWDeviceContext *ctx = hwfc->device_ctx;
2455  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2456  VulkanDevicePriv *p = ctx->internal->priv;
2457  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2458  VulkanFramesPriv *fp = hwfc->internal->priv;
2459  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
2460  VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
2461  VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
2462 
2463  for (int i = 0; i < desc->nb_layers; i++) {
2464  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
2465  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
2466  desc->layers[i].format);
2467  return AVERROR(EINVAL);
2468  }
2469  }
2470 
2471  if (!(f = av_vk_frame_alloc())) {
2472  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2473  err = AVERROR(ENOMEM);
2474  goto fail;
2475  }
2476 
2477  f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
2478 
2479  for (int i = 0; i < desc->nb_layers; i++) {
2480  const int planes = desc->layers[i].nb_planes;
2481 
2482  /* Semaphore */
2483  VkSemaphoreTypeCreateInfo sem_type_info = {
2484  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2485  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2486  .initialValue = 0,
2487  };
2488  VkSemaphoreCreateInfo sem_spawn = {
2489  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2490  .pNext = &sem_type_info,
2491  };
2492 
2493  /* Image creation */
2494  VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
2495  VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
2496  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
2497  .drmFormatModifier = desc->objects[0].format_modifier,
2498  .drmFormatModifierPlaneCount = planes,
2499  .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
2500  };
2501  VkExternalMemoryImageCreateInfo ext_img_spec = {
2502  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2503  .pNext = &ext_img_mod_spec,
2504  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2505  };
2506  VkImageCreateInfo create_info = {
2507  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2508  .pNext = &ext_img_spec,
2509  .imageType = VK_IMAGE_TYPE_2D,
2510  .format = drm_to_vulkan_fmt(desc->layers[i].format),
2511  .extent.depth = 1,
2512  .mipLevels = 1,
2513  .arrayLayers = 1,
2514  .flags = 0x0,
2515  .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
2516  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
2517  .usage = VK_IMAGE_USAGE_SAMPLED_BIT |
2518  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
2519  .samples = VK_SAMPLE_COUNT_1_BIT,
2520  .pQueueFamilyIndices = p->img_qfs,
2521  .queueFamilyIndexCount = p->nb_img_qfs,
2522  .sharingMode = p->nb_img_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2523  VK_SHARING_MODE_EXCLUSIVE,
2524  };
2525 
2526  /* Image format verification */
2527  VkExternalImageFormatProperties ext_props = {
2528  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2529  };
2530  VkImageFormatProperties2 props_ret = {
2531  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2532  .pNext = &ext_props,
2533  };
2534  VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
2535  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2536  .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
2537  .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
2538  .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
2539  .sharingMode = create_info.sharingMode,
2540  };
2541  VkPhysicalDeviceExternalImageFormatInfo props_ext = {
2542  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2543  .pNext = &props_drm_mod,
2544  .handleType = ext_img_spec.handleTypes,
2545  };
2546  VkPhysicalDeviceImageFormatInfo2 fmt_props = {
2547  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2548  .pNext = &props_ext,
2549  .format = create_info.format,
2550  .type = create_info.imageType,
2551  .tiling = create_info.tiling,
2552  .usage = create_info.usage,
2553  .flags = create_info.flags,
2554  };
2555 
2556  /* Check if importing is possible for this combination of parameters */
2557  ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
2558  &fmt_props, &props_ret);
2559  if (ret != VK_SUCCESS) {
2560  av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
2561  ff_vk_ret2str(ret));
2562  err = AVERROR_EXTERNAL;
2563  goto fail;
2564  }
2565 
2566  /* Set the image width/height */
2567  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2568  hwfc->sw_format, src->width, src->height, i);
2569 
2570  /* Set the subresource layout based on the layer properties */
2571  for (int j = 0; j < planes; j++) {
2572  ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
2573  ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
2574  ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
2575  ext_img_layouts[j].arrayPitch = 0;
2576  ext_img_layouts[j].depthPitch = 0;
2577  }
2578 
2579  /* Create image */
2580  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2581  hwctx->alloc, &f->img[i]);
2582  if (ret != VK_SUCCESS) {
2583  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2584  ff_vk_ret2str(ret));
2585  err = AVERROR(EINVAL);
2586  goto fail;
2587  }
2588 
2589  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2590  hwctx->alloc, &f->sem[i]);
2591  if (ret != VK_SUCCESS) {
2592  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2593  ff_vk_ret2str(ret));
2594  return AVERROR_EXTERNAL;
2595  }
2596 
2597  /* We'd import a semaphore onto the one we created using
2598  * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
2599  * offer us anything we could import and sync with, so instead
2600  * just signal the semaphore we created. */
2601 
2602  f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0];
2603  f->layout[i] = create_info.initialLayout;
2604  f->access[i] = 0x0;
2605  f->sem_value[i] = 0;
2606  }
2607 
2608  for (int i = 0; i < desc->nb_layers; i++) {
2609  /* Memory requirements */
2610  VkImageMemoryRequirementsInfo2 req_desc = {
2611  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2612  .image = f->img[i],
2613  };
2614  VkMemoryDedicatedRequirements ded_req = {
2615  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2616  };
2617  VkMemoryRequirements2 req2 = {
2618  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2619  .pNext = &ded_req,
2620  };
2621 
2622  /* Allocation/importing */
2623  VkMemoryFdPropertiesKHR fdmp = {
2624  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
2625  };
2626  /* This assumes that a layer will never be constructed from multiple
2627  * objects. If that was to happen in the real world, this code would
2628  * need to import each plane separately.
2629  */
2630  VkImportMemoryFdInfoKHR idesc = {
2631  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2632  .fd = dup(desc->objects[desc->layers[i].planes[0].object_index].fd),
2633  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2634  };
2635  VkMemoryDedicatedAllocateInfo ded_alloc = {
2636  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2637  .pNext = &idesc,
2638  .image = req_desc.image,
2639  };
2640 
2641  /* Get object properties */
2642  ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
2643  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2644  idesc.fd, &fdmp);
2645  if (ret != VK_SUCCESS) {
2646  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
2647  ff_vk_ret2str(ret));
2648  err = AVERROR_EXTERNAL;
2649  close(idesc.fd);
2650  goto fail;
2651  }
2652 
2653  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
2654 
2655  /* Only a single bit must be set, not a range, and it must match */
2656  req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
2657 
2658  err = alloc_mem(ctx, &req2.memoryRequirements,
2659  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2660  (ded_req.prefersDedicatedAllocation ||
2661  ded_req.requiresDedicatedAllocation) ?
2662  &ded_alloc : ded_alloc.pNext,
2663  &f->flags, &f->mem[i]);
2664  if (err) {
2665  close(idesc.fd);
2666  return err;
2667  }
2668 
2669  f->size[i] = req2.memoryRequirements.size;
2670  }
2671 
2672  for (int i = 0; i < desc->nb_layers; i++) {
2673  const int planes = desc->layers[i].nb_planes;
2674  for (int j = 0; j < planes; j++) {
2675  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2676  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
2677  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
2678 
2679  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
2680  plane_info[bind_counts].pNext = NULL;
2681  plane_info[bind_counts].planeAspect = aspect;
2682 
2683  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2684  bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
2685  bind_info[bind_counts].image = f->img[i];
2686  bind_info[bind_counts].memory = f->mem[i];
2687 
2688  /* Offset is already signalled via pPlaneLayouts above */
2689  bind_info[bind_counts].memoryOffset = 0;
2690 
2691  bind_counts++;
2692  }
2693  }
2694 
2695  /* Bind the allocated memory to the images */
2696  ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
2697  if (ret != VK_SUCCESS) {
2698  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2699  ff_vk_ret2str(ret));
2700  err = AVERROR_EXTERNAL;
2701  goto fail;
2702  }
2703 
2704  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_EXTERNAL_IMPORT);
2705  if (err)
2706  goto fail;
2707 
2708  *frame = f;
2709 
2710  return 0;
2711 
2712 fail:
2713  for (int i = 0; i < desc->nb_layers; i++) {
2714  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2715  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2716  }
2717  for (int i = 0; i < desc->nb_objects; i++)
2718  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2719 
2720  av_free(f);
2721 
2722  return err;
2723 }
2724 
2725 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2726  const AVFrame *src, int flags)
2727 {
2728  int err = 0;
2729  AVVkFrame *f;
2730 
2731  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src)))
2732  return err;
2733 
2734  /* The unmapping function will free this */
2735  dst->data[0] = (uint8_t *)f;
2736  dst->width = src->width;
2737  dst->height = src->height;
2738 
2739  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2740  &vulkan_unmap_from_drm, f);
2741  if (err < 0)
2742  goto fail;
2743 
2744  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
2745 
2746  return 0;
2747 
2748 fail:
2750  dst->data[0] = NULL;
2751  return err;
2752 }
2753 
2754 #if CONFIG_VAAPI
2755 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
2756  AVFrame *dst, const AVFrame *src,
2757  int flags)
2758 {
2759  int err;
2760  AVFrame *tmp = av_frame_alloc();
2761  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
2762  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
2763  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
2764 
2765  if (!tmp)
2766  return AVERROR(ENOMEM);
2767 
2768  /* We have to sync since like the previous comment said, no semaphores */
2769  vaSyncSurface(vaapi_ctx->display, surface_id);
2770 
2771  tmp->format = AV_PIX_FMT_DRM_PRIME;
2772 
2773  err = av_hwframe_map(tmp, src, flags);
2774  if (err < 0)
2775  goto fail;
2776 
2777  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
2778  if (err < 0)
2779  goto fail;
2780 
2781  err = ff_hwframe_map_replace(dst, src);
2782 
2783 fail:
2784  av_frame_free(&tmp);
2785  return err;
2786 }
2787 #endif
2788 #endif
2789 
2790 #if CONFIG_CUDA
2791 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
2792  AVBufferRef *cuda_hwfc,
2793  const AVFrame *frame)
2794 {
2795  int err;
2796  VkResult ret;
2797  AVVkFrame *dst_f;
2798  AVVkFrameInternal *dst_int;
2799  AVHWDeviceContext *ctx = hwfc->device_ctx;
2800  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2801  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2803  VulkanDevicePriv *p = ctx->internal->priv;
2804  FFVulkanFunctions *vk = &p->vkctx.vkfn;
2805 
2806  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
2807  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2808  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2809  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2810  CudaFunctions *cu = cu_internal->cuda_dl;
2811  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
2812  CU_AD_FORMAT_UNSIGNED_INT8;
2813 
2814  dst_f = (AVVkFrame *)frame->data[0];
2815  dst_int = dst_f->internal;
2816 
2817  if (!dst_int->cuda_fc_ref) {
2818  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
2819  if (!dst_int->cuda_fc_ref)
2820  return AVERROR(ENOMEM);
2821 
2822  for (int i = 0; i < planes; i++) {
2823  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
2824  .offset = 0,
2825  .arrayDesc = {
2826  .Depth = 0,
2827  .Format = cufmt,
2828  .NumChannels = 1 + ((planes == 2) && i),
2829  .Flags = 0,
2830  },
2831  .numLevels = 1,
2832  };
2833  int p_w, p_h;
2834 
2835 #ifdef _WIN32
2836  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
2837  .type = IsWindows8OrGreater()
2838  ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
2839  : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
2840  .size = dst_f->size[i],
2841  };
2842  VkMemoryGetWin32HandleInfoKHR export_info = {
2843  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
2844  .memory = dst_f->mem[i],
2845  .handleType = IsWindows8OrGreater()
2846  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2847  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2848  };
2849  VkSemaphoreGetWin32HandleInfoKHR sem_export = {
2850  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
2851  .semaphore = dst_f->sem[i],
2852  .handleType = IsWindows8OrGreater()
2853  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2854  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2855  };
2856  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
2857  .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
2858  };
2859 
2860  ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
2861  &ext_desc.handle.win32.handle);
2862  if (ret != VK_SUCCESS) {
2863  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
2864  ff_vk_ret2str(ret));
2865  err = AVERROR_EXTERNAL;
2866  goto fail;
2867  }
2868  dst_int->ext_mem_handle[i] = ext_desc.handle.win32.handle;
2869 #else
2870  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
2871  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
2872  .size = dst_f->size[i],
2873  };
2874  VkMemoryGetFdInfoKHR export_info = {
2875  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2876  .memory = dst_f->mem[i],
2877  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
2878  };
2879  VkSemaphoreGetFdInfoKHR sem_export = {
2880  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
2881  .semaphore = dst_f->sem[i],
2882  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2883  };
2884  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
2885  .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
2886  };
2887 
2888  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
2889  &ext_desc.handle.fd);
2890  if (ret != VK_SUCCESS) {
2891  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
2892  ff_vk_ret2str(ret));
2893  err = AVERROR_EXTERNAL;
2894  goto fail;
2895  }
2896 #endif
2897 
2898  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
2899  if (ret < 0) {
2900 #ifndef _WIN32
2901  close(ext_desc.handle.fd);
2902 #endif
2903  err = AVERROR_EXTERNAL;
2904  goto fail;
2905  }
2906 
2907  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
2908  tex_desc.arrayDesc.Width = p_w;
2909  tex_desc.arrayDesc.Height = p_h;
2910 
2911  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
2912  dst_int->ext_mem[i],
2913  &tex_desc));
2914  if (ret < 0) {
2915  err = AVERROR_EXTERNAL;
2916  goto fail;
2917  }
2918 
2919  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
2920  dst_int->cu_mma[i], 0));
2921  if (ret < 0) {
2922  err = AVERROR_EXTERNAL;
2923  goto fail;
2924  }
2925 
2926 #ifdef _WIN32
2927  ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
2928  &ext_sem_desc.handle.win32.handle);
2929 #else
2930  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
2931  &ext_sem_desc.handle.fd);
2932 #endif
2933  if (ret != VK_SUCCESS) {
2934  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
2935  ff_vk_ret2str(ret));
2936  err = AVERROR_EXTERNAL;
2937  goto fail;
2938  }
2939 #ifdef _WIN32
2940  dst_int->ext_sem_handle[i] = ext_sem_desc.handle.win32.handle;
2941 #endif
2942 
2943  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i],
2944  &ext_sem_desc));
2945  if (ret < 0) {
2946 #ifndef _WIN32
2947  close(ext_sem_desc.handle.fd);
2948 #endif
2949  err = AVERROR_EXTERNAL;
2950  goto fail;
2951  }
2952  }
2953  }
2954 
2955  return 0;
2956 
2957 fail:
2958  vulkan_free_internal(dst_f);
2959  return err;
2960 }
2961 
2962 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
2963  AVFrame *dst, const AVFrame *src)
2964 {
2965  int err;
2966  CUcontext dummy;
2967  AVVkFrame *dst_f;
2968  AVVkFrameInternal *dst_int;
2969  VulkanFramesPriv *fp = hwfc->internal->priv;
2970  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2972 
2973  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
2974  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2975  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2976  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2977  CudaFunctions *cu = cu_internal->cuda_dl;
2978  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
2979  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
2980 
2981  dst_f = (AVVkFrame *)dst->data[0];
2982 
2983  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
2984  if (err < 0)
2985  return err;
2986 
2987  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
2988  if (err < 0)
2989  return err;
2990 
2991  err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
2992  if (err < 0) {
2993  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2994  return err;
2995  }
2996 
2997  dst_int = dst_f->internal;
2998 
2999  for (int i = 0; i < planes; i++) {
3000  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
3001  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
3002  }
3003 
3004  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
3005  planes, cuda_dev->stream));
3006  if (err < 0)
3007  goto fail;
3008 
3009  for (int i = 0; i < planes; i++) {
3010  CUDA_MEMCPY2D cpy = {
3011  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
3012  .srcDevice = (CUdeviceptr)src->data[i],
3013  .srcPitch = src->linesize[i],
3014  .srcY = 0,
3015 
3016  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
3017  .dstArray = dst_int->cu_array[i],
3018  };
3019 
3020  int p_w, p_h;
3021  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3022 
3023  cpy.WidthInBytes = p_w * desc->comp[i].step;
3024  cpy.Height = p_h;
3025 
3026  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
3027  if (err < 0)
3028  goto fail;
3029  }
3030 
3031  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
3032  planes, cuda_dev->stream));
3033  if (err < 0)
3034  goto fail;
3035 
3036  for (int i = 0; i < planes; i++)
3037  dst_f->sem_value[i]++;
3038 
3039  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3040 
3041  av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n");
3042 
3043  return err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
3044 
3045 fail:
3046  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3047  vulkan_free_internal(dst_f);
3048  av_buffer_unref(&dst->buf[0]);
3049  return err;
3050 }
3051 #endif
3052 
3053 static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
3054  const AVFrame *src, int flags)
3055 {
3057 
3058  switch (src->format) {
3059 #if CONFIG_LIBDRM
3060 #if CONFIG_VAAPI
3061  case AV_PIX_FMT_VAAPI:
3062  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
3063  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
3064  else
3065  return AVERROR(ENOSYS);
3066 #endif
3067  case AV_PIX_FMT_DRM_PRIME:
3068  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
3069  return vulkan_map_from_drm(hwfc, dst, src, flags);
3070  else
3071  return AVERROR(ENOSYS);
3072 #endif
3073  default:
3074  return AVERROR(ENOSYS);
3075  }
3076 }
3077 
3078 #if CONFIG_LIBDRM
3079 typedef struct VulkanDRMMapping {
3080  AVDRMFrameDescriptor drm_desc;
3081  AVVkFrame *source;
3082 } VulkanDRMMapping;
3083 
3084 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3085 {
3086  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
3087 
3088  for (int i = 0; i < drm_desc->nb_objects; i++)
3089  close(drm_desc->objects[i].fd);
3090 
3091  av_free(drm_desc);
3092 }
3093 
3094 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
3095 {
3096  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3097  if (vulkan_drm_format_map[i].vk_format == vkfmt)
3098  return vulkan_drm_format_map[i].drm_fourcc;
3099  return DRM_FORMAT_INVALID;
3100 }
3101 
3102 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3103  const AVFrame *src, int flags)
3104 {
3105  int err = 0;
3106  VkResult ret;
3107  AVVkFrame *f = (AVVkFrame *)src->data[0];
3109  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3110  VulkanFramesPriv *fp = hwfc->internal->priv;
3111  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
3112  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
3113  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3114  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3115  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3116  };
3117  VkSemaphoreWaitInfo wait_info = {
3118  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
3119  .flags = 0x0,
3120  .semaphoreCount = planes,
3121  };
3122 
3123  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
3124  if (!drm_desc)
3125  return AVERROR(ENOMEM);
3126 
3127  err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_EXTERNAL_EXPORT);
3128  if (err < 0)
3129  goto end;
3130 
3131  /* Wait for the operation to finish so we can cleanly export it. */
3132  wait_info.pSemaphores = f->sem;
3133  wait_info.pValues = f->sem_value;
3134 
3135  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
3136 
3137  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
3138  if (err < 0)
3139  goto end;
3140 
3141  ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
3142  &drm_mod);
3143  if (ret != VK_SUCCESS) {
3144  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
3145  err = AVERROR_EXTERNAL;
3146  goto end;
3147  }
3148 
3149  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
3150  VkMemoryGetFdInfoKHR export_info = {
3151  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3152  .memory = f->mem[i],
3153  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3154  };
3155 
3156  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3157  &drm_desc->objects[i].fd);
3158  if (ret != VK_SUCCESS) {
3159  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
3160  err = AVERROR_EXTERNAL;
3161  goto end;
3162  }
3163 
3164  drm_desc->nb_objects++;
3165  drm_desc->objects[i].size = f->size[i];
3166  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
3167  }
3168 
3169  drm_desc->nb_layers = planes;
3170  for (int i = 0; i < drm_desc->nb_layers; i++) {
3171  VkSubresourceLayout layout;
3172  VkImageSubresource sub = {
3173  .aspectMask = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
3174  };
3175  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
3176 
3177  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
3178  drm_desc->layers[i].nb_planes = 1;
3179 
3180  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
3181  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
3182  err = AVERROR_PATCHWELCOME;
3183  goto end;
3184  }
3185 
3186  drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
3187 
3188  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
3189  continue;
3190 
3191  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
3192  drm_desc->layers[i].planes[0].offset = layout.offset;
3193  drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
3194 
3195  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY)
3196  drm_desc->layers[i].planes[0].offset += f->offset[i];
3197  }
3198 
3199  dst->width = src->width;
3200  dst->height = src->height;
3201  dst->data[0] = (uint8_t *)drm_desc;
3202 
3203  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
3204 
3205  return 0;
3206 
3207 end:
3208  av_free(drm_desc);
3209  return err;
3210 }
3211 
3212 #if CONFIG_VAAPI
3213 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
3214  const AVFrame *src, int flags)
3215 {
3216  int err;
3217  AVFrame *tmp = av_frame_alloc();
3218  if (!tmp)
3219  return AVERROR(ENOMEM);
3220 
3221  tmp->format = AV_PIX_FMT_DRM_PRIME;
3222 
3223  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
3224  if (err < 0)
3225  goto fail;
3226 
3227  err = av_hwframe_map(dst, tmp, flags);
3228  if (err < 0)
3229  goto fail;
3230 
3231  err = ff_hwframe_map_replace(dst, src);
3232 
3233 fail:
3234  av_frame_free(&tmp);
3235  return err;
3236 }
3237 #endif
3238 #endif
3239 
3241  const AVFrame *src, int flags)
3242 {
3244 
3245  switch (dst->format) {
3246 #if CONFIG_LIBDRM
3247  case AV_PIX_FMT_DRM_PRIME:
3248  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
3249  return vulkan_map_to_drm(hwfc, dst, src, flags);
3250  else
3251  return AVERROR(ENOSYS);
3252 #if CONFIG_VAAPI
3253  case AV_PIX_FMT_VAAPI:
3254  if (p->vkctx.extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS)
3255  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
3256  else
3257  return AVERROR(ENOSYS);
3258 #endif
3259 #endif
3260  default:
3261  break;
3262  }
3263  return AVERROR(ENOSYS);
3264 }
3265 
3267 {
3268  size_t size;
3269  *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
3270  size = height*(*stride);
3271  size = FFALIGN(size, p->props.properties.limits.minMemoryMapAlignment);
3272  return size;
3273 }
3274 
3276  AVBufferRef **bufs, size_t *buf_offsets,
3277  const int *buf_stride, int w,
3278  int h, enum AVPixelFormat pix_fmt, int to_buf)
3279 {
3280  int err;
3281  AVVkFrame *frame = (AVVkFrame *)f->data[0];
3282  VulkanFramesPriv *fp = hwfc->internal->priv;
3284  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3285  VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
3286  int nb_img_bar = 0;
3287 
3288  const int nb_images = ff_vk_count_images(frame);
3289  int pixfmt_planes = av_pix_fmt_count_planes(pix_fmt);
3291 
3292  VkCommandBuffer cmd_buf;
3293  FFVkExecContext *exec = ff_vk_exec_get(to_buf ? &fp->download_exec :
3294  &fp->upload_exec);
3295  cmd_buf = exec->buf;
3296  ff_vk_exec_start(&p->vkctx, exec);
3297 
3298  err = ff_vk_exec_add_dep_buf(&p->vkctx, exec, bufs, pixfmt_planes, 1);
3299  if (err < 0)
3300  return err;
3301 
3302  err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, f,
3303  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
3304  VK_PIPELINE_STAGE_2_TRANSFER_BIT);
3305  if (err < 0)
3306  return err;
3307 
3308  ff_vk_frame_barrier(&p->vkctx, exec, f, img_bar, &nb_img_bar,
3309  VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
3310  VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR,
3311  to_buf ? VK_ACCESS_TRANSFER_READ_BIT :
3312  VK_ACCESS_TRANSFER_WRITE_BIT,
3313  to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL :
3314  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3315  VK_QUEUE_FAMILY_IGNORED);
3316 
3317  vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
3318  .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
3319  .pImageMemoryBarriers = img_bar,
3320  .imageMemoryBarrierCount = nb_img_bar,
3321  });
3322 
3323  /* Schedule a copy for each plane */
3324  for (int i = 0; i < pixfmt_planes; i++) {
3325  int idx = FFMIN(i, nb_images - 1);
3326  VkImageAspectFlags plane_aspect[] = { VK_IMAGE_ASPECT_COLOR_BIT,
3327  VK_IMAGE_ASPECT_PLANE_0_BIT,
3328  VK_IMAGE_ASPECT_PLANE_1_BIT,
3329  VK_IMAGE_ASPECT_PLANE_2_BIT, };
3330 
3331  FFVkBuffer *vkbuf = (FFVkBuffer *)bufs[i]->data;
3332  VkBufferImageCopy buf_reg = {
3333  .bufferOffset = buf_offsets[i],
3334  .bufferRowLength = buf_stride[i] / desc->comp[i].step,
3335  .imageSubresource.layerCount = 1,
3336  .imageSubresource.aspectMask = plane_aspect[(pixfmt_planes != nb_images) +
3337  i*(pixfmt_planes != nb_images)],
3338  .imageOffset = { 0, 0, 0, },
3339  };
3340 
3341  uint32_t p_w, p_h;
3342  get_plane_wh(&p_w, &p_h, pix_fmt, w, h, i);
3343 
3344  buf_reg.bufferImageHeight = p_h;
3345  buf_reg.imageExtent = (VkExtent3D){ p_w, p_h, 1, };
3346 
3347  if (to_buf)
3348  vk->CmdCopyImageToBuffer(cmd_buf, frame->img[idx],
3349  img_bar[0].newLayout,
3350  vkbuf->buf,
3351  1, &buf_reg);
3352  else
3353  vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[idx],
3354  img_bar[0].newLayout,
3355  1, &buf_reg);
3356  }
3357 
3358  err = ff_vk_exec_submit(&p->vkctx, exec);
3359  if (err < 0)
3360  return err;
3361 
3362  /* Wait for the operation to complete when downloading */
3363  if (to_buf)
3364  ff_vk_exec_wait(&p->vkctx, exec);
3365 
3366  return 0;
3367 }
3368 
3369 static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf,
3370  const AVFrame *swf, int from)
3371 {
3372  int err = 0;
3373  VkResult ret;
3374  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
3375  AVVulkanDeviceContext *hwctx = dev_ctx->hwctx;
3377  FFVulkanFunctions *vk = &p->vkctx.vkfn;
3378 
3379  AVFrame tmp;
3381  AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 };
3382  size_t buf_offsets[AV_NUM_DATA_POINTERS] = { 0 };
3383 
3384  uint32_t p_w, p_h;
3385  const int planes = av_pix_fmt_count_planes(swf->format);
3386 
3387  int host_mapped[AV_NUM_DATA_POINTERS] = { 0 };
3388  const int map_host = !!(p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY);
3389 
3390  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
3391  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
3392  return AVERROR(EINVAL);
3393  }
3394 
3395  if (swf->width > hwfc->width || swf->height > hwfc->height)
3396  return AVERROR(EINVAL);
3397 
3398  /* Create buffers */
3399  for (int i = 0; i < planes; i++) {
3400  size_t req_size;
3401 
3402  VkExternalMemoryBufferCreateInfo create_desc = {
3403  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
3404  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3405  };
3406 
3407  VkImportMemoryHostPointerInfoEXT import_desc = {
3408  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3409  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3410  };
3411 
3412  VkMemoryHostPointerPropertiesEXT p_props = {
3413  .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
3414  };
3415 
3416  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3417 
3418  tmp.linesize[i] = FFABS(swf->linesize[i]);
3419 
3420  /* Do not map images with a negative stride */
3421  if (map_host && swf->linesize[i] > 0) {
3422  size_t offs;
3423  offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment;
3424  import_desc.pHostPointer = swf->data[i] - offs;
3425 
3426  /* We have to compensate for the few extra bytes of padding we
3427  * completely ignore at the start */
3428  req_size = FFALIGN(offs + tmp.linesize[i] * p_h,
3429  p->hprops.minImportedHostPointerAlignment);
3430 
3431  ret = vk->GetMemoryHostPointerPropertiesEXT(hwctx->act_dev,
3432  import_desc.handleType,
3433  import_desc.pHostPointer,
3434  &p_props);
3435  if (ret == VK_SUCCESS && p_props.memoryTypeBits) {
3436  host_mapped[i] = 1;
3437  buf_offsets[i] = offs;
3438  }
3439  }
3440 
3441  if (!host_mapped[i])
3442  req_size = get_req_buffer_size(p, &tmp.linesize[i], p_h);
3443 
3444  err = ff_vk_create_avbuf(&p->vkctx, &bufs[i], req_size,
3445  host_mapped[i] ? &create_desc : NULL,
3446  host_mapped[i] ? &import_desc : NULL,
3447  from ? VK_BUFFER_USAGE_TRANSFER_DST_BIT :
3448  VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
3449  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
3450  (host_mapped[i] ?
3451  VK_MEMORY_PROPERTY_HOST_COHERENT_BIT : 0x0));
3452  if (err < 0)
3453  goto end;
3454 
3455  vkbufs[i] = (FFVkBuffer *)bufs[i]->data;
3456  }
3457 
3458  if (!from) {
3459  /* Map, copy image TO buffer (which then goes to the VkImage), unmap */
3460  if ((err = ff_vk_map_buffers(&p->vkctx, vkbufs, tmp.data, planes, 0)))
3461  goto end;
3462 
3463  for (int i = 0; i < planes; i++) {
3464  if (host_mapped[i])
3465  continue;
3466 
3467  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3468 
3469  av_image_copy_plane(tmp.data[i], tmp.linesize[i],
3470  (const uint8_t *)swf->data[i], swf->linesize[i],
3471  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3472  p_h);
3473  }
3474 
3475  if ((err = ff_vk_unmap_buffers(&p->vkctx, vkbufs, planes, 1)))
3476  goto end;
3477  }
3478 
3479  /* Copy buffers into/from image */
3480  err = transfer_image_buf(hwfc, (AVFrame *)vkf, bufs, buf_offsets,
3481  tmp.linesize, swf->width, swf->height, swf->format,
3482  from);
3483 
3484  if (from) {
3485  /* Map, copy buffer (which came FROM the VkImage) to the frame, unmap */
3486  if ((err = ff_vk_map_buffers(&p->vkctx, vkbufs, tmp.data, planes, 0)))
3487  goto end;
3488 
3489  for (int i = 0; i < planes; i++) {
3490  if (host_mapped[i])
3491  continue;
3492 
3493  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3494 
3496  (const uint8_t *)tmp.data[i], tmp.linesize[i],
3497  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3498  p_h);
3499  }
3500 
3501  if ((err = ff_vk_unmap_buffers(&p->vkctx, vkbufs, planes, 1)))
3502  goto end;
3503  }
3504 
3505 end:
3506  for (int i = 0; i < planes; i++)
3507  av_buffer_unref(&bufs[i]);
3508 
3509  return err;
3510 }
3511 
3513  const AVFrame *src)
3514 {
3516 
3517  switch (src->format) {
3518 #if CONFIG_CUDA
3519  case AV_PIX_FMT_CUDA:
3520 #ifdef _WIN32
3521  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
3522  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
3523 #else
3524  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
3525  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
3526 #endif
3527  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
3528 #endif
3529  default:
3530  if (src->hw_frames_ctx)
3531  return AVERROR(ENOSYS);
3532  else
3533  return vulkan_transfer_data(hwfc, dst, src, 0);
3534  }
3535 }
3536 
3537 #if CONFIG_CUDA
3538 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
3539  const AVFrame *src)
3540 {
3541  int err;
3542  CUcontext dummy;
3543  AVVkFrame *dst_f;
3544  AVVkFrameInternal *dst_int;
3545  VulkanFramesPriv *fp = hwfc->internal->priv;
3546  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3548 
3550  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3551  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3552  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3553  CudaFunctions *cu = cu_internal->cuda_dl;
3554  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
3555  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
3556 
3557  dst_f = (AVVkFrame *)src->data[0];
3558 
3559  err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_EXPORT);
3560  if (err < 0)
3561  return err;
3562 
3563  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
3564  if (err < 0)
3565  return err;
3566 
3567  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
3568  if (err < 0) {
3569  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3570  return err;
3571  }
3572 
3573  dst_int = dst_f->internal;
3574 
3575  for (int i = 0; i < planes; i++) {
3576  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
3577  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
3578  }
3579 
3580  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
3581  planes, cuda_dev->stream));
3582  if (err < 0)
3583  goto fail;
3584 
3585  for (int i = 0; i < planes; i++) {
3586  CUDA_MEMCPY2D cpy = {
3587  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
3588  .dstDevice = (CUdeviceptr)dst->data[i],
3589  .dstPitch = dst->linesize[i],
3590  .dstY = 0,
3591 
3592  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
3593  .srcArray = dst_int->cu_array[i],
3594  };
3595 
3596  int w, h;
3597  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3598 
3599  cpy.WidthInBytes = w * desc->comp[i].step;
3600  cpy.Height = h;
3601 
3602  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
3603  if (err < 0)
3604  goto fail;
3605  }
3606 
3607  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
3608  planes, cuda_dev->stream));
3609  if (err < 0)
3610  goto fail;
3611 
3612  for (int i = 0; i < planes; i++)
3613  dst_f->sem_value[i]++;
3614 
3615  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3616 
3617  av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n");
3618 
3619  return prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
3620 
3621 fail:
3622  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3623  vulkan_free_internal(dst_f);
3624  av_buffer_unref(&dst->buf[0]);
3625  return err;
3626 }
3627 #endif
3628 
3630  const AVFrame *src)
3631 {
3633 
3634  switch (dst->format) {
3635 #if CONFIG_CUDA
3636  case AV_PIX_FMT_CUDA:
3637 #ifdef _WIN32
3638  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
3639  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
3640 #else
3641  if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
3642  (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
3643 #endif
3644  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
3645 #endif
3646  default:
3647  if (dst->hw_frames_ctx)
3648  return AVERROR(ENOSYS);
3649  else
3650  return vulkan_transfer_data(hwfc, src, dst, 1);
3651  }
3652 }
3653 
3655  AVHWFramesContext *src_fc, int flags)
3656 {
3657  return vulkan_frames_init(dst_fc);
3658 }
3659 
3661 {
3662  int err;
3663  AVVkFrame *f = av_mallocz(sizeof(AVVkFrame));
3664  if (!f)
3665  return NULL;
3666 
3667  f->internal = av_mallocz(sizeof(*f->internal));
3668  if (!f->internal) {
3669  av_free(f);
3670  return NULL;
3671  }
3672 
3673  err = pthread_mutex_init(&f->internal->update_mutex, NULL);
3674  if (err != 0) {
3675  av_free(f->internal);
3676  av_free(f);
3677  return NULL;
3678  }
3679 
3680  return f;
3681 }
3682 
3685  .name = "Vulkan",
3686 
3687  .device_hwctx_size = sizeof(AVVulkanDeviceContext),
3688  .device_priv_size = sizeof(VulkanDevicePriv),
3689  .frames_hwctx_size = sizeof(AVVulkanFramesContext),
3690  .frames_priv_size = sizeof(VulkanFramesPriv),
3691 
3692  .device_init = &vulkan_device_init,
3693  .device_create = &vulkan_device_create,
3694  .device_derive = &vulkan_device_derive,
3695 
3696  .frames_get_constraints = &vulkan_frames_get_constraints,
3697  .frames_init = vulkan_frames_init,
3698  .frames_get_buffer = vulkan_get_buffer,
3699  .frames_uninit = vulkan_frames_uninit,
3700 
3701  .transfer_get_formats = vulkan_transfer_get_formats,
3702  .transfer_data_to = vulkan_transfer_data_to,
3703  .transfer_data_from = vulkan_transfer_data_from,
3704 
3705  .map_to = vulkan_map_to,
3706  .map_from = vulkan_map_from,
3707  .frames_derive_to = &vulkan_frames_derive_to,
3708 
3709  .pix_fmts = (const enum AVPixelFormat []) {
3712  },
3713 };
vulkan_loader.h
FF_VK_EXT_NO_FLAG
@ FF_VK_EXT_NO_FLAG
Definition: vulkan_functions.h:50
formats
formats
Definition: signature.h:48
load_libvulkan
static int load_libvulkan(AVHWDeviceContext *ctx)
Definition: hwcontext_vulkan.c:357
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:92
vulkan_device_init
static int vulkan_device_init(AVHWDeviceContext *ctx)
Definition: hwcontext_vulkan.c:1382
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:487
ff_vk_load_props
int ff_vk_load_props(FFVulkanContext *s)
Loads props/mprops/driver_props.
Definition: vulkan.c:86
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVVulkanDeviceContext::phys_dev
VkPhysicalDevice phys_dev
Physical device.
Definition: hwcontext_vulkan.h:65
check_validation_layers
static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts, const char *const **dst, uint32_t *num, int *debug_mode)
Definition: hwcontext_vulkan.c:603
AV_PIX_FMT_CUDA
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition: pixfmt.h:253
ff_vk_exec_get
FFVkExecContext * ff_vk_exec_get(FFVkExecPool *pool)
Retrieve an execution pool.
Definition: vulkan.c:494
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
VulkanDevicePriv::libvulkan
void * libvulkan
Definition: hwcontext_vulkan.c:85
VulkanOptExtension::name
const char * name
Definition: hwcontext_vulkan.c:392
FFVkFormatEntry::nb_images
int nb_images
Definition: hwcontext_vulkan.c:164
AVCUDADeviceContextInternal
Definition: hwcontext_cuda_internal.h:31
AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE
@ AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE
Definition: hwcontext_vulkan.h:170
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
VulkanQueueCtx::nb_buf_deps
int nb_buf_deps
Definition: hwcontext_vulkan.c:79
SETUP_QUEUE
#define SETUP_QUEUE(qf_idx)
FF_VK_EXT_VIDEO_DECODE_H264
@ FF_VK_EXT_VIDEO_DECODE_H264
Definition: vulkan_functions.h:44
hwcontext_cuda_internal.h
vulkan_transfer_data_to
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_vulkan.c:3512
thread.h
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2936
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_qf_init
int ff_vk_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, VkQueueFlagBits dev_family)
Chooses a QF and loads it into a context.
Definition: vulkan.c:225
vulkan_frames_get_constraints
static int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
Definition: hwcontext_vulkan.c:1632
AVVkFrameInternal::update_mutex
pthread_mutex_t update_mutex
Definition: hwcontext_vulkan.c:139
vulkan_transfer_data
static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, const AVFrame *swf, int from)
Definition: hwcontext_vulkan.c:3369
av_unused
#define av_unused
Definition: attributes.h:131
vulkan_frames_derive_to
static int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags)
Definition: hwcontext_vulkan.c:3654
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:100
FF_VK_EXT_VIDEO_DECODE_AV1
@ FF_VK_EXT_VIDEO_DECODE_AV1
Definition: vulkan_functions.h:46
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
pixdesc.h
AVVulkanDeviceContext::get_proc_addr
PFN_vkGetInstanceProcAddr get_proc_addr
Pointer to the instance-provided vkGetInstanceProcAddr loading function.
Definition: hwcontext_vulkan.h:55
optional_device_exts
static const VulkanOptExtension optional_device_exts[]
Definition: hwcontext_vulkan.c:401
AVFrame::width
int width
Definition: frame.h:412
w
uint8_t w
Definition: llviddspenc.c:38
VulkanQueueCtx::fence
VkFence fence
Definition: hwcontext_vulkan.c:71
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:1991
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:348
AVVulkanFramesContext::create_pnext
void * create_pnext
Extension data for image creation.
Definition: hwcontext_vulkan.h:206
FF_VK_EXT_DESCRIPTOR_BUFFER
@ FF_VK_EXT_DESCRIPTOR_BUFFER
Definition: vulkan_functions.h:40
VulkanDevicePriv::img_qfs
uint32_t img_qfs[5]
Definition: hwcontext_vulkan.c:107
av_hwframe_map
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:794
nb_vk_formats_list
static const int nb_vk_formats_list
Definition: hwcontext_vulkan.c:231
data
const char data[16]
Definition: mxf.c:148
AVVulkanDeviceContext::queue_family_decode_index
int queue_family_decode_index
Queue family index for video decode ops, and the amount of queues enabled.
Definition: hwcontext_vulkan.h:138
try_export_flags
static void try_export_flags(AVHWFramesContext *hwfc, VkExternalMemoryHandleTypeFlags *comp_handle_types, VkExternalMemoryHandleTypeFlagBits *iexp, VkExternalMemoryHandleTypeFlagBits exp)
Definition: hwcontext_vulkan.c:2099
AV_PIX_FMT_YUV420P10
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:465
AVVulkanDeviceContext::inst
VkInstance inst
Vulkan instance.
Definition: hwcontext_vulkan.h:60
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:251
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AVVAAPIDeviceContext::display
VADisplay display
The VADisplay handle, to be filled by the user.
Definition: hwcontext_vaapi.h:72
fc
#define fc(width, name, range_min, range_max)
Definition: cbs_av1.c:457
vulkan_map_from
static int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
Definition: hwcontext_vulkan.c:3240
AVHWDeviceContext::internal
AVHWDeviceInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:71
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
FFVkFormatEntry::vkf
VkFormat vkf
Definition: hwcontext_vulkan.c:160
AVHWFramesContext::internal
AVHWFramesInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:134
ff_vk_uninit
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition: vulkan.c:1892
AVDictionary
Definition: dict.c:34
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:742
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:151
av_popcount
#define av_popcount
Definition: common.h:150
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:458
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AV_DRM_MAX_PLANES
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
Definition: hwcontext_drm.h:39
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
AVFrame::buf
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:590
AVVulkanDeviceContext::nb_decode_queues
int nb_decode_queues
Definition: hwcontext_vulkan.h:139
FF_VK_EXT_VIDEO_DECODE_H265
@ FF_VK_EXT_VIDEO_DECODE_H265
Definition: vulkan_functions.h:45
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:376
VulkanDeviceSelection::uuid
uint8_t uuid[VK_UUID_SIZE]
Definition: hwcontext_vulkan.c:819
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:596
AVVulkanDeviceContext::queue_family_index
int queue_family_index
Queue family index for graphics operations, and the number of queues enabled for it.
Definition: hwcontext_vulkan.h:108
AV_PIX_FMT_P212
#define AV_PIX_FMT_P212
Definition: pixfmt.h:527
AVHWFramesInternal::pool_internal
AVBufferPool * pool_internal
Definition: hwcontext_internal.h:118
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
FFVkBuffer::buf
VkBuffer buf
Definition: vulkan.h:97
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:1687
AV_HWDEVICE_TYPE_VULKAN
@ AV_HWDEVICE_TYPE_VULKAN
Definition: hwcontext.h:39
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:453
AV_HWDEVICE_TYPE_CUDA
@ AV_HWDEVICE_TYPE_CUDA
Definition: hwcontext.h:30
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:1889
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2976
ASPECT_3PLANE
#define ASPECT_3PLANE
Definition: hwcontext_vulkan.c:157
VulkanDevicePriv::hprops
VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
Definition: hwcontext_vulkan.c:94
vulkan_device_derive
static int vulkan_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:1545
VulkanOptExtension::flag
FFVulkanExtensions flag
Definition: hwcontext_vulkan.c:393
AVVulkanDeviceContext::alloc
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
Definition: hwcontext_vulkan.h:48
AVHWFramesInternal::priv
void * priv
Definition: hwcontext_internal.h:116
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:205
VulkanDeviceSelection::drm_minor
uint32_t drm_minor
Definition: hwcontext_vulkan.c:822
lock_frame
static void lock_frame(AVHWFramesContext *fc, AVVkFrame *vkf)
Definition: hwcontext_vulkan.c:2227
AVVulkanDeviceContext::queue_family_comp_index
int queue_family_comp_index
Queue family index for compute operations and the number of queues enabled.
Definition: hwcontext_vulkan.h:122
ff_vk_find_struct
static const void * ff_vk_find_struct(const void *chain, VkStructureType stype)
Definition: vulkan.h:279
FF_VK_EXT_VIDEO_DECODE_QUEUE
@ FF_VK_EXT_VIDEO_DECODE_QUEUE
Definition: vulkan_functions.h:43
fail
#define fail()
Definition: checkasm.h:138
AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
@ AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
Definition: hwcontext_vulkan.h:165
AVDRMLayerDescriptor::nb_planes
int nb_planes
Number of planes in the layer.
Definition: hwcontext_drm.h:106
ff_vk_unmap_buffers
int ff_vk_unmap_buffers(FFVulkanContext *s, FFVkBuffer **buf, int nb_buffers, int flush)
Definition: vulkan.c:1012
AVVulkanFramesContext::flags
AVVkFrameFlags flags
A combination of AVVkFrameFlags.
Definition: hwcontext_vulkan.h:222
VulkanDevicePriv
Definition: hwcontext_vulkan.c:83
AVDRMLayerDescriptor::planes
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
Definition: hwcontext_drm.h:110
dummy
int dummy
Definition: motion.c:66
AVVkFrame::mem
VkDeviceMemory mem[AV_NUM_DATA_POINTERS]
Memory backing the images.
Definition: hwcontext_vulkan.h:283
AVVulkanFramesContext
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
Definition: hwcontext_vulkan.h:176
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:471
lock_queue
static void lock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
Definition: hwcontext_vulkan.c:1370
AVCUDADeviceContextInternal::cuda_device
CUdevice cuda_device
Definition: hwcontext_cuda_internal.h:34
VulkanDevicePriv::vkctx
FFVulkanContext vkctx
Definition: hwcontext_vulkan.c:87
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)
Definition: hwcontext_vulkan.c:283
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_ret2str
const char * ff_vk_ret2str(VkResult res)
Converts Vulkan return values to strings.
Definition: vulkan.c:34
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:449
FF_VK_EXT_COOP_MATRIX
@ FF_VK_EXT_COOP_MATRIX
Definition: vulkan_functions.h:48
VulkanDevicePriv::device_features_1_1
VkPhysicalDeviceVulkan11Features device_features_1_1
Definition: hwcontext_vulkan.c:97
VulkanDevicePriv::props
VkPhysicalDeviceProperties2 props
Definition: hwcontext_vulkan.c:92
vk_find_format_entry
static const struct FFVkFormatEntry * vk_find_format_entry(enum AVPixelFormat p)
Definition: hwcontext_vulkan.c:241
AVDRMPlaneDescriptor::offset
ptrdiff_t offset
Offset within that object of this plane.
Definition: hwcontext_drm.h:83
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:88
AV_PIX_FMT_YUV444P10
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:468
vk_dbg_callback
static VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *data, void *priv)
Definition: hwcontext_vulkan.c:430
FF_VK_EXT_VIDEO_QUEUE
@ FF_VK_EXT_VIDEO_QUEUE
Definition: vulkan_functions.h:42
AV_PIX_FMT_Y210
#define AV_PIX_FMT_Y210
Definition: pixfmt.h:518
avassert.h
HWContextType::type
enum AVHWDeviceType type
Definition: hwcontext_internal.h:30
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
AV_PIX_FMT_YUV422P16
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:477
AVHWFramesContext::height
int height
Definition: hwcontext.h:229
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:465
ff_vk_create_avbuf
int ff_vk_create_avbuf(FFVulkanContext *s, AVBufferRef **ref, size_t size, void *pNext, void *alloc_pNext, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
Definition: vulkan.c:938
AVVulkanDeviceContext::nb_graphics_queues
int nb_graphics_queues
Definition: hwcontext_vulkan.h:109
vulkan_map_to
static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
Definition: hwcontext_vulkan.c:3053
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:62
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:384
AVHWFramesContext::pool
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:190
VulkanDeviceSelection::pci_device
uint32_t pci_device
Definition: hwcontext_vulkan.c:825
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:478
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:51
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
ff_vk_load_functions
static int ff_vk_load_functions(AVHWDeviceContext *ctx, FFVulkanFunctions *vk, uint64_t extensions_mask, int has_inst, int has_dev)
Function loader.
Definition: vulkan_loader.h:89
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demux_decode.c:41
prepare_frame
static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, AVVkFrame *frame, enum PrepMode pmode)
Definition: hwcontext_vulkan.c:1892
VulkanDevicePriv::atomic_float_features
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_features
Definition: hwcontext_vulkan.c:101
ff_vk_exec_wait
void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e)
Definition: vulkan.c:501
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:178
ASPECT_2PLANE
#define ASPECT_2PLANE
Definition: hwcontext_vulkan.c:156
VulkanQueueCtx
Definition: hwcontext_vulkan.c:70
from
const char * from
Definition: jacosubdec.c:66
FF_VK_EXT_EXTERNAL_HOST_MEMORY
@ FF_VK_EXT_EXTERNAL_HOST_MEMORY
Definition: vulkan_functions.h:34
AVVulkanFramesContext::unlock_frame
void(* unlock_frame)(struct AVHWFramesContext *fc, AVVkFrame *vkf)
Similar to lock_frame(), unlocks a frame.
Definition: hwcontext_vulkan.h:256
AVVulkanFramesContext::img_flags
VkImageCreateFlags img_flags
Flags to set during image creation.
Definition: hwcontext_vulkan.h:228
vulkan_frames_uninit
static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:2237
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
AV_PIX_FMT_YUV420P16
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:476
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AVDRMObjectDescriptor::fd
int fd
DRM PRIME fd for the object.
Definition: hwcontext_drm.h:52
check_extensions
static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, const char *const **dst, uint32_t *num, int debug)
Definition: hwcontext_vulkan.c:474
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:572
VulkanDeviceSelection::index
int index
Definition: hwcontext_vulkan.c:827
vulkan_transfer_get_formats
static int vulkan_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
Definition: hwcontext_vulkan.c:2393
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:66
ff_vk_exec_pool_free
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition: vulkan.c:256
AV_PIX_FMT_GRAYF32
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:497
LIBAVUTIL_VERSION_MINOR
#define LIBAVUTIL_VERSION_MINOR
Definition: version.h:82
get_req_buffer_size
static size_t get_req_buffer_size(VulkanDevicePriv *p, int *stride, int height)
Definition: hwcontext_vulkan.c:3266
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
FFVkFormatEntry::nb_images_fallback
int nb_images_fallback
Definition: hwcontext_vulkan.c:165
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:65
vulkan_frame_free_cb
static void vulkan_frame_free_cb(void *opaque, uint8_t *data)
Definition: hwcontext_vulkan.c:1809
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:233
AVVulkanDeviceContext
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_vulkan.h:44
VulkanDevicePriv::qf_mutex
pthread_mutex_t ** qf_mutex
Definition: hwcontext_vulkan.c:105
opts
AVDictionary * opts
Definition: movenc.c:50
PREP_MODE_WRITE
@ PREP_MODE_WRITE
Definition: hwcontext_vulkan.c:1885
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:455
pick_queue_family
static int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf, VkQueueFlagBits flags)
Definition: hwcontext_vulkan.c:999
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:222
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
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:99
FFVkFormatEntry
Definition: hwcontext_vulkan.c:159
VulkanDevicePriv::desc_buf_features
VkPhysicalDeviceDescriptorBufferFeaturesEXT desc_buf_features
Definition: hwcontext_vulkan.c:100
AVHWDeviceInternal::priv
void * priv
Definition: hwcontext_internal.h:105
AV_PIX_FMT_YUYV422
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
AVVkFrameInternal
Definition: hwcontext_vulkan.c:138
VulkanDevicePriv::debug_ctx
VkDebugUtilsMessengerEXT debug_ctx
Definition: hwcontext_vulkan.c:111
AVVulkanFramesContext::alloc_pnext
void * alloc_pnext[AV_NUM_DATA_POINTERS]
Extension data for memory allocation.
Definition: hwcontext_vulkan.h:215
setup_queue_families
static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
Definition: hwcontext_vulkan.c:1022
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:152
LIBAVUTIL_VERSION_MAJOR
#define LIBAVUTIL_VERSION_MAJOR
Definition: version.h:81
AV_PIX_FMT_P410
#define AV_PIX_FMT_P410
Definition: pixfmt.h:526
ff_hwcontext_type_vulkan
const HWContextType ff_hwcontext_type_vulkan
Definition: hwcontext_vulkan.c:3683
hwcontext_vulkan.h
AVVulkanDeviceContext::enabled_inst_extensions
const char *const * enabled_inst_extensions
Enabled instance extensions.
Definition: hwcontext_vulkan.h:87
VulkanDevicePriv::device_features_1_2
VkPhysicalDeviceVulkan12Features device_features_1_2
Definition: hwcontext_vulkan.c:98
VulkanQueueCtx::buf_deps_alloc_size
unsigned int buf_deps_alloc_size
Definition: hwcontext_vulkan.c:80
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:236
VulkanQueueCtx::qidx
int qidx
Definition: hwcontext_vulkan.c:75
AVVulkanFramesContext::usage
VkImageUsageFlagBits usage
Defines extra usage of output frames.
Definition: hwcontext_vulkan.h:195
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:258
VulkanDevicePriv::device_features_1_3
VkPhysicalDeviceVulkan13Features device_features_1_3
Definition: hwcontext_vulkan.c:99
AV_PIX_FMT_YUV422P10
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:466
ff_vk_exec_pool_init
int ff_vk_exec_pool_init(FFVulkanContext *s, FFVkQueueFamilyCtx *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:296
AVVulkanDeviceContext::queue_family_tx_index
int queue_family_tx_index
Queue family index for transfer operations and the number of queues enabled.
Definition: hwcontext_vulkan.h:115
alloc_bind_mem
static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, void *alloc_pnext, size_t alloc_pnext_stride)
Definition: hwcontext_vulkan.c:1814
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
FFVulkanContext
Definition: vulkan.h:228
fp
#define fp
Definition: regdef.h:44
exp
int8_t exp
Definition: eval.c:72
ff_vk_count_images
static int ff_vk_count_images(AVVkFrame *f)
Definition: vulkan.h:270
VulkanFramesPriv
Definition: hwcontext_vulkan.c:126
vulkan_frame_free
static void vulkan_frame_free(AVHWFramesContext *hwfc, AVVkFrame *f)
Definition: hwcontext_vulkan.c:1781
index
int index
Definition: gxfenc.c:89
pthread_mutex_unlock
#define pthread_mutex_unlock(a)
Definition: ffprobe.c:79
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
VulkanDeviceSelection
Definition: hwcontext_vulkan.c:818
FF_VK_EXT_DRM_MODIFIER_FLAGS
@ FF_VK_EXT_DRM_MODIFIER_FLAGS
Definition: vulkan_functions.h:31
source
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a source
Definition: filter_design.txt:255
VulkanDevicePriv::nb_tot_qfs
uint32_t nb_tot_qfs
Definition: hwcontext_vulkan.c:106
FFVulkanContext::device
AVHWDeviceContext * device
Definition: vulkan.h:252
AVDRMFrameDescriptor::layers
AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]
Array of layers in the frame.
Definition: hwcontext_drm.h:149
usage
const char * usage
Definition: floatimg_cmp.c:60
PREP_MODE_DECODING_DST
@ PREP_MODE_DECODING_DST
Definition: hwcontext_vulkan.c:1888
AVVkFrame::size
size_t size[AV_NUM_DATA_POINTERS]
Definition: hwcontext_vulkan.h:284
vulkan_pool_alloc
static AVBufferRef * vulkan_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_vulkan.c:2161
PrepMode
PrepMode
Definition: hwcontext_vulkan.c:1884
VulkanDeviceSelection::has_drm
uint32_t has_drm
Definition: hwcontext_vulkan.c:823
f
f
Definition: af_crystalizer.c:121
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:68
sem_wait
#define sem_wait(psem)
Definition: semaphore.h:27
AV_PIX_FMT_P012
#define AV_PIX_FMT_P012
Definition: pixfmt.h:515
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
AVVkFrame
Definition: hwcontext_vulkan.h:265
av_vk_frame_alloc
AVVkFrame * av_vk_frame_alloc(void)
Allocates a single AVVkFrame and initializes everything as 0.
Definition: hwcontext_vulkan.c:3660
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:121
vulkan_device_free
static void vulkan_device_free(AVHWDeviceContext *ctx)
Definition: hwcontext_vulkan.c:1156
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:494
AV_PIX_FMT_YUV422P12
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:470
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:451
size
int size
Definition: twinvq_data.h:10344
vulkan_transfer_data_from
static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_vulkan.c:3629
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:341
VulkanDevicePriv::use_linear_images
int use_linear_images
Definition: hwcontext_vulkan.c:114
FFVkQueueFamilyCtx
Definition: vulkan.h:111
AV_PIX_FMT_YUV444P12
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:472
planes
static const struct @362 planes[]
FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
@ FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
Definition: vulkan_functions.h:30
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:427
VulkanDevicePriv::transfer_qf
FFVkQueueFamilyCtx transfer_qf
Definition: hwcontext_vulkan.c:89
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:191
VulkanDeviceSelection::vendor_id
uint32_t vendor_id
Definition: hwcontext_vulkan.c:826
AV_PIX_FMT_Y212
#define AV_PIX_FMT_Y212
Definition: pixfmt.h:519
AVDRMObjectDescriptor::size
size_t size
Total size of the object.
Definition: hwcontext_drm.h:58
height
#define height
VulkanFramesPriv::upload_exec
FFVkExecPool upload_exec
Definition: hwcontext_vulkan.c:131
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:478
FFVkExecContext
Definition: vulkan.h:153
VulkanOptExtension
Definition: hwcontext_vulkan.c:391
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:256
AV_PIX_FMT_P216
#define AV_PIX_FMT_P216
Definition: pixfmt.h:529
CHECK_CU
#define CHECK_CU(x)
Definition: cuviddec.c:116
AV_PIX_FMT_P210
#define AV_PIX_FMT_P210
Definition: pixfmt.h:525
AV_PIX_FMT_VAAPI
@ AV_PIX_FMT_VAAPI
Hardware acceleration through VA-API, data[3] contains a VASurfaceID.
Definition: pixfmt.h:119
VulkanDevicePriv::dev_is_nvidia
int dev_is_nvidia
Definition: hwcontext_vulkan.c:123
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:147
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
vulkan_free_internal
static void vulkan_free_internal(AVVkFrame *f)
Definition: hwcontext_vulkan.c:1745
AV_HWDEVICE_TYPE_VAAPI
@ AV_HWDEVICE_TYPE_VAAPI
Definition: hwcontext.h:31
VulkanQueueCtx::qf
int qf
Definition: hwcontext_vulkan.c:74
COPY_FEATURE
#define COPY_FEATURE(DST, NAME)
vulkan.h
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
AVDRMFrameDescriptor::objects
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
Definition: hwcontext_drm.h:141
AVCUDADeviceContextInternal::cuda_dl
CudaFunctions * cuda_dl
Definition: hwcontext_cuda_internal.h:32
ff_vk_exec_start
int ff_vk_exec_start(FFVulkanContext *s, FFVkExecContext *e)
Start/submit/wait an execution.
Definition: vulkan.c:510
VulkanQueueCtx::buf_deps
AVBufferRef ** buf_deps
Definition: hwcontext_vulkan.c:78
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:244
FF_VK_EXT_EXTERNAL_FD_MEMORY
@ FF_VK_EXT_EXTERNAL_FD_MEMORY
Definition: vulkan_functions.h:32
VulkanFramesPriv::compute_exec
FFVkExecPool compute_exec
Definition: hwcontext_vulkan.c:128
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:31
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:368
plane_info
Definition: vf_edgedetect.c:52
VulkanDevicePriv::nb_img_qfs
uint32_t nb_img_qfs
Definition: hwcontext_vulkan.c:108
ff_vk_frame_barrier
void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e, AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar, VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage, VkAccessFlagBits new_access, VkImageLayout new_layout, uint32_t new_qf)
Definition: vulkan.c:1299
vulkan_frames_init
static int vulkan_frames_init(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:2253
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AVVulkanDeviceContext::nb_encode_queues
int nb_encode_queues
Definition: hwcontext_vulkan.h:131
AV_PIX_FMT_X2RGB10
#define AV_PIX_FMT_X2RGB10
Definition: pixfmt.h:522
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:254
VulkanDeviceSelection::has_uuid
int has_uuid
Definition: hwcontext_vulkan.c:820
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:457
FFVulkanContext::extensions
FFVulkanExtensions extensions
Definition: vulkan.h:232
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:949
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:262
mod
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:750
AV_PIX_FMT_P016
#define AV_PIX_FMT_P016
Definition: pixfmt.h:516
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:452
AVHWFrameTransferDirection
AVHWFrameTransferDirection
Definition: hwcontext.h:415
create_instance
static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
Definition: hwcontext_vulkan.c:713
stride
#define stride
Definition: h264pred_template.c:537
AVVkFrame::sem
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization timeline semaphores, one for each VkImage.
Definition: hwcontext_vulkan.h:303
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
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
ret
ret
Definition: filter_design.txt:187
pixfmt
enum AVPixelFormat pixfmt
Definition: kmsgrab.c:365
AVHWDeviceContext::type
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:79
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:89
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVHWFramesContext::device_ctx
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:149
FFVulkanContext::vkfn
FFVulkanFunctions vkfn
Definition: vulkan.h:231
cuda_check.h
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:162
vulkan_get_buffer
static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
Definition: hwcontext_vulkan.c:2379
FFVkExecPool
Definition: vulkan.h:210
transfer_image_buf
static int transfer_image_buf(AVHWFramesContext *hwfc, AVFrame *f, AVBufferRef **bufs, size_t *buf_offsets, const int *buf_stride, int w, int h, enum AVPixelFormat pix_fmt, int to_buf)
Definition: hwcontext_vulkan.c:3275
unlock_queue
static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
Definition: hwcontext_vulkan.c:1376
AVHWFramesConstraints::max_height
int max_height
Definition: hwcontext.h:479
AVVkFrame::internal
struct AVVkFrameInternal * internal
Internal data.
Definition: hwcontext_vulkan.h:316
AV_PIX_FMT_YUV420P12
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:469
AV_PIX_FMT_UYVY422
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:81
FFVkExecContext::buf
VkCommandBuffer buf
Definition: vulkan.h:164
SIZE_SPECIFIER
#define SIZE_SPECIFIER
Definition: internal.h:141
AVFrame::hw_frames_ctx
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition: frame.h:752
vulkan_device_create
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:1529
FFVkQueueFamilyCtx::nb_queues
int nb_queues
Definition: vulkan.h:113
AVFrame::height
int height
Definition: frame.h:412
FFVkFormatEntry::pixfmt
enum AVPixelFormat pixfmt
Definition: hwcontext_vulkan.c:161
av_image_copy_plane_uc_from
void av_image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, const uint8_t *src, ptrdiff_t src_linesize, ptrdiff_t bytewidth, int height)
Copy image data located in uncacheable (e.g.
Definition: imgutils.c:359
AVHWFramesConstraints::min_height
int min_height
Definition: hwcontext.h:472
VulkanQueueCtx::was_synchronous
int was_synchronous
Definition: hwcontext_vulkan.c:73
RELEASE_PROPS
#define RELEASE_PROPS(props, count)
Definition: hwcontext_vulkan.c:467
VulkanDevicePriv::compute_qf
FFVkQueueFamilyCtx compute_qf
Definition: hwcontext_vulkan.c:88
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AVVulkanDeviceContext::nb_comp_queues
int nb_comp_queues
Definition: hwcontext_vulkan.h:123
AV_PIX_FMT_GBRAPF32
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:495
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:842
FF_VK_EXT_DEBUG_UTILS
@ FF_VK_EXT_DEBUG_UTILS
Definition: vulkan_functions.h:35
optional_instance_exts
static const VulkanOptExtension optional_instance_exts[]
Definition: hwcontext_vulkan.c:396
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
FFVkFormatEntry::fallback
const VkFormat fallback[5]
Definition: hwcontext_vulkan.c:166
PREP_MODE_EXTERNAL_IMPORT
@ PREP_MODE_EXTERNAL_IMPORT
Definition: hwcontext_vulkan.c:1887
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:71
AVVulkanFramesContext::tiling
VkImageTiling tiling
Controls the tiling of allocated frames.
Definition: hwcontext_vulkan.h:185
VulkanDeviceSelection::drm_major
uint32_t drm_major
Definition: hwcontext_vulkan.c:821
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:514
unlock_frame
static void unlock_frame(AVHWFramesContext *fc, AVVkFrame *vkf)
Definition: hwcontext_vulkan.c:2232
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:311
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:270
desc
const char * desc
Definition: libsvtav1.c:83
AVVulkanDeviceContext::enabled_dev_extensions
const char *const * enabled_dev_extensions
Enabled device extensions.
Definition: hwcontext_vulkan.h:98
AVVulkanFramesContext::nb_layers
int nb_layers
Number of layers each image will have.
Definition: hwcontext_vulkan.h:241
FFVulkanContext::hwctx
AVVulkanDeviceContext * hwctx
Definition: vulkan.h:253
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:70
VulkanFramesPriv::download_exec
FFVkExecPool download_exec
Definition: hwcontext_vulkan.c:132
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
FFVulkanExtensions
FFVulkanExtensions
Definition: vulkan_functions.h:29
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:70
hwcontext_internal.h
AVVulkanDeviceContext::nb_enabled_inst_extensions
int nb_enabled_inst_extensions
Definition: hwcontext_vulkan.h:88
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVDictionaryEntry
Definition: dict.h:89
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:1974
ff_vk_exec_discard_deps
void ff_vk_exec_discard_deps(FFVulkanContext *s, FFVkExecContext *e)
Definition: vulkan.c:546
PREP_MODE_EXTERNAL_EXPORT
@ PREP_MODE_EXTERNAL_EXPORT
Definition: hwcontext_vulkan.c:1886
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AV_PIX_FMT_P416
#define AV_PIX_FMT_P416
Definition: pixfmt.h:530
VulkanDevicePriv::mprops
VkPhysicalDeviceMemoryProperties mprops
Definition: hwcontext_vulkan.c:93
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
FF_VK_EXT_EXTERNAL_FD_SEM
@ FF_VK_EXT_EXTERNAL_FD_SEM
Definition: vulkan_functions.h:33
FFVkBuffer
Definition: vulkan.h:96
AVVulkanDeviceContext::nb_tx_queues
int nb_tx_queues
Definition: hwcontext_vulkan.h:116
vk_dev_type
static const char * vk_dev_type(enum VkPhysicalDeviceType type)
Definition: hwcontext_vulkan.c:830
FF_VK_EXT_DEVICE_DRM
@ FF_VK_EXT_DEVICE_DRM
Definition: vulkan_functions.h:41
FF_VK_EXT_ATOMIC_FLOAT
@ FF_VK_EXT_ATOMIC_FLOAT
Definition: vulkan_functions.h:47
VulkanDevicePriv::disable_multiplane
int disable_multiplane
Definition: hwcontext_vulkan.c:120
imgutils.h
ff_vk_exec_submit
int ff_vk_exec_submit(FFVulkanContext *s, FFVkExecContext *e)
Definition: vulkan.c:721
AV_PIX_FMT_XV36
#define AV_PIX_FMT_XV36
Definition: pixfmt.h:521
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:467
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:385
VulkanQueueCtx::queue
VkQueue queue
Definition: hwcontext_vulkan.c:72
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
FFVkFormatEntry::vk_planes
int vk_planes
Definition: hwcontext_vulkan.c:163
HWContextType
Definition: hwcontext_internal.h:29
AV_PIX_FMT_P412
#define AV_PIX_FMT_P412
Definition: pixfmt.h:528
VulkanDevicePriv::contiguous_planes
int contiguous_planes
Definition: hwcontext_vulkan.c:117
FN_MAP_TO
#define FN_MAP_TO(dst_t, dst_name, src_t, src_name)
Definition: hwcontext_vulkan.c:250
AVVAAPIDeviceContext
VAAPI connection details.
Definition: hwcontext_vaapi.h:68
h
h
Definition: vp9dsp_template.c:2038
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:78
AVDictionaryEntry::value
char * value
Definition: dict.h:91
avstring.h
AVDRMDeviceContext
DRM device.
Definition: hwcontext_drm.h:157
ADD_VAL_TO_LIST
#define ADD_VAL_TO_LIST(list, count, val)
Definition: hwcontext_vulkan.c:453
AVDRMFrameDescriptor::nb_objects
int nb_objects
Number of DRM objects making up this frame.
Definition: hwcontext_drm.h:137
AVVulkanDeviceContext::queue_family_encode_index
int queue_family_encode_index
Queue family index for video encode ops, and the amount of queues enabled.
Definition: hwcontext_vulkan.h:130
HWMapDescriptor
Definition: hwcontext_internal.h:132
FFVulkanFunctions
Definition: vulkan_functions.h:226
VulkanFramesPriv::modifier_info
VkImageDrmFormatModifierListCreateInfoEXT * modifier_info
Definition: hwcontext_vulkan.c:135
FFVkFormatEntry::aspect
VkImageAspectFlags aspect
Definition: hwcontext_vulkan.c:162
VulkanDeviceSelection::name
const char * name
Definition: hwcontext_vulkan.c:824
ff_vk_map_buffers
int ff_vk_map_buffers(FFVulkanContext *s, FFVkBuffer **buf, uint8_t *mem[], int nb_buffers, int invalidate)
Buffer management code.
Definition: vulkan.c:965
AV_HWDEVICE_TYPE_DRM
@ AV_HWDEVICE_TYPE_DRM
Definition: hwcontext.h:36
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:1187
w32dlfcn.h
VulkanDevicePriv::coop_matrix_features
VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_matrix_features
Definition: hwcontext_vulkan.c:102
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:2856
pthread_mutex_lock
#define pthread_mutex_lock(a)
Definition: ffprobe.c:75