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