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 SETUP_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 
1325  /*
1326  * VkPhysicalDeviceVulkan12Features has a timelineSemaphore field, but
1327  * MoltenVK doesn't implement VkPhysicalDeviceVulkan12Features yet, so we
1328  * use VkPhysicalDeviceTimelineSemaphoreFeatures directly.
1329  */
1330  VkPhysicalDeviceTimelineSemaphoreFeatures timeline_features = {
1331  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
1332  };
1333  VkPhysicalDeviceVulkan12Features dev_features_1_2 = {
1334  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
1335  .pNext = &timeline_features,
1336  };
1337  VkPhysicalDeviceVulkan11Features dev_features_1_1 = {
1338  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
1339  .pNext = &dev_features_1_2,
1340  };
1341  VkPhysicalDeviceFeatures2 dev_features = {
1342  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1343  .pNext = &dev_features_1_1,
1344  };
1345 
1346  VkDeviceCreateInfo dev_info = {
1347  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1348  .pNext = &hwctx->device_features,
1349  };
1350 
1351  hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
1352  hwctx->device_features.pNext = &p->device_features_1_1;
1353  p->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
1355  p->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
1356  ctx->free = vulkan_device_free;
1357 
1358  /* Create an instance if not given one */
1359  if ((err = create_instance(ctx, opts)))
1360  goto end;
1361 
1362  /* Find a device (if not given one) */
1363  if ((err = find_device(ctx, dev_select)))
1364  goto end;
1365 
1366  vk->GetPhysicalDeviceFeatures2(hwctx->phys_dev, &dev_features);
1367 
1368  /* Try to keep in sync with libplacebo */
1369 #define COPY_FEATURE(DST, NAME) (DST).features.NAME = dev_features.features.NAME;
1370  COPY_FEATURE(hwctx->device_features, shaderImageGatherExtended)
1371  COPY_FEATURE(hwctx->device_features, shaderStorageImageReadWithoutFormat)
1372  COPY_FEATURE(hwctx->device_features, shaderStorageImageWriteWithoutFormat)
1373  COPY_FEATURE(hwctx->device_features, fragmentStoresAndAtomics)
1374  COPY_FEATURE(hwctx->device_features, vertexPipelineStoresAndAtomics)
1375  COPY_FEATURE(hwctx->device_features, shaderInt64)
1376 #undef COPY_FEATURE
1377 
1378  /* We require timeline semaphores */
1379  if (!timeline_features.timelineSemaphore) {
1380  av_log(ctx, AV_LOG_ERROR, "Device does not support timeline semaphores!\n");
1381  err = AVERROR(ENOSYS);
1382  goto end;
1383  }
1384  p->device_features_1_2.timelineSemaphore = 1;
1385 
1386  /* Setup queue family */
1387  if ((err = setup_queue_families(ctx, &dev_info)))
1388  goto end;
1389 
1390  if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
1391  &dev_info.enabledExtensionCount, 0))) {
1392  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1393  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1394  av_free((void *)dev_info.pQueueCreateInfos);
1395  goto end;
1396  }
1397 
1398  ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
1399  &hwctx->act_dev);
1400 
1401  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1402  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1403  av_free((void *)dev_info.pQueueCreateInfos);
1404 
1405  if (ret != VK_SUCCESS) {
1406  av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n",
1407  vk_ret2str(ret));
1408  for (int i = 0; i < dev_info.enabledExtensionCount; i++)
1409  av_free((void *)dev_info.ppEnabledExtensionNames[i]);
1410  av_free((void *)dev_info.ppEnabledExtensionNames);
1411  err = AVERROR_EXTERNAL;
1412  goto end;
1413  }
1414 
1415  /* Tiled images setting, use them by default */
1416  opt_d = av_dict_get(opts, "linear_images", NULL, 0);
1417  if (opt_d)
1418  p->use_linear_images = strtol(opt_d->value, NULL, 10);
1419 
1420  opt_d = av_dict_get(opts, "contiguous_planes", NULL, 0);
1421  if (opt_d)
1422  p->contiguous_planes = strtol(opt_d->value, NULL, 10);
1423  else
1424  p->contiguous_planes = -1;
1425 
1426  hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames;
1427  hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount;
1428 
1429 end:
1430  return err;
1431 }
1432 
1434 {
1435  int err;
1436  uint32_t queue_num;
1437  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1438  VulkanDevicePriv *p = ctx->internal->priv;
1439  FFVulkanFunctions *vk = &p->vkfn;
1440  int graph_index, comp_index, tx_index, enc_index, dec_index;
1441 
1442  /* Set device extension flags */
1443  for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) {
1444  for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) {
1445  if (!strcmp(hwctx->enabled_dev_extensions[i],
1446  optional_device_exts[j].name)) {
1448  break;
1449  }
1450  }
1451  }
1452 
1453  err = ff_vk_load_functions(ctx, vk, p->extensions, 1, 1);
1454  if (err < 0) {
1455  av_log(ctx, AV_LOG_ERROR, "Unable to load functions!\n");
1456  return err;
1457  }
1458 
1459  p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1460  p->props.pNext = &p->hprops;
1461  p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
1462 
1463  vk->GetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props);
1464  av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n",
1465  p->props.properties.deviceName);
1466  av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n");
1467  av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %"PRIu64"\n",
1468  p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
1469  av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %"SIZE_SPECIFIER"\n",
1470  p->props.properties.limits.minMemoryMapAlignment);
1472  av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %"PRIu64"\n",
1473  p->hprops.minImportedHostPointerAlignment);
1474 
1475  p->dev_is_nvidia = (p->props.properties.vendorID == 0x10de);
1476  p->dev_is_intel = (p->props.properties.vendorID == 0x8086);
1477 
1478  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &queue_num, NULL);
1479  if (!queue_num) {
1480  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1481  return AVERROR_EXTERNAL;
1482  }
1483 
1484  graph_index = hwctx->queue_family_index;
1485  comp_index = hwctx->queue_family_comp_index;
1486  tx_index = hwctx->queue_family_tx_index;
1487  enc_index = hwctx->queue_family_encode_index;
1488  dec_index = hwctx->queue_family_decode_index;
1489 
1490 #define CHECK_QUEUE(type, required, fidx, ctx_qf, qc) \
1491  do { \
1492  if (ctx_qf < 0 && required) { \
1493  av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \
1494  " in the context!\n", type); \
1495  return AVERROR(EINVAL); \
1496  } else if (fidx < 0 || ctx_qf < 0) { \
1497  break; \
1498  } else if (ctx_qf >= queue_num) { \
1499  av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \
1500  type, ctx_qf, queue_num); \
1501  return AVERROR(EINVAL); \
1502  } \
1503  \
1504  av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \
1505  " for%s%s%s%s%s\n", \
1506  ctx_qf, qc, \
1507  ctx_qf == graph_index ? " graphics" : "", \
1508  ctx_qf == comp_index ? " compute" : "", \
1509  ctx_qf == tx_index ? " transfers" : "", \
1510  ctx_qf == enc_index ? " encode" : "", \
1511  ctx_qf == dec_index ? " decode" : ""); \
1512  graph_index = (ctx_qf == graph_index) ? -1 : graph_index; \
1513  comp_index = (ctx_qf == comp_index) ? -1 : comp_index; \
1514  tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \
1515  enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \
1516  dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \
1517  p->qfs[p->num_qfs++] = ctx_qf; \
1518  } while (0)
1519 
1520  CHECK_QUEUE("graphics", 0, graph_index, hwctx->queue_family_index, hwctx->nb_graphics_queues);
1521  CHECK_QUEUE("upload", 1, tx_index, hwctx->queue_family_tx_index, hwctx->nb_tx_queues);
1522  CHECK_QUEUE("compute", 1, comp_index, hwctx->queue_family_comp_index, hwctx->nb_comp_queues);
1523  CHECK_QUEUE("encode", 0, enc_index, hwctx->queue_family_encode_index, hwctx->nb_encode_queues);
1524  CHECK_QUEUE("decode", 0, dec_index, hwctx->queue_family_decode_index, hwctx->nb_decode_queues);
1525 
1526 #undef CHECK_QUEUE
1527 
1528  /* Get device capabilities */
1529  vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
1530 
1531  return 0;
1532 }
1533 
1534 static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device,
1535  AVDictionary *opts, int flags)
1536 {
1537  VulkanDeviceSelection dev_select = { 0 };
1538  if (device && device[0]) {
1539  char *end = NULL;
1540  dev_select.index = strtol(device, &end, 10);
1541  if (end == device) {
1542  dev_select.index = 0;
1543  dev_select.name = device;
1544  }
1545  }
1546 
1547  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1548 }
1549 
1551  AVHWDeviceContext *src_ctx,
1552  AVDictionary *opts, int flags)
1553 {
1554  av_unused VulkanDeviceSelection dev_select = { 0 };
1555 
1556  /* If there's only one device on the system, then even if its not covered
1557  * by the following checks (e.g. non-PCIe ARM GPU), having an empty
1558  * dev_select will mean it'll get picked. */
1559  switch(src_ctx->type) {
1560 #if CONFIG_LIBDRM
1561 #if CONFIG_VAAPI
1562  case AV_HWDEVICE_TYPE_VAAPI: {
1563  AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
1564 
1565  const char *vendor = vaQueryVendorString(src_hwctx->display);
1566  if (!vendor) {
1567  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n");
1568  return AVERROR_EXTERNAL;
1569  }
1570 
1571  if (strstr(vendor, "Intel"))
1572  dev_select.vendor_id = 0x8086;
1573  if (strstr(vendor, "AMD"))
1574  dev_select.vendor_id = 0x1002;
1575 
1576  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1577  }
1578 #endif
1579  case AV_HWDEVICE_TYPE_DRM: {
1580  AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1581 
1582  drmDevice *drm_dev_info;
1583  int err = drmGetDevice(src_hwctx->fd, &drm_dev_info);
1584  if (err) {
1585  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd!\n");
1586  return AVERROR_EXTERNAL;
1587  }
1588 
1589  if (drm_dev_info->bustype == DRM_BUS_PCI)
1590  dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id;
1591 
1592  drmFreeDevice(&drm_dev_info);
1593 
1594  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1595  }
1596 #endif
1597 #if CONFIG_CUDA
1598  case AV_HWDEVICE_TYPE_CUDA: {
1599  AVHWDeviceContext *cuda_cu = src_ctx;
1600  AVCUDADeviceContext *src_hwctx = src_ctx->hwctx;
1601  AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal;
1602  CudaFunctions *cu = cu_internal->cuda_dl;
1603 
1604  int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid,
1605  cu_internal->cuda_device));
1606  if (ret < 0) {
1607  av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n");
1608  return AVERROR_EXTERNAL;
1609  }
1610 
1611  dev_select.has_uuid = 1;
1612 
1613  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1614  }
1615 #endif
1616  default:
1617  return AVERROR(ENOSYS);
1618  }
1619 }
1620 
1622  const void *hwconfig,
1623  AVHWFramesConstraints *constraints)
1624 {
1625  int count = 0;
1626  VulkanDevicePriv *p = ctx->internal->priv;
1627 
1628  for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++)
1629  count += pixfmt_is_supported(ctx, i, p->use_linear_images);
1630 
1631 #if CONFIG_CUDA
1632  if (p->dev_is_nvidia)
1633  count++;
1634 #endif
1635 
1636  constraints->valid_sw_formats = av_malloc_array(count + 1,
1637  sizeof(enum AVPixelFormat));
1638  if (!constraints->valid_sw_formats)
1639  return AVERROR(ENOMEM);
1640 
1641  count = 0;
1642  for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++)
1644  constraints->valid_sw_formats[count++] = i;
1645 
1646 #if CONFIG_CUDA
1647  if (p->dev_is_nvidia)
1648  constraints->valid_sw_formats[count++] = AV_PIX_FMT_CUDA;
1649 #endif
1650  constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE;
1651 
1652  constraints->min_width = 0;
1653  constraints->min_height = 0;
1654  constraints->max_width = p->props.properties.limits.maxImageDimension2D;
1655  constraints->max_height = p->props.properties.limits.maxImageDimension2D;
1656 
1657  constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat));
1658  if (!constraints->valid_hw_formats)
1659  return AVERROR(ENOMEM);
1660 
1661  constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN;
1662  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1663 
1664  return 0;
1665 }
1666 
1667 static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
1668  VkMemoryPropertyFlagBits req_flags, const void *alloc_extension,
1669  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
1670 {
1671  VkResult ret;
1672  int index = -1;
1673  VulkanDevicePriv *p = ctx->internal->priv;
1674  FFVulkanFunctions *vk = &p->vkfn;
1675  AVVulkanDeviceContext *dev_hwctx = ctx->hwctx;
1676  VkMemoryAllocateInfo alloc_info = {
1677  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1678  .pNext = alloc_extension,
1679  .allocationSize = req->size,
1680  };
1681 
1682  /* The vulkan spec requires memory types to be sorted in the "optimal"
1683  * order, so the first matching type we find will be the best/fastest one */
1684  for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
1685  const VkMemoryType *type = &p->mprops.memoryTypes[i];
1686 
1687  /* The memory type must be supported by the requirements (bitfield) */
1688  if (!(req->memoryTypeBits & (1 << i)))
1689  continue;
1690 
1691  /* The memory type flags must include our properties */
1692  if ((type->propertyFlags & req_flags) != req_flags)
1693  continue;
1694 
1695  /* The memory type must be large enough */
1696  if (req->size > p->mprops.memoryHeaps[type->heapIndex].size)
1697  continue;
1698 
1699  /* Found a suitable memory type */
1700  index = i;
1701  break;
1702  }
1703 
1704  if (index < 0) {
1705  av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
1706  req_flags);
1707  return AVERROR(EINVAL);
1708  }
1709 
1710  alloc_info.memoryTypeIndex = index;
1711 
1712  ret = vk->AllocateMemory(dev_hwctx->act_dev, &alloc_info,
1713  dev_hwctx->alloc, mem);
1714  if (ret != VK_SUCCESS) {
1715  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
1716  vk_ret2str(ret));
1717  return AVERROR(ENOMEM);
1718  }
1719 
1720  *mem_flags |= p->mprops.memoryTypes[index].propertyFlags;
1721 
1722  return 0;
1723 }
1724 
1726 {
1727  AVVkFrameInternal *internal = f->internal;
1728 
1729  if (!internal)
1730  return;
1731 
1732 #if CONFIG_CUDA
1733  if (internal->cuda_fc_ref) {
1734  AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
1735  int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
1736  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
1737  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
1738  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
1739  CudaFunctions *cu = cu_internal->cuda_dl;
1740 
1741  for (int i = 0; i < planes; i++) {
1742  if (internal->cu_sem[i])
1743  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
1744  if (internal->cu_mma[i])
1745  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
1746  if (internal->ext_mem[i])
1747  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
1748 #ifdef _WIN32
1749  if (internal->ext_sem_handle[i])
1750  CloseHandle(internal->ext_sem_handle[i]);
1751  if (internal->ext_mem_handle[i])
1752  CloseHandle(internal->ext_mem_handle[i]);
1753 #endif
1754  }
1755 
1756  av_buffer_unref(&internal->cuda_fc_ref);
1757  }
1758 #endif
1759 
1760  av_freep(&f->internal);
1761 }
1762 
1763 static void vulkan_frame_free(void *opaque, uint8_t *data)
1764 {
1765  AVVkFrame *f = (AVVkFrame *)data;
1766  AVHWFramesContext *hwfc = opaque;
1767  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1769  FFVulkanFunctions *vk = &p->vkfn;
1771 
1772  /* We could use vkWaitSemaphores, but the validation layer seems to have
1773  * issues tracking command buffer execution state on uninit. */
1774  vk->DeviceWaitIdle(hwctx->act_dev);
1775 
1777 
1778  for (int i = 0; i < planes; i++) {
1779  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
1780  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
1781  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
1782  }
1783 
1784  av_free(f);
1785 }
1786 
1788  void *alloc_pnext, size_t alloc_pnext_stride)
1789 {
1790  int err;
1791  VkResult ret;
1792  AVHWDeviceContext *ctx = hwfc->device_ctx;
1793  VulkanDevicePriv *p = ctx->internal->priv;
1794  FFVulkanFunctions *vk = &p->vkfn;
1795  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
1796  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1797  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
1798 
1799  VkMemoryRequirements cont_memory_requirements = { 0 };
1800  int cont_mem_size_list[AV_NUM_DATA_POINTERS] = { 0 };
1801  int cont_mem_size = 0;
1802 
1803  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1804 
1805  for (int i = 0; i < planes; i++) {
1806  int use_ded_mem;
1807  VkImageMemoryRequirementsInfo2 req_desc = {
1808  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
1809  .image = f->img[i],
1810  };
1811  VkMemoryDedicatedAllocateInfo ded_alloc = {
1812  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1813  .pNext = (void *)(((uint8_t *)alloc_pnext) + i*alloc_pnext_stride),
1814  };
1815  VkMemoryDedicatedRequirements ded_req = {
1816  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
1817  };
1818  VkMemoryRequirements2 req = {
1819  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
1820  .pNext = &ded_req,
1821  };
1822 
1823  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
1824 
1825  if (f->tiling == VK_IMAGE_TILING_LINEAR)
1826  req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
1827  p->props.properties.limits.minMemoryMapAlignment);
1828 
1829  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) {
1830  if (ded_req.requiresDedicatedAllocation) {
1831  av_log(hwfc, AV_LOG_ERROR, "Cannot allocate all planes in a single allocation, "
1832  "device requires dedicated image allocation!\n");
1833  return AVERROR(EINVAL);
1834  } else if (!i) {
1835  cont_memory_requirements = req.memoryRequirements;
1836  } else if (cont_memory_requirements.memoryTypeBits !=
1837  req.memoryRequirements.memoryTypeBits) {
1838  av_log(hwfc, AV_LOG_ERROR, "The memory requirements differ between plane 0 "
1839  "and %i, cannot allocate in a single region!\n",
1840  i);
1841  return AVERROR(EINVAL);
1842  }
1843 
1844  cont_mem_size_list[i] = FFALIGN(req.memoryRequirements.size,
1845  req.memoryRequirements.alignment);
1846  cont_mem_size += cont_mem_size_list[i];
1847  continue;
1848  }
1849 
1850  /* In case the implementation prefers/requires dedicated allocation */
1851  use_ded_mem = ded_req.prefersDedicatedAllocation |
1852  ded_req.requiresDedicatedAllocation;
1853  if (use_ded_mem)
1854  ded_alloc.image = f->img[i];
1855 
1856  /* Allocate memory */
1857  if ((err = alloc_mem(ctx, &req.memoryRequirements,
1858  f->tiling == VK_IMAGE_TILING_LINEAR ?
1859  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1860  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1861  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
1862  &f->flags, &f->mem[i])))
1863  return err;
1864 
1865  f->size[i] = req.memoryRequirements.size;
1866  bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1867  bind_info[i].image = f->img[i];
1868  bind_info[i].memory = f->mem[i];
1869  }
1870 
1871  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) {
1872  cont_memory_requirements.size = cont_mem_size;
1873 
1874  /* Allocate memory */
1875  if ((err = alloc_mem(ctx, &cont_memory_requirements,
1876  f->tiling == VK_IMAGE_TILING_LINEAR ?
1877  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1878  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1879  (void *)(((uint8_t *)alloc_pnext)),
1880  &f->flags, &f->mem[0])))
1881  return err;
1882 
1883  f->size[0] = cont_memory_requirements.size;
1884 
1885  for (int i = 0, offset = 0; i < planes; i++) {
1886  bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1887  bind_info[i].image = f->img[i];
1888  bind_info[i].memory = f->mem[0];
1889  bind_info[i].memoryOffset = offset;
1890 
1891  f->offset[i] = bind_info[i].memoryOffset;
1892  offset += cont_mem_size_list[i];
1893  }
1894  }
1895 
1896  /* Bind the allocated memory to the images */
1897  ret = vk->BindImageMemory2(hwctx->act_dev, planes, bind_info);
1898  if (ret != VK_SUCCESS) {
1899  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
1900  vk_ret2str(ret));
1901  return AVERROR_EXTERNAL;
1902  }
1903 
1904  return 0;
1905 }
1906 
1907 enum PrepMode {
1911 };
1912 
1914  AVVkFrame *frame, enum PrepMode pmode)
1915 {
1916  int err;
1917  uint32_t src_qf, dst_qf;
1918  VkImageLayout new_layout;
1919  VkAccessFlags new_access;
1920  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1922  FFVulkanFunctions *vk = &p->vkfn;
1923  uint64_t sem_sig_val[AV_NUM_DATA_POINTERS];
1924 
1925  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
1926 
1927  VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = {
1928  .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
1929  .pSignalSemaphoreValues = sem_sig_val,
1930  .signalSemaphoreValueCount = planes,
1931  };
1932 
1933  VkSubmitInfo s_info = {
1934  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1935  .pNext = &s_timeline_sem_info,
1936  .pSignalSemaphores = frame->sem,
1937  .signalSemaphoreCount = planes,
1938  };
1939 
1940  VkPipelineStageFlagBits wait_st[AV_NUM_DATA_POINTERS];
1941  for (int i = 0; i < planes; i++) {
1942  wait_st[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1943  sem_sig_val[i] = frame->sem_value[i] + 1;
1944  }
1945 
1946  switch (pmode) {
1947  case PREP_MODE_WRITE:
1948  new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1949  new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
1950  src_qf = VK_QUEUE_FAMILY_IGNORED;
1951  dst_qf = VK_QUEUE_FAMILY_IGNORED;
1952  break;
1954  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1955  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1956  src_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
1957  dst_qf = VK_QUEUE_FAMILY_IGNORED;
1958  s_timeline_sem_info.pWaitSemaphoreValues = frame->sem_value;
1959  s_timeline_sem_info.waitSemaphoreValueCount = planes;
1960  s_info.pWaitSemaphores = frame->sem;
1961  s_info.pWaitDstStageMask = wait_st;
1962  s_info.waitSemaphoreCount = planes;
1963  break;
1965  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1966  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1967  src_qf = VK_QUEUE_FAMILY_IGNORED;
1968  dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
1969  s_timeline_sem_info.pWaitSemaphoreValues = frame->sem_value;
1970  s_timeline_sem_info.waitSemaphoreValueCount = planes;
1971  s_info.pWaitSemaphores = frame->sem;
1972  s_info.pWaitDstStageMask = wait_st;
1973  s_info.waitSemaphoreCount = planes;
1974  break;
1975  }
1976 
1977  if ((err = wait_start_exec_ctx(hwfc, ectx)))
1978  return err;
1979 
1980  /* Change the image layout to something more optimal for writes.
1981  * This also signals the newly created semaphore, making it usable
1982  * for synchronization */
1983  for (int i = 0; i < planes; i++) {
1984  img_bar[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1985  img_bar[i].srcAccessMask = 0x0;
1986  img_bar[i].dstAccessMask = new_access;
1987  img_bar[i].oldLayout = frame->layout[i];
1988  img_bar[i].newLayout = new_layout;
1989  img_bar[i].srcQueueFamilyIndex = src_qf;
1990  img_bar[i].dstQueueFamilyIndex = dst_qf;
1991  img_bar[i].image = frame->img[i];
1992  img_bar[i].subresourceRange.levelCount = 1;
1993  img_bar[i].subresourceRange.layerCount = 1;
1994  img_bar[i].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1995 
1996  frame->layout[i] = img_bar[i].newLayout;
1997  frame->access[i] = img_bar[i].dstAccessMask;
1998  }
1999 
2000  vk->CmdPipelineBarrier(get_buf_exec_ctx(hwfc, ectx),
2001  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2002  VK_PIPELINE_STAGE_TRANSFER_BIT,
2003  0, 0, NULL, 0, NULL, planes, img_bar);
2004 
2005  return submit_exec_ctx(hwfc, ectx, &s_info, frame, 0);
2006 }
2007 
2008 static inline void get_plane_wh(int *w, int *h, enum AVPixelFormat format,
2009  int frame_w, int frame_h, int plane)
2010 {
2012 
2013  /* Currently always true unless gray + alpha support is added */
2014  if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB ||
2015  !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
2016  *w = frame_w;
2017  *h = frame_h;
2018  return;
2019  }
2020 
2021  *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w);
2022  *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h);
2023 }
2024 
2026  VkImageTiling tiling, VkImageUsageFlagBits usage,
2027  void *create_pnext)
2028 {
2029  int err;
2030  VkResult ret;
2031  AVHWDeviceContext *ctx = hwfc->device_ctx;
2032  VulkanDevicePriv *p = ctx->internal->priv;
2033  FFVulkanFunctions *vk = &p->vkfn;
2034  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2035  enum AVPixelFormat format = hwfc->sw_format;
2036  const VkFormat *img_fmts = av_vkfmt_from_pixfmt(format);
2037  const int planes = av_pix_fmt_count_planes(format);
2038 
2039  VkExportSemaphoreCreateInfo ext_sem_info = {
2040  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
2041 #ifdef _WIN32
2042  .handleTypes = IsWindows8OrGreater()
2043  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2044  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2045 #else
2046  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2047 #endif
2048  };
2049 
2050  VkSemaphoreTypeCreateInfo sem_type_info = {
2051  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2052 #ifdef _WIN32
2053  .pNext = p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM ? &ext_sem_info : NULL,
2054 #else
2055  .pNext = p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL,
2056 #endif
2057  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2058  .initialValue = 0,
2059  };
2060 
2061  VkSemaphoreCreateInfo sem_spawn = {
2062  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2063  .pNext = &sem_type_info,
2064  };
2065 
2067  if (!f) {
2068  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2069  return AVERROR(ENOMEM);
2070  }
2071 
2072  /* Create the images */
2073  for (int i = 0; i < planes; i++) {
2074  VkImageCreateInfo create_info = {
2075  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2076  .pNext = create_pnext,
2077  .imageType = VK_IMAGE_TYPE_2D,
2078  .format = img_fmts[i],
2079  .extent.depth = 1,
2080  .mipLevels = 1,
2081  .arrayLayers = 1,
2082  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2083  .tiling = tiling,
2084  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2085  .usage = usage,
2086  .samples = VK_SAMPLE_COUNT_1_BIT,
2087  .pQueueFamilyIndices = p->qfs,
2088  .queueFamilyIndexCount = p->num_qfs,
2089  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2090  VK_SHARING_MODE_EXCLUSIVE,
2091  };
2092 
2093  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2094  format, hwfc->width, hwfc->height, i);
2095 
2096  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2097  hwctx->alloc, &f->img[i]);
2098  if (ret != VK_SUCCESS) {
2099  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2100  vk_ret2str(ret));
2101  err = AVERROR(EINVAL);
2102  goto fail;
2103  }
2104 
2105  /* Create semaphore */
2106  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2107  hwctx->alloc, &f->sem[i]);
2108  if (ret != VK_SUCCESS) {
2109  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2110  vk_ret2str(ret));
2111  return AVERROR_EXTERNAL;
2112  }
2113 
2114  f->layout[i] = create_info.initialLayout;
2115  f->access[i] = 0x0;
2116  f->sem_value[i] = 0;
2117  }
2118 
2119  f->flags = 0x0;
2120  f->tiling = tiling;
2121 
2122  *frame = f;
2123  return 0;
2124 
2125 fail:
2126  vulkan_frame_free(hwfc, (uint8_t *)f);
2127  return err;
2128 }
2129 
2130 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2132  VkExternalMemoryHandleTypeFlags *comp_handle_types,
2133  VkExternalMemoryHandleTypeFlagBits *iexp,
2134  VkExternalMemoryHandleTypeFlagBits exp)
2135 {
2136  VkResult ret;
2137  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2138  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
2140  FFVulkanFunctions *vk = &p->vkfn;
2141 
2142  const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
2144  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2145  int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
2146  int nb_mods;
2147 
2148  VkExternalImageFormatProperties eprops = {
2149  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2150  };
2151  VkImageFormatProperties2 props = {
2152  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2153  .pNext = &eprops,
2154  };
2155  VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
2156  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2157  .pNext = NULL,
2158  .pQueueFamilyIndices = p->qfs,
2159  .queueFamilyIndexCount = p->num_qfs,
2160  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2161  VK_SHARING_MODE_EXCLUSIVE,
2162  };
2163  VkPhysicalDeviceExternalImageFormatInfo enext = {
2164  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2165  .handleType = exp,
2166  .pNext = has_mods ? &phy_dev_mod_info : NULL,
2167  };
2168  VkPhysicalDeviceImageFormatInfo2 pinfo = {
2169  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2170  .pNext = !exp ? NULL : &enext,
2171  .format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0],
2172  .type = VK_IMAGE_TYPE_2D,
2173  .tiling = hwctx->tiling,
2174  .usage = hwctx->usage,
2175  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2176  };
2177 
2178  nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
2179  for (int i = 0; i < nb_mods; i++) {
2180  if (has_mods)
2181  phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
2182 
2183  ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
2184  &pinfo, &props);
2185 
2186  if (ret == VK_SUCCESS) {
2187  *iexp |= exp;
2188  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2189  }
2190  }
2191 }
2192 
2193 static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2194 {
2195  int err;
2196  AVVkFrame *f;
2197  AVBufferRef *avbuf = NULL;
2198  AVHWFramesContext *hwfc = opaque;
2199  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2201  VulkanFramesPriv *fp = hwfc->internal->priv;
2202  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2203  VkExternalMemoryHandleTypeFlags e = 0x0;
2204 
2205  VkExternalMemoryImageCreateInfo eiinfo = {
2206  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2207  .pNext = hwctx->create_pnext,
2208  };
2209 
2210 #ifdef _WIN32
2211  if (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2212  try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2213  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2214  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2215 #else
2217  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2218  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2219 
2221  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2222  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2223 #endif
2224 
2225  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2226  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2227  eminfo[i].pNext = hwctx->alloc_pnext[i];
2228  eminfo[i].handleTypes = e;
2229  }
2230 
2231  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
2232  eiinfo.handleTypes ? &eiinfo : NULL);
2233  if (err)
2234  return NULL;
2235 
2236  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2237  if (err)
2238  goto fail;
2239 
2240  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_WRITE);
2241  if (err)
2242  goto fail;
2243 
2244  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2245  vulkan_frame_free, hwfc, 0);
2246  if (!avbuf)
2247  goto fail;
2248 
2249  return avbuf;
2250 
2251 fail:
2252  vulkan_frame_free(hwfc, (uint8_t *)f);
2253  return NULL;
2254 }
2255 
2257 {
2258  VulkanFramesPriv *fp = hwfc->internal->priv;
2259 
2260  if (fp->modifier_info) {
2261  if (fp->modifier_info->pDrmFormatModifiers)
2262  av_freep(&fp->modifier_info->pDrmFormatModifiers);
2263  av_freep(&fp->modifier_info);
2264  }
2265 
2266  free_exec_ctx(hwfc, &fp->conv_ctx);
2267  free_exec_ctx(hwfc, &fp->upload_ctx);
2268  free_exec_ctx(hwfc, &fp->download_ctx);
2269 }
2270 
2272 {
2273  int err;
2274  AVVkFrame *f;
2275  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2276  VulkanFramesPriv *fp = hwfc->internal->priv;
2277  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
2279  const VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
2280  const int has_modifiers = !!(p->extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS);
2281 
2282  /* Default tiling flags */
2283  hwctx->tiling = hwctx->tiling ? hwctx->tiling :
2284  has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
2285  p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
2286  VK_IMAGE_TILING_OPTIMAL;
2287 
2288  if (!hwctx->usage)
2290 
2291  if (!(hwctx->flags & AV_VK_FRAME_FLAG_NONE)) {
2292  if (p->contiguous_planes == 1 ||
2293  ((p->contiguous_planes == -1) && p->dev_is_intel))
2295  }
2296 
2297  modifier_info = vk_find_struct(hwctx->create_pnext,
2298  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2299 
2300  /* Get the supported modifiers if the user has not given any. */
2301  if (has_modifiers && !modifier_info) {
2302  const VkFormat *fmt = av_vkfmt_from_pixfmt(hwfc->sw_format);
2303  VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
2304  FFVulkanFunctions *vk = &p->vkfn;
2305  VkDrmFormatModifierPropertiesEXT *mod_props;
2306  uint64_t *modifiers;
2307  int modifier_count = 0;
2308 
2309  VkDrmFormatModifierPropertiesListEXT mod_props_list = {
2310  .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
2311  .pNext = NULL,
2312  .drmFormatModifierCount = 0,
2313  .pDrmFormatModifierProperties = NULL,
2314  };
2315  VkFormatProperties2 prop = {
2316  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
2317  .pNext = &mod_props_list,
2318  };
2319 
2320  /* Get all supported modifiers */
2321  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
2322 
2323  if (!mod_props_list.drmFormatModifierCount) {
2324  av_log(hwfc, AV_LOG_ERROR, "There are no supported modifiers for the given sw_format\n");
2325  return AVERROR(EINVAL);
2326  }
2327 
2328  /* Createa structure to hold the modifier list info */
2329  modifier_info = av_mallocz(sizeof(*modifier_info));
2330  if (!modifier_info)
2331  return AVERROR(ENOMEM);
2332 
2333  modifier_info->pNext = NULL;
2334  modifier_info->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;
2335 
2336  /* Add structure to the image creation pNext chain */
2337  if (!hwctx->create_pnext)
2338  hwctx->create_pnext = modifier_info;
2339  else
2340  vk_link_struct(hwctx->create_pnext, (void *)modifier_info);
2341 
2342  /* Backup the allocated struct to be freed later */
2343  fp->modifier_info = modifier_info;
2344 
2345  /* Allocate list of modifiers */
2346  modifiers = av_mallocz(mod_props_list.drmFormatModifierCount *
2347  sizeof(*modifiers));
2348  if (!modifiers)
2349  return AVERROR(ENOMEM);
2350 
2351  modifier_info->pDrmFormatModifiers = modifiers;
2352 
2353  /* Allocate a temporary list to hold all modifiers supported */
2354  mod_props = av_mallocz(mod_props_list.drmFormatModifierCount *
2355  sizeof(*mod_props));
2356  if (!mod_props)
2357  return AVERROR(ENOMEM);
2358 
2359  mod_props_list.pDrmFormatModifierProperties = mod_props;
2360 
2361  /* Finally get all modifiers from the device */
2362  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
2363 
2364  /* Reject any modifiers that don't match our requirements */
2365  for (int i = 0; i < mod_props_list.drmFormatModifierCount; i++) {
2366  if (!(mod_props[i].drmFormatModifierTilingFeatures & hwctx->usage))
2367  continue;
2368 
2369  modifiers[modifier_count++] = mod_props[i].drmFormatModifier;
2370  }
2371 
2372  if (!modifier_count) {
2373  av_log(hwfc, AV_LOG_ERROR, "None of the given modifiers supports"
2374  " the usage flags!\n");
2375  av_freep(&mod_props);
2376  return AVERROR(EINVAL);
2377  }
2378 
2379  modifier_info->drmFormatModifierCount = modifier_count;
2380  av_freep(&mod_props);
2381  }
2382 
2383  err = create_exec_ctx(hwfc, &fp->conv_ctx,
2384  dev_hwctx->queue_family_comp_index,
2385  dev_hwctx->nb_comp_queues);
2386  if (err)
2387  return err;
2388 
2389  err = create_exec_ctx(hwfc, &fp->upload_ctx,
2390  dev_hwctx->queue_family_tx_index,
2391  dev_hwctx->nb_tx_queues);
2392  if (err)
2393  return err;
2394 
2395  err = create_exec_ctx(hwfc, &fp->download_ctx,
2396  dev_hwctx->queue_family_tx_index, 1);
2397  if (err)
2398  return err;
2399 
2400  /* Test to see if allocation will fail */
2401  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
2402  hwctx->create_pnext);
2403  if (err)
2404  return err;
2405 
2406  vulkan_frame_free(hwfc, (uint8_t *)f);
2407 
2408  /* If user did not specify a pool, hwfc->pool will be set to the internal one
2409  * in hwcontext.c just after this gets called */
2410  if (!hwfc->pool) {
2412  hwfc, vulkan_pool_alloc,
2413  NULL);
2414  if (!hwfc->internal->pool_internal)
2415  return AVERROR(ENOMEM);
2416  }
2417 
2418  return 0;
2419 }
2420 
2422 {
2423  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
2424  if (!frame->buf[0])
2425  return AVERROR(ENOMEM);
2426 
2427  frame->data[0] = frame->buf[0]->data;
2428  frame->format = AV_PIX_FMT_VULKAN;
2429  frame->width = hwfc->width;
2430  frame->height = hwfc->height;
2431 
2432  return 0;
2433 }
2434 
2436  enum AVHWFrameTransferDirection dir,
2437  enum AVPixelFormat **formats)
2438 {
2439  enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
2440  if (!fmts)
2441  return AVERROR(ENOMEM);
2442 
2443  fmts[0] = hwfc->sw_format;
2444  fmts[1] = AV_PIX_FMT_NONE;
2445 
2446  *formats = fmts;
2447  return 0;
2448 }
2449 
2450 typedef struct VulkanMapping {
2452  int flags;
2453 } VulkanMapping;
2454 
2456 {
2457  VulkanMapping *map = hwmap->priv;
2458  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2459  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2461  FFVulkanFunctions *vk = &p->vkfn;
2462 
2463  /* Check if buffer needs flushing */
2464  if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
2465  !(map->frame->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
2466  VkResult ret;
2467  VkMappedMemoryRange flush_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
2468 
2469  for (int i = 0; i < planes; i++) {
2470  flush_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
2471  flush_ranges[i].memory = map->frame->mem[i];
2472  flush_ranges[i].size = VK_WHOLE_SIZE;
2473  }
2474 
2475  ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, planes,
2476  flush_ranges);
2477  if (ret != VK_SUCCESS) {
2478  av_log(hwfc, AV_LOG_ERROR, "Failed to flush memory: %s\n",
2479  vk_ret2str(ret));
2480  }
2481  }
2482 
2483  for (int i = 0; i < planes; i++)
2484  vk->UnmapMemory(hwctx->act_dev, map->frame->mem[i]);
2485 
2486  av_free(map);
2487 }
2488 
2490  const AVFrame *src, int flags)
2491 {
2492  VkResult ret;
2493  int err, mapped_mem_count = 0, mem_planes = 0;
2494  AVVkFrame *f = (AVVkFrame *)src->data[0];
2495  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2496  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
2497  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2499  FFVulkanFunctions *vk = &p->vkfn;
2500 
2502  if (!map)
2503  return AVERROR(EINVAL);
2504 
2505  if (src->format != AV_PIX_FMT_VULKAN) {
2506  av_log(hwfc, AV_LOG_ERROR, "Cannot map from pixel format %s!\n",
2507  av_get_pix_fmt_name(src->format));
2508  err = AVERROR(EINVAL);
2509  goto fail;
2510  }
2511 
2512  if (!(f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ||
2513  !(f->tiling == VK_IMAGE_TILING_LINEAR)) {
2514  av_log(hwfc, AV_LOG_ERROR, "Unable to map frame, not host visible "
2515  "and linear!\n");
2516  err = AVERROR(EINVAL);
2517  goto fail;
2518  }
2519 
2520  dst->width = src->width;
2521  dst->height = src->height;
2522 
2523  mem_planes = hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY ? 1 : planes;
2524  for (int i = 0; i < mem_planes; i++) {
2525  ret = vk->MapMemory(hwctx->act_dev, f->mem[i], 0,
2526  VK_WHOLE_SIZE, 0, (void **)&dst->data[i]);
2527  if (ret != VK_SUCCESS) {
2528  av_log(hwfc, AV_LOG_ERROR, "Failed to map image memory: %s\n",
2529  vk_ret2str(ret));
2530  err = AVERROR_EXTERNAL;
2531  goto fail;
2532  }
2533  mapped_mem_count++;
2534  }
2535 
2536  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) {
2537  for (int i = 0; i < planes; i++)
2538  dst->data[i] = dst->data[0] + f->offset[i];
2539  }
2540 
2541  /* Check if the memory contents matter */
2543  !(f->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
2544  VkMappedMemoryRange map_mem_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
2545  for (int i = 0; i < planes; i++) {
2546  map_mem_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
2547  map_mem_ranges[i].size = VK_WHOLE_SIZE;
2548  map_mem_ranges[i].memory = f->mem[i];
2549  }
2550 
2551  ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, planes,
2552  map_mem_ranges);
2553  if (ret != VK_SUCCESS) {
2554  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
2555  vk_ret2str(ret));
2556  err = AVERROR_EXTERNAL;
2557  goto fail;
2558  }
2559  }
2560 
2561  for (int i = 0; i < planes; i++) {
2562  VkImageSubresource sub = {
2563  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2564  };
2565  VkSubresourceLayout layout;
2566  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
2567  dst->linesize[i] = layout.rowPitch;
2568  }
2569 
2570  map->frame = f;
2571  map->flags = flags;
2572 
2573  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
2575  if (err < 0)
2576  goto fail;
2577 
2578  return 0;
2579 
2580 fail:
2581  for (int i = 0; i < mapped_mem_count; i++)
2582  vk->UnmapMemory(hwctx->act_dev, f->mem[i]);
2583 
2584  av_free(map);
2585  return err;
2586 }
2587 
2588 #if CONFIG_LIBDRM
2589 static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
2590 {
2591  AVVkFrame *f = hwmap->priv;
2592  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2593  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2595  FFVulkanFunctions *vk = &p->vkfn;
2596 
2597  VkSemaphoreWaitInfo wait_info = {
2598  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
2599  .flags = 0x0,
2600  .pSemaphores = f->sem,
2601  .pValues = f->sem_value,
2602  .semaphoreCount = planes,
2603  };
2604 
2605  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
2606 
2608 
2609  for (int i = 0; i < planes; i++) {
2610  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2611  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2612  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2613  }
2614 
2615  av_free(f);
2616 }
2617 
2618 static const struct {
2619  uint32_t drm_fourcc;
2620  VkFormat vk_format;
2621 } vulkan_drm_format_map[] = {
2622  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
2623  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
2624  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
2625  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
2626  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
2627  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
2628  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
2629  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
2630  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
2631  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
2632 };
2633 
2634 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
2635 {
2636  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
2637  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
2638  return vulkan_drm_format_map[i].vk_format;
2639  return VK_FORMAT_UNDEFINED;
2640 }
2641 
2642 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
2643  const AVFrame *src)
2644 {
2645  int err = 0;
2646  VkResult ret;
2647  AVVkFrame *f;
2648  int bind_counts = 0;
2649  AVHWDeviceContext *ctx = hwfc->device_ctx;
2650  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2651  VulkanDevicePriv *p = ctx->internal->priv;
2652  FFVulkanFunctions *vk = &p->vkfn;
2653  VulkanFramesPriv *fp = hwfc->internal->priv;
2654  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
2655  VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
2656  VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
2657 
2658  for (int i = 0; i < desc->nb_layers; i++) {
2659  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
2660  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
2661  desc->layers[i].format);
2662  return AVERROR(EINVAL);
2663  }
2664  }
2665 
2666  if (!(f = av_vk_frame_alloc())) {
2667  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2668  err = AVERROR(ENOMEM);
2669  goto fail;
2670  }
2671 
2672  f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
2673 
2674  for (int i = 0; i < desc->nb_layers; i++) {
2675  const int planes = desc->layers[i].nb_planes;
2676 
2677  /* Semaphore */
2678  VkSemaphoreTypeCreateInfo sem_type_info = {
2679  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2680  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2681  .initialValue = 0,
2682  };
2683  VkSemaphoreCreateInfo sem_spawn = {
2684  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2685  .pNext = &sem_type_info,
2686  };
2687 
2688  /* Image creation */
2689  VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
2690  VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
2691  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
2692  .drmFormatModifier = desc->objects[0].format_modifier,
2693  .drmFormatModifierPlaneCount = planes,
2694  .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
2695  };
2696  VkExternalMemoryImageCreateInfo ext_img_spec = {
2697  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2698  .pNext = &ext_img_mod_spec,
2699  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2700  };
2701  VkImageCreateInfo create_info = {
2702  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2703  .pNext = &ext_img_spec,
2704  .imageType = VK_IMAGE_TYPE_2D,
2705  .format = drm_to_vulkan_fmt(desc->layers[i].format),
2706  .extent.depth = 1,
2707  .mipLevels = 1,
2708  .arrayLayers = 1,
2709  .flags = 0x0, /* ALIAS flag is implicit for imported images */
2710  .tiling = f->tiling,
2711  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
2712  .usage = VK_IMAGE_USAGE_SAMPLED_BIT |
2713  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
2714  .samples = VK_SAMPLE_COUNT_1_BIT,
2715  .pQueueFamilyIndices = p->qfs,
2716  .queueFamilyIndexCount = p->num_qfs,
2717  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2718  VK_SHARING_MODE_EXCLUSIVE,
2719  };
2720 
2721  /* Image format verification */
2722  VkExternalImageFormatProperties ext_props = {
2723  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2724  };
2725  VkImageFormatProperties2 props_ret = {
2726  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2727  .pNext = &ext_props,
2728  };
2729  VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
2730  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2731  .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
2732  .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
2733  .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
2734  .sharingMode = create_info.sharingMode,
2735  };
2736  VkPhysicalDeviceExternalImageFormatInfo props_ext = {
2737  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2738  .pNext = &props_drm_mod,
2739  .handleType = ext_img_spec.handleTypes,
2740  };
2741  VkPhysicalDeviceImageFormatInfo2 fmt_props = {
2742  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2743  .pNext = &props_ext,
2744  .format = create_info.format,
2745  .type = create_info.imageType,
2746  .tiling = create_info.tiling,
2747  .usage = create_info.usage,
2748  .flags = create_info.flags,
2749  };
2750 
2751  /* Check if importing is possible for this combination of parameters */
2752  ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
2753  &fmt_props, &props_ret);
2754  if (ret != VK_SUCCESS) {
2755  av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
2756  vk_ret2str(ret));
2757  err = AVERROR_EXTERNAL;
2758  goto fail;
2759  }
2760 
2761  /* Set the image width/height */
2762  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2763  hwfc->sw_format, src->width, src->height, i);
2764 
2765  /* Set the subresource layout based on the layer properties */
2766  for (int j = 0; j < planes; j++) {
2767  ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
2768  ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
2769  ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
2770  ext_img_layouts[j].arrayPitch = 0;
2771  ext_img_layouts[j].depthPitch = 0;
2772  }
2773 
2774  /* Create image */
2775  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2776  hwctx->alloc, &f->img[i]);
2777  if (ret != VK_SUCCESS) {
2778  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2779  vk_ret2str(ret));
2780  err = AVERROR(EINVAL);
2781  goto fail;
2782  }
2783 
2784  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2785  hwctx->alloc, &f->sem[i]);
2786  if (ret != VK_SUCCESS) {
2787  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2788  vk_ret2str(ret));
2789  return AVERROR_EXTERNAL;
2790  }
2791 
2792  /* We'd import a semaphore onto the one we created using
2793  * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
2794  * offer us anything we could import and sync with, so instead
2795  * just signal the semaphore we created. */
2796 
2797  f->layout[i] = create_info.initialLayout;
2798  f->access[i] = 0x0;
2799  f->sem_value[i] = 0;
2800  }
2801 
2802  for (int i = 0; i < desc->nb_objects; i++) {
2803  /* Memory requirements */
2804  VkImageMemoryRequirementsInfo2 req_desc = {
2805  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2806  .image = f->img[i],
2807  };
2808  VkMemoryDedicatedRequirements ded_req = {
2809  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2810  };
2811  VkMemoryRequirements2 req2 = {
2812  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2813  .pNext = &ded_req,
2814  };
2815 
2816  /* Allocation/importing */
2817  VkMemoryFdPropertiesKHR fdmp = {
2818  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
2819  };
2820  VkImportMemoryFdInfoKHR idesc = {
2821  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2822  .fd = dup(desc->objects[i].fd),
2823  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2824  };
2825  VkMemoryDedicatedAllocateInfo ded_alloc = {
2826  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2827  .pNext = &idesc,
2828  .image = req_desc.image,
2829  };
2830 
2831  /* Get object properties */
2832  ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
2833  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2834  idesc.fd, &fdmp);
2835  if (ret != VK_SUCCESS) {
2836  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
2837  vk_ret2str(ret));
2838  err = AVERROR_EXTERNAL;
2839  close(idesc.fd);
2840  goto fail;
2841  }
2842 
2843  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
2844 
2845  /* Only a single bit must be set, not a range, and it must match */
2846  req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
2847 
2848  err = alloc_mem(ctx, &req2.memoryRequirements,
2849  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2850  (ded_req.prefersDedicatedAllocation ||
2851  ded_req.requiresDedicatedAllocation) ?
2852  &ded_alloc : ded_alloc.pNext,
2853  &f->flags, &f->mem[i]);
2854  if (err) {
2855  close(idesc.fd);
2856  return err;
2857  }
2858 
2859  f->size[i] = req2.memoryRequirements.size;
2860  }
2861 
2862  for (int i = 0; i < desc->nb_layers; i++) {
2863  const int planes = desc->layers[i].nb_planes;
2864  for (int j = 0; j < planes; j++) {
2865  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2866  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
2867  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
2868 
2869  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
2870  plane_info[bind_counts].pNext = NULL;
2871  plane_info[bind_counts].planeAspect = aspect;
2872 
2873  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2874  bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
2875  bind_info[bind_counts].image = f->img[i];
2876  bind_info[bind_counts].memory = f->mem[desc->layers[i].planes[j].object_index];
2877 
2878  /* Offset is already signalled via pPlaneLayouts above */
2879  bind_info[bind_counts].memoryOffset = 0;
2880 
2881  bind_counts++;
2882  }
2883  }
2884 
2885  /* Bind the allocated memory to the images */
2886  ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
2887  if (ret != VK_SUCCESS) {
2888  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2889  vk_ret2str(ret));
2890  err = AVERROR_EXTERNAL;
2891  goto fail;
2892  }
2893 
2894  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_IMPORT);
2895  if (err)
2896  goto fail;
2897 
2898  *frame = f;
2899 
2900  return 0;
2901 
2902 fail:
2903  for (int i = 0; i < desc->nb_layers; i++) {
2904  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2905  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2906  }
2907  for (int i = 0; i < desc->nb_objects; i++)
2908  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2909 
2910  av_free(f);
2911 
2912  return err;
2913 }
2914 
2915 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2916  const AVFrame *src, int flags)
2917 {
2918  int err = 0;
2919  AVVkFrame *f;
2920 
2921  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src)))
2922  return err;
2923 
2924  /* The unmapping function will free this */
2925  dst->data[0] = (uint8_t *)f;
2926  dst->width = src->width;
2927  dst->height = src->height;
2928 
2929  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2930  &vulkan_unmap_from_drm, f);
2931  if (err < 0)
2932  goto fail;
2933 
2934  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
2935 
2936  return 0;
2937 
2938 fail:
2939  vulkan_frame_free(hwfc->device_ctx->hwctx, (uint8_t *)f);
2940  dst->data[0] = NULL;
2941  return err;
2942 }
2943 
2944 #if CONFIG_VAAPI
2945 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
2946  AVFrame *dst, const AVFrame *src,
2947  int flags)
2948 {
2949  int err;
2950  AVFrame *tmp = av_frame_alloc();
2951  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
2952  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
2953  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
2954 
2955  if (!tmp)
2956  return AVERROR(ENOMEM);
2957 
2958  /* We have to sync since like the previous comment said, no semaphores */
2959  vaSyncSurface(vaapi_ctx->display, surface_id);
2960 
2961  tmp->format = AV_PIX_FMT_DRM_PRIME;
2962 
2963  err = av_hwframe_map(tmp, src, flags);
2964  if (err < 0)
2965  goto fail;
2966 
2967  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
2968  if (err < 0)
2969  goto fail;
2970 
2971  err = ff_hwframe_map_replace(dst, src);
2972 
2973 fail:
2974  av_frame_free(&tmp);
2975  return err;
2976 }
2977 #endif
2978 #endif
2979 
2980 #if CONFIG_CUDA
2981 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
2982  AVBufferRef *cuda_hwfc,
2983  const AVFrame *frame)
2984 {
2985  int err;
2986  VkResult ret;
2987  AVVkFrame *dst_f;
2988  AVVkFrameInternal *dst_int;
2989  AVHWDeviceContext *ctx = hwfc->device_ctx;
2990  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2991  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2993  VulkanDevicePriv *p = ctx->internal->priv;
2994  FFVulkanFunctions *vk = &p->vkfn;
2995 
2996  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
2997  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2998  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2999  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3000  CudaFunctions *cu = cu_internal->cuda_dl;
3001  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
3002  CU_AD_FORMAT_UNSIGNED_INT8;
3003 
3004  dst_f = (AVVkFrame *)frame->data[0];
3005 
3006  dst_int = dst_f->internal;
3007  if (!dst_int || !dst_int->cuda_fc_ref) {
3008  if (!dst_f->internal)
3009  dst_f->internal = dst_int = av_mallocz(sizeof(*dst_f->internal));
3010 
3011  if (!dst_int)
3012  return AVERROR(ENOMEM);
3013 
3014  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
3015  if (!dst_int->cuda_fc_ref) {
3016  av_freep(&dst_f->internal);
3017  return AVERROR(ENOMEM);
3018  }
3019 
3020  for (int i = 0; i < planes; i++) {
3021  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
3022  .offset = 0,
3023  .arrayDesc = {
3024  .Depth = 0,
3025  .Format = cufmt,
3026  .NumChannels = 1 + ((planes == 2) && i),
3027  .Flags = 0,
3028  },
3029  .numLevels = 1,
3030  };
3031  int p_w, p_h;
3032 
3033 #ifdef _WIN32
3034  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3035  .type = IsWindows8OrGreater()
3036  ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3037  : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
3038  .size = dst_f->size[i],
3039  };
3040  VkMemoryGetWin32HandleInfoKHR export_info = {
3041  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
3042  .memory = dst_f->mem[i],
3043  .handleType = IsWindows8OrGreater()
3044  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3045  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3046  };
3047  VkSemaphoreGetWin32HandleInfoKHR sem_export = {
3048  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
3049  .semaphore = dst_f->sem[i],
3050  .handleType = IsWindows8OrGreater()
3051  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
3052  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3053  };
3054  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3055  .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
3056  };
3057 
3058  ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
3059  &ext_desc.handle.win32.handle);
3060  if (ret != VK_SUCCESS) {
3061  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
3062  vk_ret2str(ret));
3063  err = AVERROR_EXTERNAL;
3064  goto fail;
3065  }
3066  dst_int->ext_mem_handle[i] = ext_desc.handle.win32.handle;
3067 #else
3068  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3069  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
3070  .size = dst_f->size[i],
3071  };
3072  VkMemoryGetFdInfoKHR export_info = {
3073  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3074  .memory = dst_f->mem[i],
3075  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
3076  };
3077  VkSemaphoreGetFdInfoKHR sem_export = {
3078  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
3079  .semaphore = dst_f->sem[i],
3080  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
3081  };
3082  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3083  .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
3084  };
3085 
3086  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3087  &ext_desc.handle.fd);
3088  if (ret != VK_SUCCESS) {
3089  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
3090  vk_ret2str(ret));
3091  err = AVERROR_EXTERNAL;
3092  goto fail;
3093  }
3094 #endif
3095 
3096  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
3097  if (ret < 0) {
3098 #ifndef _WIN32
3099  close(ext_desc.handle.fd);
3100 #endif
3101  err = AVERROR_EXTERNAL;
3102  goto fail;
3103  }
3104 
3105  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3106  tex_desc.arrayDesc.Width = p_w;
3107  tex_desc.arrayDesc.Height = p_h;
3108 
3109  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
3110  dst_int->ext_mem[i],
3111  &tex_desc));
3112  if (ret < 0) {
3113  err = AVERROR_EXTERNAL;
3114  goto fail;
3115  }
3116 
3117  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
3118  dst_int->cu_mma[i], 0));
3119  if (ret < 0) {
3120  err = AVERROR_EXTERNAL;
3121  goto fail;
3122  }
3123 
3124 #ifdef _WIN32
3125  ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
3126  &ext_sem_desc.handle.win32.handle);
3127 #else
3128  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
3129  &ext_sem_desc.handle.fd);
3130 #endif
3131  if (ret != VK_SUCCESS) {
3132  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
3133  vk_ret2str(ret));
3134  err = AVERROR_EXTERNAL;
3135  goto fail;
3136  }
3137 #ifdef _WIN32
3138  dst_int->ext_sem_handle[i] = ext_sem_desc.handle.win32.handle;
3139 #endif
3140 
3141  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i],
3142  &ext_sem_desc));
3143  if (ret < 0) {
3144 #ifndef _WIN32
3145  close(ext_sem_desc.handle.fd);
3146 #endif
3147  err = AVERROR_EXTERNAL;
3148  goto fail;
3149  }
3150  }
3151  }
3152 
3153  return 0;
3154 
3155 fail:
3156  vulkan_free_internal(dst_f);
3157  return err;
3158 }
3159 
3160 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
3161  AVFrame *dst, const AVFrame *src)
3162 {
3163  int err;
3164  CUcontext dummy;
3165  AVVkFrame *dst_f;
3166  AVVkFrameInternal *dst_int;
3167  VulkanFramesPriv *fp = hwfc->internal->priv;
3168  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3170 
3171  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3172  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3173  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3174  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3175  CudaFunctions *cu = cu_internal->cuda_dl;
3176  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
3177  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
3178 
3179  dst_f = (AVVkFrame *)dst->data[0];
3180 
3181  err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_EXPORT);
3182  if (err < 0)
3183  return err;
3184 
3185  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
3186  if (err < 0)
3187  return err;
3188 
3189  err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
3190  if (err < 0) {
3191  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3192  return err;
3193  }
3194 
3195  dst_int = dst_f->internal;
3196 
3197  for (int i = 0; i < planes; i++) {
3198  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
3199  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
3200  }
3201 
3202  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
3203  planes, cuda_dev->stream));
3204  if (err < 0)
3205  goto fail;
3206 
3207  for (int i = 0; i < planes; i++) {
3208  CUDA_MEMCPY2D cpy = {
3209  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
3210  .srcDevice = (CUdeviceptr)src->data[i],
3211  .srcPitch = src->linesize[i],
3212  .srcY = 0,
3213 
3214  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
3215  .dstArray = dst_int->cu_array[i],
3216  };
3217 
3218  int p_w, p_h;
3219  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3220 
3221  cpy.WidthInBytes = p_w * desc->comp[i].step;
3222  cpy.Height = p_h;
3223 
3224  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
3225  if (err < 0)
3226  goto fail;
3227  }
3228 
3229  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
3230  planes, cuda_dev->stream));
3231  if (err < 0)
3232  goto fail;
3233 
3234  for (int i = 0; i < planes; i++)
3235  dst_f->sem_value[i]++;
3236 
3237  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3238 
3239  av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n");
3240 
3241  return err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_IMPORT);
3242 
3243 fail:
3244  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3245  vulkan_free_internal(dst_f);
3246  dst_f->internal = NULL;
3247  av_buffer_unref(&dst->buf[0]);
3248  return err;
3249 }
3250 #endif
3251 
3252 static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
3253  const AVFrame *src, int flags)
3254 {
3256 
3257  switch (src->format) {
3258 #if CONFIG_LIBDRM
3259 #if CONFIG_VAAPI
3260  case AV_PIX_FMT_VAAPI:
3262  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
3263  else
3264  return AVERROR(ENOSYS);
3265 #endif
3266  case AV_PIX_FMT_DRM_PRIME:
3268  return vulkan_map_from_drm(hwfc, dst, src, flags);
3269  else
3270  return AVERROR(ENOSYS);
3271 #endif
3272  default:
3273  return AVERROR(ENOSYS);
3274  }
3275 }
3276 
3277 #if CONFIG_LIBDRM
3278 typedef struct VulkanDRMMapping {
3279  AVDRMFrameDescriptor drm_desc;
3280  AVVkFrame *source;
3281 } VulkanDRMMapping;
3282 
3283 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3284 {
3285  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
3286 
3287  for (int i = 0; i < drm_desc->nb_objects; i++)
3288  close(drm_desc->objects[i].fd);
3289 
3290  av_free(drm_desc);
3291 }
3292 
3293 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
3294 {
3295  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3296  if (vulkan_drm_format_map[i].vk_format == vkfmt)
3297  return vulkan_drm_format_map[i].drm_fourcc;
3298  return DRM_FORMAT_INVALID;
3299 }
3300 
3301 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3302  const AVFrame *src, int flags)
3303 {
3304  int err = 0;
3305  VkResult ret;
3306  AVVkFrame *f = (AVVkFrame *)src->data[0];
3308  FFVulkanFunctions *vk = &p->vkfn;
3309  VulkanFramesPriv *fp = hwfc->internal->priv;
3310  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
3311  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
3312  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3313  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3314  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3315  };
3316  VkSemaphoreWaitInfo wait_info = {
3317  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
3318  .flags = 0x0,
3319  .semaphoreCount = planes,
3320  };
3321 
3322  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
3323  if (!drm_desc)
3324  return AVERROR(ENOMEM);
3325 
3326  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_EXPORT);
3327  if (err < 0)
3328  goto end;
3329 
3330  /* Wait for the operation to finish so we can cleanly export it. */
3331  wait_info.pSemaphores = f->sem;
3332  wait_info.pValues = f->sem_value;
3333 
3334  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
3335 
3336  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
3337  if (err < 0)
3338  goto end;
3339 
3340  ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
3341  &drm_mod);
3342  if (ret != VK_SUCCESS) {
3343  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
3344  err = AVERROR_EXTERNAL;
3345  goto end;
3346  }
3347 
3348  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
3349  VkMemoryGetFdInfoKHR export_info = {
3350  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3351  .memory = f->mem[i],
3352  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3353  };
3354 
3355  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3356  &drm_desc->objects[i].fd);
3357  if (ret != VK_SUCCESS) {
3358  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
3359  err = AVERROR_EXTERNAL;
3360  goto end;
3361  }
3362 
3363  drm_desc->nb_objects++;
3364  drm_desc->objects[i].size = f->size[i];
3365  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
3366  }
3367 
3368  drm_desc->nb_layers = planes;
3369  for (int i = 0; i < drm_desc->nb_layers; i++) {
3370  VkSubresourceLayout layout;
3371  VkImageSubresource sub = {
3372  .aspectMask = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
3373  };
3374  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
3375 
3376  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
3377  drm_desc->layers[i].nb_planes = 1;
3378 
3379  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
3380  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
3381  err = AVERROR_PATCHWELCOME;
3382  goto end;
3383  }
3384 
3385  drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
3386 
3387  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
3388  continue;
3389 
3390  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
3391  drm_desc->layers[i].planes[0].offset = layout.offset;
3392  drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
3393 
3394  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY)
3395  drm_desc->layers[i].planes[0].offset += f->offset[i];
3396  }
3397 
3398  dst->width = src->width;
3399  dst->height = src->height;
3400  dst->data[0] = (uint8_t *)drm_desc;
3401 
3402  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
3403 
3404  return 0;
3405 
3406 end:
3407  av_free(drm_desc);
3408  return err;
3409 }
3410 
3411 #if CONFIG_VAAPI
3412 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
3413  const AVFrame *src, int flags)
3414 {
3415  int err;
3416  AVFrame *tmp = av_frame_alloc();
3417  if (!tmp)
3418  return AVERROR(ENOMEM);
3419 
3420  tmp->format = AV_PIX_FMT_DRM_PRIME;
3421 
3422  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
3423  if (err < 0)
3424  goto fail;
3425 
3426  err = av_hwframe_map(dst, tmp, flags);
3427  if (err < 0)
3428  goto fail;
3429 
3430  err = ff_hwframe_map_replace(dst, src);
3431 
3432 fail:
3433  av_frame_free(&tmp);
3434  return err;
3435 }
3436 #endif
3437 #endif
3438 
3440  const AVFrame *src, int flags)
3441 {
3443 
3444  switch (dst->format) {
3445 #if CONFIG_LIBDRM
3446  case AV_PIX_FMT_DRM_PRIME:
3448  return vulkan_map_to_drm(hwfc, dst, src, flags);
3449  else
3450  return AVERROR(ENOSYS);
3451 #if CONFIG_VAAPI
3452  case AV_PIX_FMT_VAAPI:
3454  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
3455  else
3456  return AVERROR(ENOSYS);
3457 #endif
3458 #endif
3459  default:
3460  return vulkan_map_frame_to_mem(hwfc, dst, src, flags);
3461  }
3462 }
3463 
3464 typedef struct ImageBuffer {
3465  VkBuffer buf;
3466  VkDeviceMemory mem;
3467  VkMemoryPropertyFlagBits flags;
3469 } ImageBuffer;
3470 
3471 static void free_buf(void *opaque, uint8_t *data)
3472 {
3473  AVHWDeviceContext *ctx = opaque;
3474  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3475  VulkanDevicePriv *p = ctx->internal->priv;
3476  FFVulkanFunctions *vk = &p->vkfn;
3477  ImageBuffer *vkbuf = (ImageBuffer *)data;
3478 
3479  if (vkbuf->buf)
3480  vk->DestroyBuffer(hwctx->act_dev, vkbuf->buf, hwctx->alloc);
3481  if (vkbuf->mem)
3482  vk->FreeMemory(hwctx->act_dev, vkbuf->mem, hwctx->alloc);
3483 
3484  av_free(data);
3485 }
3486 
3488 {
3489  size_t size;
3490  *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
3491  size = height*(*stride);
3492  size = FFALIGN(size, p->props.properties.limits.minMemoryMapAlignment);
3493  return size;
3494 }
3495 
3497  VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags,
3498  size_t size, uint32_t req_memory_bits, int host_mapped,
3499  void *create_pnext, void *alloc_pnext)
3500 {
3501  int err;
3502  VkResult ret;
3503  int use_ded_mem;
3504  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3505  VulkanDevicePriv *p = ctx->internal->priv;
3506  FFVulkanFunctions *vk = &p->vkfn;
3507 
3508  VkBufferCreateInfo buf_spawn = {
3509  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
3510  .pNext = create_pnext,
3511  .usage = usage,
3512  .size = size,
3513  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
3514  };
3515 
3516  VkBufferMemoryRequirementsInfo2 req_desc = {
3517  .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
3518  };
3519  VkMemoryDedicatedAllocateInfo ded_alloc = {
3520  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
3521  .pNext = alloc_pnext,
3522  };
3523  VkMemoryDedicatedRequirements ded_req = {
3524  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
3525  };
3526  VkMemoryRequirements2 req = {
3527  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3528  .pNext = &ded_req,
3529  };
3530 
3531  ImageBuffer *vkbuf = av_mallocz(sizeof(*vkbuf));
3532  if (!vkbuf)
3533  return AVERROR(ENOMEM);
3534 
3535  vkbuf->mapped_mem = host_mapped;
3536 
3537  ret = vk->CreateBuffer(hwctx->act_dev, &buf_spawn, NULL, &vkbuf->buf);
3538  if (ret != VK_SUCCESS) {
3539  av_log(ctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
3540  vk_ret2str(ret));
3541  err = AVERROR_EXTERNAL;
3542  goto fail;
3543  }
3544 
3545  req_desc.buffer = vkbuf->buf;
3546 
3547  vk->GetBufferMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
3548 
3549  /* In case the implementation prefers/requires dedicated allocation */
3550  use_ded_mem = ded_req.prefersDedicatedAllocation |
3551  ded_req.requiresDedicatedAllocation;
3552  if (use_ded_mem)
3553  ded_alloc.buffer = vkbuf->buf;
3554 
3555  /* Additional requirements imposed on us */
3556  if (req_memory_bits)
3557  req.memoryRequirements.memoryTypeBits &= req_memory_bits;
3558 
3559  err = alloc_mem(ctx, &req.memoryRequirements, flags,
3560  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
3561  &vkbuf->flags, &vkbuf->mem);
3562  if (err)
3563  goto fail;
3564 
3565  ret = vk->BindBufferMemory(hwctx->act_dev, vkbuf->buf, vkbuf->mem, 0);
3566  if (ret != VK_SUCCESS) {
3567  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
3568  vk_ret2str(ret));
3569  err = AVERROR_EXTERNAL;
3570  goto fail;
3571  }
3572 
3573  *buf = av_buffer_create((uint8_t *)vkbuf, sizeof(*vkbuf), free_buf, ctx, 0);
3574  if (!(*buf)) {
3575  err = AVERROR(ENOMEM);
3576  goto fail;
3577  }
3578 
3579  return 0;
3580 
3581 fail:
3582  free_buf(ctx, (uint8_t *)vkbuf);
3583  return err;
3584 }
3585 
3586 /* Skips mapping of host mapped buffers but still invalidates them */
3587 static int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[],
3588  int nb_buffers, int invalidate)
3589 {
3590  VkResult ret;
3591  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3592  VulkanDevicePriv *p = ctx->internal->priv;
3593  FFVulkanFunctions *vk = &p->vkfn;
3594  VkMappedMemoryRange invalidate_ctx[AV_NUM_DATA_POINTERS];
3595  int invalidate_count = 0;
3596 
3597  for (int i = 0; i < nb_buffers; i++) {
3598  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3599  if (vkbuf->mapped_mem)
3600  continue;
3601 
3602  ret = vk->MapMemory(hwctx->act_dev, vkbuf->mem, 0,
3603  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
3604  if (ret != VK_SUCCESS) {
3605  av_log(ctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
3606  vk_ret2str(ret));
3607  return AVERROR_EXTERNAL;
3608  }
3609  }
3610 
3611  if (!invalidate)
3612  return 0;
3613 
3614  for (int i = 0; i < nb_buffers; i++) {
3615  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3616  const VkMappedMemoryRange ival_buf = {
3617  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3618  .memory = vkbuf->mem,
3619  .size = VK_WHOLE_SIZE,
3620  };
3621 
3622  /* For host imported memory Vulkan says to use platform-defined
3623  * sync methods, but doesn't really say not to call flush or invalidate
3624  * on original host pointers. It does explicitly allow to do that on
3625  * host-mapped pointers which are then mapped again using vkMapMemory,
3626  * but known implementations return the original pointers when mapped
3627  * again. */
3628  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
3629  continue;
3630 
3631  invalidate_ctx[invalidate_count++] = ival_buf;
3632  }
3633 
3634  if (invalidate_count) {
3635  ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, invalidate_count,
3636  invalidate_ctx);
3637  if (ret != VK_SUCCESS)
3638  av_log(ctx, AV_LOG_WARNING, "Failed to invalidate memory: %s\n",
3639  vk_ret2str(ret));
3640  }
3641 
3642  return 0;
3643 }
3644 
3646  int nb_buffers, int flush)
3647 {
3648  int err = 0;
3649  VkResult ret;
3650  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3651  VulkanDevicePriv *p = ctx->internal->priv;
3652  FFVulkanFunctions *vk = &p->vkfn;
3653  VkMappedMemoryRange flush_ctx[AV_NUM_DATA_POINTERS];
3654  int flush_count = 0;
3655 
3656  if (flush) {
3657  for (int i = 0; i < nb_buffers; i++) {
3658  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3659  const VkMappedMemoryRange flush_buf = {
3660  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3661  .memory = vkbuf->mem,
3662  .size = VK_WHOLE_SIZE,
3663  };
3664 
3665  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
3666  continue;
3667 
3668  flush_ctx[flush_count++] = flush_buf;
3669  }
3670  }
3671 
3672  if (flush_count) {
3673  ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, flush_count, flush_ctx);
3674  if (ret != VK_SUCCESS) {
3675  av_log(ctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
3676  vk_ret2str(ret));
3677  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
3678  }
3679  }
3680 
3681  for (int i = 0; i < nb_buffers; i++) {
3682  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3683  if (vkbuf->mapped_mem)
3684  continue;
3685 
3686  vk->UnmapMemory(hwctx->act_dev, vkbuf->mem);
3687  }
3688 
3689  return err;
3690 }
3691 
3693  AVBufferRef **bufs, size_t *buf_offsets,
3694  const int *buf_stride, int w,
3695  int h, enum AVPixelFormat pix_fmt, int to_buf)
3696 {
3697  int err;
3698  AVVkFrame *frame = (AVVkFrame *)f->data[0];
3699  VulkanFramesPriv *fp = hwfc->internal->priv;
3701  FFVulkanFunctions *vk = &p->vkfn;
3702 
3703  int bar_num = 0;
3704  VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS];
3705 
3706  const int planes = av_pix_fmt_count_planes(pix_fmt);
3708 
3709  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
3710  VulkanExecCtx *ectx = to_buf ? &fp->download_ctx : &fp->upload_ctx;
3711  VkCommandBuffer cmd_buf = get_buf_exec_ctx(hwfc, ectx);
3712 
3713  uint64_t sem_signal_values[AV_NUM_DATA_POINTERS];
3714 
3715  VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = {
3716  .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
3717  .pWaitSemaphoreValues = frame->sem_value,
3718  .pSignalSemaphoreValues = sem_signal_values,
3719  .waitSemaphoreValueCount = planes,
3720  .signalSemaphoreValueCount = planes,
3721  };
3722 
3723  VkSubmitInfo s_info = {
3724  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3725  .pNext = &s_timeline_sem_info,
3726  .pSignalSemaphores = frame->sem,
3727  .pWaitSemaphores = frame->sem,
3728  .pWaitDstStageMask = sem_wait_dst,
3729  .signalSemaphoreCount = planes,
3730  .waitSemaphoreCount = planes,
3731  };
3732 
3733  for (int i = 0; i < planes; i++)
3734  sem_signal_values[i] = frame->sem_value[i] + 1;
3735 
3736  if ((err = wait_start_exec_ctx(hwfc, ectx)))
3737  return err;
3738 
3739  /* Change the image layout to something more optimal for transfers */
3740  for (int i = 0; i < planes; i++) {
3741  VkImageLayout new_layout = to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL :
3742  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3743  VkAccessFlags new_access = to_buf ? VK_ACCESS_TRANSFER_READ_BIT :
3744  VK_ACCESS_TRANSFER_WRITE_BIT;
3745 
3746  sem_wait_dst[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3747 
3748  /* If the layout matches and we have read access skip the barrier */
3749  if ((frame->layout[i] == new_layout) && (frame->access[i] & new_access))
3750  continue;
3751 
3752  img_bar[bar_num].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3753  img_bar[bar_num].srcAccessMask = 0x0;
3754  img_bar[bar_num].dstAccessMask = new_access;
3755  img_bar[bar_num].oldLayout = frame->layout[i];
3756  img_bar[bar_num].newLayout = new_layout;
3757  img_bar[bar_num].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3758  img_bar[bar_num].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3759  img_bar[bar_num].image = frame->img[i];
3760  img_bar[bar_num].subresourceRange.levelCount = 1;
3761  img_bar[bar_num].subresourceRange.layerCount = 1;
3762  img_bar[bar_num].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3763 
3764  frame->layout[i] = img_bar[bar_num].newLayout;
3765  frame->access[i] = img_bar[bar_num].dstAccessMask;
3766 
3767  bar_num++;
3768  }
3769 
3770  if (bar_num)
3771  vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3772  VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
3773  0, NULL, 0, NULL, bar_num, img_bar);
3774 
3775  /* Schedule a copy for each plane */
3776  for (int i = 0; i < planes; i++) {
3777  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3778  VkBufferImageCopy buf_reg = {
3779  .bufferOffset = buf_offsets[i],
3780  .bufferRowLength = buf_stride[i] / desc->comp[i].step,
3781  .imageSubresource.layerCount = 1,
3782  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3783  .imageOffset = { 0, 0, 0, },
3784  };
3785 
3786  int p_w, p_h;
3787  get_plane_wh(&p_w, &p_h, pix_fmt, w, h, i);
3788 
3789  buf_reg.bufferImageHeight = p_h;
3790  buf_reg.imageExtent = (VkExtent3D){ p_w, p_h, 1, };
3791 
3792  if (to_buf)
3793  vk->CmdCopyImageToBuffer(cmd_buf, frame->img[i], frame->layout[i],
3794  vkbuf->buf, 1, &buf_reg);
3795  else
3796  vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[i],
3797  frame->layout[i], 1, &buf_reg);
3798  }
3799 
3800  /* When uploading, do this asynchronously if the source is refcounted by
3801  * keeping the buffers as a submission dependency.
3802  * The hwcontext is guaranteed to not be freed until all frames are freed
3803  * in the frames_unint function.
3804  * When downloading to buffer, do this synchronously and wait for the
3805  * queue submission to finish executing */
3806  if (!to_buf) {
3807  int ref;
3808  for (ref = 0; ref < AV_NUM_DATA_POINTERS; ref++) {
3809  if (!f->buf[ref])
3810  break;
3811  if ((err = add_buf_dep_exec_ctx(hwfc, ectx, &f->buf[ref], 1)))
3812  return err;
3813  }
3814  if (ref && (err = add_buf_dep_exec_ctx(hwfc, ectx, bufs, planes)))
3815  return err;
3816  return submit_exec_ctx(hwfc, ectx, &s_info, frame, !ref);
3817  } else {
3818  return submit_exec_ctx(hwfc, ectx, &s_info, frame, 1);
3819  }
3820 }
3821 
3822 static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf,
3823  const AVFrame *swf, int from)
3824 {
3825  int err = 0;
3826  VkResult ret;
3827  AVVkFrame *f = (AVVkFrame *)vkf->data[0];
3828  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
3829  AVVulkanDeviceContext *hwctx = dev_ctx->hwctx;
3831  FFVulkanFunctions *vk = &p->vkfn;
3832 
3833  AVFrame tmp;
3834  AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 };
3835  size_t buf_offsets[AV_NUM_DATA_POINTERS] = { 0 };
3836 
3837  int p_w, p_h;
3838  const int planes = av_pix_fmt_count_planes(swf->format);
3839 
3840  int host_mapped[AV_NUM_DATA_POINTERS] = { 0 };
3841  const int map_host = !!(p->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY);
3842 
3843  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
3844  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
3845  return AVERROR(EINVAL);
3846  }
3847 
3848  if (swf->width > hwfc->width || swf->height > hwfc->height)
3849  return AVERROR(EINVAL);
3850 
3851  /* For linear, host visiable images */
3852  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
3853  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
3854  AVFrame *map = av_frame_alloc();
3855  if (!map)
3856  return AVERROR(ENOMEM);
3857  map->format = swf->format;
3858 
3860  if (err)
3861  return err;
3862 
3863  err = av_frame_copy((AVFrame *)(from ? swf : map), from ? map : swf);
3864  av_frame_free(&map);
3865  return err;
3866  }
3867 
3868  /* Create buffers */
3869  for (int i = 0; i < planes; i++) {
3870  size_t req_size;
3871 
3872  VkExternalMemoryBufferCreateInfo create_desc = {
3873  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
3874  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3875  };
3876 
3877  VkImportMemoryHostPointerInfoEXT import_desc = {
3878  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3879  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3880  };
3881 
3882  VkMemoryHostPointerPropertiesEXT p_props = {
3883  .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
3884  };
3885 
3886  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3887 
3888  tmp.linesize[i] = FFABS(swf->linesize[i]);
3889 
3890  /* Do not map images with a negative stride */
3891  if (map_host && swf->linesize[i] > 0) {
3892  size_t offs;
3893  offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment;
3894  import_desc.pHostPointer = swf->data[i] - offs;
3895 
3896  /* We have to compensate for the few extra bytes of padding we
3897  * completely ignore at the start */
3898  req_size = FFALIGN(offs + tmp.linesize[i] * p_h,
3899  p->hprops.minImportedHostPointerAlignment);
3900 
3901  ret = vk->GetMemoryHostPointerPropertiesEXT(hwctx->act_dev,
3902  import_desc.handleType,
3903  import_desc.pHostPointer,
3904  &p_props);
3905 
3906  if (ret == VK_SUCCESS) {
3907  host_mapped[i] = 1;
3908  buf_offsets[i] = offs;
3909  }
3910  }
3911 
3912  if (!host_mapped[i])
3913  req_size = get_req_buffer_size(p, &tmp.linesize[i], p_h);
3914 
3915  err = create_buf(dev_ctx, &bufs[i],
3916  from ? VK_BUFFER_USAGE_TRANSFER_DST_BIT :
3917  VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
3918  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
3919  req_size, p_props.memoryTypeBits, host_mapped[i],
3920  host_mapped[i] ? &create_desc : NULL,
3921  host_mapped[i] ? &import_desc : NULL);
3922  if (err)
3923  goto end;
3924  }
3925 
3926  if (!from) {
3927  /* Map, copy image TO buffer (which then goes to the VkImage), unmap */
3928  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3929  goto end;
3930 
3931  for (int i = 0; i < planes; i++) {
3932  if (host_mapped[i])
3933  continue;
3934 
3935  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3936 
3937  av_image_copy_plane(tmp.data[i], tmp.linesize[i],
3938  (const uint8_t *)swf->data[i], swf->linesize[i],
3939  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3940  p_h);
3941  }
3942 
3943  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3944  goto end;
3945  }
3946 
3947  /* Copy buffers into/from image */
3948  err = transfer_image_buf(hwfc, vkf, bufs, buf_offsets, tmp.linesize,
3949  swf->width, swf->height, swf->format, from);
3950 
3951  if (from) {
3952  /* Map, copy buffer (which came FROM the VkImage) to the frame, unmap */
3953  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3954  goto end;
3955 
3956  for (int i = 0; i < planes; i++) {
3957  if (host_mapped[i])
3958  continue;
3959 
3960  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3961 
3962  av_image_copy_plane_uc_from(swf->data[i], swf->linesize[i],
3963  (const uint8_t *)tmp.data[i], tmp.linesize[i],
3964  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3965  p_h);
3966  }
3967 
3968  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3969  goto end;
3970  }
3971 
3972 end:
3973  for (int i = 0; i < planes; i++)
3974  av_buffer_unref(&bufs[i]);
3975 
3976  return err;
3977 }
3978 
3980  const AVFrame *src)
3981 {
3983 
3984  switch (src->format) {
3985 #if CONFIG_CUDA
3986  case AV_PIX_FMT_CUDA:
3987 #ifdef _WIN32
3988  if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
3989  (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
3990 #else
3991  if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
3992  (p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
3993 #endif
3994  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
3995 #endif
3996  default:
3997  if (src->hw_frames_ctx)
3998  return AVERROR(ENOSYS);
3999  else
4000  return vulkan_transfer_data(hwfc, dst, src, 0);
4001  }
4002 }
4003 
4004 #if CONFIG_CUDA
4005 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
4006  const AVFrame *src)
4007 {
4008  int err;
4009  CUcontext dummy;
4010  AVVkFrame *dst_f;
4011  AVVkFrameInternal *dst_int;
4012  VulkanFramesPriv *fp = hwfc->internal->priv;
4013  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4015 
4017  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4018  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4019  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4020  CudaFunctions *cu = cu_internal->cuda_dl;
4021  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4022  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4023 
4024  dst_f = (AVVkFrame *)src->data[0];
4025 
4026  err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4027  if (err < 0)
4028  return err;
4029 
4030  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4031  if (err < 0)
4032  return err;
4033 
4034  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
4035  if (err < 0) {
4036  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4037  return err;
4038  }
4039 
4040  dst_int = dst_f->internal;
4041 
4042  for (int i = 0; i < planes; i++) {
4043  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4044  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4045  }
4046 
4047  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4048  planes, cuda_dev->stream));
4049  if (err < 0)
4050  goto fail;
4051 
4052  for (int i = 0; i < planes; i++) {
4053  CUDA_MEMCPY2D cpy = {
4054  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
4055  .dstDevice = (CUdeviceptr)dst->data[i],
4056  .dstPitch = dst->linesize[i],
4057  .dstY = 0,
4058 
4059  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
4060  .srcArray = dst_int->cu_array[i],
4061  };
4062 
4063  int w, h;
4064  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4065 
4066  cpy.WidthInBytes = w * desc->comp[i].step;
4067  cpy.Height = h;
4068 
4069  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4070  if (err < 0)
4071  goto fail;
4072  }
4073 
4074  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4075  planes, cuda_dev->stream));
4076  if (err < 0)
4077  goto fail;
4078 
4079  for (int i = 0; i < planes; i++)
4080  dst_f->sem_value[i]++;
4081 
4082  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4083 
4084  av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n");
4085 
4086  return prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4087 
4088 fail:
4089  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4090  vulkan_free_internal(dst_f);
4091  dst_f->internal = NULL;
4092  av_buffer_unref(&dst->buf[0]);
4093  return err;
4094 }
4095 #endif
4096 
4098  const AVFrame *src)
4099 {
4101 
4102  switch (dst->format) {
4103 #if CONFIG_CUDA
4104  case AV_PIX_FMT_CUDA:
4105 #ifdef _WIN32
4106  if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4107  (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4108 #else
4109  if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4110  (p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4111 #endif
4112  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
4113 #endif
4114  default:
4115  if (dst->hw_frames_ctx)
4116  return AVERROR(ENOSYS);
4117  else
4118  return vulkan_transfer_data(hwfc, src, dst, 1);
4119  }
4120 }
4121 
4123  AVHWFramesContext *src_fc, int flags)
4124 {
4125  return vulkan_frames_init(dst_fc);
4126 }
4127 
4129 {
4130  return av_mallocz(sizeof(AVVkFrame));
4131 }
4132 
4135  .name = "Vulkan",
4136 
4137  .device_hwctx_size = sizeof(AVVulkanDeviceContext),
4138  .device_priv_size = sizeof(VulkanDevicePriv),
4139  .frames_hwctx_size = sizeof(AVVulkanFramesContext),
4140  .frames_priv_size = sizeof(VulkanFramesPriv),
4141 
4142  .device_init = &vulkan_device_init,
4143  .device_create = &vulkan_device_create,
4144  .device_derive = &vulkan_device_derive,
4145 
4146  .frames_get_constraints = &vulkan_frames_get_constraints,
4147  .frames_init = vulkan_frames_init,
4148  .frames_get_buffer = vulkan_get_buffer,
4149  .frames_uninit = vulkan_frames_uninit,
4150 
4151  .transfer_get_formats = vulkan_transfer_get_formats,
4152  .transfer_data_to = vulkan_transfer_data_to,
4153  .transfer_data_from = vulkan_transfer_data_from,
4154 
4155  .map_to = vulkan_map_to,
4156  .map_from = vulkan_map_from,
4157  .frames_derive_to = &vulkan_frames_derive_to,
4158 
4159  .pix_fmts = (const enum AVPixelFormat []) {
4162  },
4163 };
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:449
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:1433
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:428
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:2452
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:381
vulkan_transfer_data_to
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_vulkan.c:3979
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:2662
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:1621
vulkan_transfer_data
static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, const AVFrame *swf, int from)
Definition: hwcontext_vulkan.c:3822
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:4122
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:111
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
pixdesc.h
AVVulkanDeviceContext::get_proc_addr
PFN_vkGetInstanceProcAddr get_proc_addr
Pointer to the instance-provided vkGetInstanceProcAddr loading function.
Definition: hwcontext_vulkan.h: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
AVFrame::width
int width
Definition: frame.h:397
AV_PIX_FMT_YUVA420P16
#define AV_PIX_FMT_YUVA420P16
Definition: pixfmt.h:448
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:320
AV_PIX_FMT_YUVA420P10
#define AV_PIX_FMT_YUVA420P10
Definition: pixfmt.h:443
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:790
data
const char data[16]
Definition: mxf.c:143
linear
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:132
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:2131
AV_PIX_FMT_YUV420P10
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:406
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:3439
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:738
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:149
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:525
AV_PIX_FMT_YUVA422P10
#define AV_PIX_FMT_YUVA422P10
Definition: pixfmt.h:444
AVVulkanDeviceContext::nb_decode_queues
int nb_decode_queues
Definition: hwcontext_vulkan.h:137
vk_pixfmt_map
static const struct @316 vk_pixfmt_map[]
prepare_frame
static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, AVVkFrame *frame, enum PrepMode pmode)
Definition: hwcontext_vulkan.c:1913
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:348
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:346
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:1667
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:370
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:2702
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:1550
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:131
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:450
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
dummy
int dummy
Definition: motion.c:65
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:3467
ImageBuffer::buf
VkBuffer buf
Definition: hwcontext_vulkan.c:3465
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:2489
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:147
vulkan_frame_free
static void vulkan_frame_free(void *opaque, uint8_t *data)
Definition: hwcontext_vulkan.c:1763
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:390
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:99
AV_PIX_FMT_YUV444P10
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:409
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:418
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:3252
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:505
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:419
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:50
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
ff_vk_load_functions
static int ff_vk_load_functions(AVHWDeviceContext *ctx, FFVulkanFunctions *vk, uint64_t extensions_mask, int has_inst, int has_dev)
Function loader.
Definition: vulkan_loader.h:80
AV_PIX_FMT_0BGR32
#define AV_PIX_FMT_0BGR32
Definition: pixfmt.h:384
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:189
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:447
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:2256
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:417
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:2435
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:438
LIBAVUTIL_VERSION_MINOR
#define LIBAVUTIL_VERSION_MINOR
Definition: version.h:82
ImageBuffer::mem
VkDeviceMemory mem
Definition: hwcontext_vulkan.c:3466
get_req_buffer_size
static size_t get_req_buffer_size(VulkanDevicePriv *p, int *stride, int height)
Definition: hwcontext_vulkan.c:3487
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:64
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:1908
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:396
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:606
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:2450
unmap_buffers
static int unmap_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, int nb_buffers, int flush)
Definition: hwcontext_vulkan.c:3645
ff_hwcontext_type_vulkan
const HWContextType ff_hwcontext_type_vulkan
Definition: hwcontext_vulkan.c:4133
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:407
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:1787
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:3496
VulkanFramesPriv
Definition: hwcontext_vulkan.c:116
index
int index
Definition: gxfenc.c:89
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
planes
static const struct @328 planes[]
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:2025
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:2193
PrepMode
PrepMode
Definition: hwcontext_vulkan.c:1907
f
f
Definition: af_crystalizer.c:122
AVCUDADeviceContext::internal
AVCUDADeviceContextInternal * internal
Definition: hwcontext_cuda.h:45
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h: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:764
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:4128
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:435
AV_PIX_FMT_YUV422P12
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:411
vulkan_unmap_frame
static void vulkan_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
Definition: hwcontext_vulkan.c:2455
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:3692
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:392
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:4097
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:326
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:413
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:412
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:3464
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:445
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:116
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:1725
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
AV_HWFRAME_MAP_READ
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition: hwcontext.h:524
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:31
weights
static const int weights[]
Definition: hevc_pel.c:32
AV_PIX_FMT_NV24
@ AV_PIX_FMT_NV24
planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:340
plane_info
Definition: vf_edgedetect.c:52
vulkan_frames_init
static int vulkan_frames_init(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:2271
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:459
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:264
free_buf
static void free_buf(void *opaque, uint8_t *data)
Definition: hwcontext_vulkan.c:3471
VulkanDeviceSelection::has_uuid
int has_uuid
Definition: hwcontext_vulkan.c:759
hwcontext_drm.h
VulkanMapping::frame
AVVkFrame * frame
Definition: hwcontext_vulkan.c:2451
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:398
AV_HWFRAME_MAP_WRITE
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition: hwcontext.h:528
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:946
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:341
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:272
mod
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:750
AV_PIX_FMT_P016
#define AV_PIX_FMT_P016
Definition: pixfmt.h:456
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:393
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:2421
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:2008
AV_PIX_FMT_YUV420P12
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:410
SIZE_SPECIFIER
#define SIZE_SPECIFIER
Definition: internal.h:195
map_buffers
static int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[], int nb_buffers, int invalidate)
Definition: hwcontext_vulkan.c:3587
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:659
vulkan_device_create
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:1534
AVFrame::height
int height
Definition: frame.h:397
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:446
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:436
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
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:112
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:1910
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
AVVulkanFramesContext::tiling
VkImageTiling tiling
Controls the tiling of allocated frames.
Definition: hwcontext_vulkan.h:164
VulkanExecCtx
Definition: hwcontext_vulkan.c:71
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:455
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
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:280
desc
const char * desc
Definition: libsvtav1.c:83
AVVulkanDeviceContext::enabled_dev_extensions
const char *const * enabled_dev_extensions
Enabled device extensions.
Definition: hwcontext_vulkan.h: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:33
AVDictionaryEntry
Definition: dict.h:79
AV_DRM_MAX_PLANES
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
Definition: hwcontext_drm.h:39
PREP_MODE_EXTERNAL_EXPORT
@ PREP_MODE_EXTERNAL_EXPORT
Definition: hwcontext_vulkan.c:1909
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:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
FF_VK_EXT_EXTERNAL_FD_SEM
@ FF_VK_EXT_EXTERNAL_FD_SEM
Definition: vulkan_functions.h:33
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:3468
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:370
VulkanQueueCtx::queue
VkQueue queue
Definition: hwcontext_vulkan.c:62
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
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:2582