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