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