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