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