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