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