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 #include "config.h"
20 #include "pixdesc.h"
21 #include "avstring.h"
22 #include "imgutils.h"
23 #include "hwcontext.h"
24 #include "hwcontext_internal.h"
25 #include "hwcontext_vulkan.h"
26 
27 #if CONFIG_LIBDRM
28 #include <unistd.h>
29 #include <xf86drm.h>
30 #include <drm_fourcc.h>
31 #include "hwcontext_drm.h"
32 #if CONFIG_VAAPI
33 #include <va/va_drmcommon.h>
34 #include "hwcontext_vaapi.h"
35 #endif
36 #endif
37 
38 #if CONFIG_CUDA
40 #include "cuda_check.h"
41 #define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x)
42 #endif
43 
44 typedef struct VulkanQueueCtx {
45  VkFence fence;
46  VkQueue queue;
48 
49  /* Buffer dependencies */
54 
55 typedef struct VulkanExecCtx {
56  VkCommandPool pool;
57  VkCommandBuffer *bufs;
59  int nb_queues;
62 
63 typedef struct VulkanDevicePriv {
64  /* Properties */
65  VkPhysicalDeviceProperties2 props;
66  VkPhysicalDeviceMemoryProperties mprops;
67  VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops;
68 
69  /* Queues */
70  uint32_t qfs[3];
71  int num_qfs;
72 
73  /* Debug callback */
74  VkDebugUtilsMessengerEXT debug_ctx;
75 
76  /* Extensions */
77  uint64_t extensions;
78 
79  /* Settings */
81 
82  /* Nvidia */
85 
86 typedef struct VulkanFramesPriv {
87  /* Image conversions */
89 
90  /* Image transfers */
94 
95 typedef struct AVVkFrameInternal {
96 #if CONFIG_CUDA
97  /* Importing external memory into cuda is really expensive so we keep the
98  * memory imported all the time */
99  AVBufferRef *cuda_fc_ref; /* Need to keep it around for uninit */
100  CUexternalMemory ext_mem[AV_NUM_DATA_POINTERS];
101  CUmipmappedArray cu_mma[AV_NUM_DATA_POINTERS];
102  CUarray cu_array[AV_NUM_DATA_POINTERS];
103  CUexternalSemaphore cu_sem[AV_NUM_DATA_POINTERS];
104 #endif
106 
107 #define GET_QUEUE_COUNT(hwctx, graph, comp, tx) ( \
108  graph ? hwctx->nb_graphics_queues : \
109  comp ? (hwctx->nb_comp_queues ? \
110  hwctx->nb_comp_queues : hwctx->nb_graphics_queues) : \
111  tx ? (hwctx->nb_tx_queues ? hwctx->nb_tx_queues : \
112  (hwctx->nb_comp_queues ? \
113  hwctx->nb_comp_queues : hwctx->nb_graphics_queues)) : \
114  0 \
115 )
116 
117 #define VK_LOAD_PFN(inst, name) PFN_##name pfn_##name = (PFN_##name) \
118  vkGetInstanceProcAddr(inst, #name)
119 
120 #define DEFAULT_USAGE_FLAGS (VK_IMAGE_USAGE_SAMPLED_BIT | \
121  VK_IMAGE_USAGE_STORAGE_BIT | \
122  VK_IMAGE_USAGE_TRANSFER_SRC_BIT | \
123  VK_IMAGE_USAGE_TRANSFER_DST_BIT)
124 
125 #define ADD_VAL_TO_LIST(list, count, val) \
126  do { \
127  list = av_realloc_array(list, sizeof(*list), ++count); \
128  if (!list) { \
129  err = AVERROR(ENOMEM); \
130  goto fail; \
131  } \
132  list[count - 1] = av_strdup(val); \
133  if (!list[count - 1]) { \
134  err = AVERROR(ENOMEM); \
135  goto fail; \
136  } \
137  } while(0)
138 
139 static const struct {
141  const VkFormat vkfmts[3];
142 } vk_pixfmt_map[] = {
143  { AV_PIX_FMT_GRAY8, { VK_FORMAT_R8_UNORM } },
144  { AV_PIX_FMT_GRAY16, { VK_FORMAT_R16_UNORM } },
145  { AV_PIX_FMT_GRAYF32, { VK_FORMAT_R32_SFLOAT } },
146 
147  { AV_PIX_FMT_NV12, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
148  { AV_PIX_FMT_P010, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
149  { AV_PIX_FMT_P016, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
150 
151  { AV_PIX_FMT_YUV420P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
152  { AV_PIX_FMT_YUV422P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
153  { AV_PIX_FMT_YUV444P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
154 
155  { AV_PIX_FMT_YUV420P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
156  { AV_PIX_FMT_YUV422P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
157  { AV_PIX_FMT_YUV444P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
158 
159  { AV_PIX_FMT_ABGR, { VK_FORMAT_A8B8G8R8_UNORM_PACK32 } },
160  { AV_PIX_FMT_BGRA, { VK_FORMAT_B8G8R8A8_UNORM } },
161  { AV_PIX_FMT_RGBA, { VK_FORMAT_R8G8B8A8_UNORM } },
162  { AV_PIX_FMT_RGB24, { VK_FORMAT_R8G8B8_UNORM } },
163  { AV_PIX_FMT_BGR24, { VK_FORMAT_B8G8R8_UNORM } },
164  { AV_PIX_FMT_RGB48, { VK_FORMAT_R16G16B16_UNORM } },
165  { AV_PIX_FMT_RGBA64, { VK_FORMAT_R16G16B16A16_UNORM } },
166  { AV_PIX_FMT_RGB565, { VK_FORMAT_R5G6B5_UNORM_PACK16 } },
167  { AV_PIX_FMT_BGR565, { VK_FORMAT_B5G6R5_UNORM_PACK16 } },
168  { AV_PIX_FMT_BGR0, { VK_FORMAT_B8G8R8A8_UNORM } },
169  { AV_PIX_FMT_0BGR, { VK_FORMAT_A8B8G8R8_UNORM_PACK32 } },
170  { AV_PIX_FMT_RGB0, { VK_FORMAT_R8G8B8A8_UNORM } },
171 
172  { AV_PIX_FMT_GBRPF32, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
173 };
174 
175 const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p)
176 {
177  for (enum AVPixelFormat i = 0; i < FF_ARRAY_ELEMS(vk_pixfmt_map); i++)
178  if (vk_pixfmt_map[i].pixfmt == p)
179  return vk_pixfmt_map[i].vkfmts;
180  return NULL;
181 }
182 
184  int linear)
185 {
186  const VkFormat *fmt = av_vkfmt_from_pixfmt(p);
188 
189  if (!fmt)
190  return 0;
191 
192  for (int i = 0; i < planes; i++) {
193  VkFormatFeatureFlags flags;
194  VkFormatProperties2 prop = {
195  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
196  };
197  vkGetPhysicalDeviceFormatProperties2(hwctx->phys_dev, fmt[i], &prop);
198  flags = linear ? prop.formatProperties.linearTilingFeatures :
199  prop.formatProperties.optimalTilingFeatures;
200  if (!(flags & DEFAULT_USAGE_FLAGS))
201  return 0;
202  }
203 
204  return 1;
205 }
206 
208  EXT_EXTERNAL_DMABUF_MEMORY = 1ULL << 0, /* VK_EXT_external_memory_dma_buf */
209  EXT_DRM_MODIFIER_FLAGS = 1ULL << 1, /* VK_EXT_image_drm_format_modifier */
210  EXT_EXTERNAL_FD_MEMORY = 1ULL << 2, /* VK_KHR_external_memory_fd */
211  EXT_EXTERNAL_FD_SEM = 1ULL << 3, /* VK_KHR_external_semaphore_fd */
212  EXT_EXTERNAL_HOST_MEMORY = 1ULL << 4, /* VK_EXT_external_memory_host */
213 
214  EXT_NO_FLAG = 1ULL << 63,
215 };
216 
217 typedef struct VulkanOptExtension {
218  const char *name;
219  uint64_t flag;
221 
223  /* For future use */
224 };
225 
227  { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, EXT_EXTERNAL_FD_MEMORY, },
228  { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, EXT_EXTERNAL_DMABUF_MEMORY, },
229  { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, EXT_DRM_MODIFIER_FLAGS, },
230  { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, EXT_EXTERNAL_FD_SEM, },
231  { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, EXT_EXTERNAL_HOST_MEMORY, },
232 };
233 
234 /* Converts return values to strings */
235 static const char *vk_ret2str(VkResult res)
236 {
237 #define CASE(VAL) case VAL: return #VAL
238  switch (res) {
239  CASE(VK_SUCCESS);
240  CASE(VK_NOT_READY);
241  CASE(VK_TIMEOUT);
242  CASE(VK_EVENT_SET);
243  CASE(VK_EVENT_RESET);
244  CASE(VK_INCOMPLETE);
245  CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
246  CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
247  CASE(VK_ERROR_INITIALIZATION_FAILED);
248  CASE(VK_ERROR_DEVICE_LOST);
249  CASE(VK_ERROR_MEMORY_MAP_FAILED);
250  CASE(VK_ERROR_LAYER_NOT_PRESENT);
251  CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
252  CASE(VK_ERROR_FEATURE_NOT_PRESENT);
253  CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
254  CASE(VK_ERROR_TOO_MANY_OBJECTS);
255  CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
256  CASE(VK_ERROR_FRAGMENTED_POOL);
257  CASE(VK_ERROR_SURFACE_LOST_KHR);
258  CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
259  CASE(VK_SUBOPTIMAL_KHR);
260  CASE(VK_ERROR_OUT_OF_DATE_KHR);
261  CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
262  CASE(VK_ERROR_VALIDATION_FAILED_EXT);
263  CASE(VK_ERROR_INVALID_SHADER_NV);
264  CASE(VK_ERROR_OUT_OF_POOL_MEMORY);
265  CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE);
266  CASE(VK_ERROR_NOT_PERMITTED_EXT);
267  CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
268  CASE(VK_ERROR_INVALID_DEVICE_ADDRESS_EXT);
269  CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
270  default: return "Unknown error";
271  }
272 #undef CASE
273 }
274 
275 static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
276  VkDebugUtilsMessageTypeFlagsEXT messageType,
277  const VkDebugUtilsMessengerCallbackDataEXT *data,
278  void *priv)
279 {
280  int l;
281  AVHWDeviceContext *ctx = priv;
282 
283  switch (severity) {
284  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: l = AV_LOG_VERBOSE; break;
285  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: l = AV_LOG_INFO; break;
286  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: l = AV_LOG_WARNING; break;
287  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: l = AV_LOG_ERROR; break;
288  default: l = AV_LOG_DEBUG; break;
289  }
290 
291  av_log(ctx, l, "%s\n", data->pMessage);
292  for (int i = 0; i < data->cmdBufLabelCount; i++)
293  av_log(ctx, l, "\t%i: %s\n", i, data->pCmdBufLabels[i].pLabelName);
294 
295  return 0;
296 }
297 
299  const char * const **dst, uint32_t *num, int debug)
300 {
301  const char *tstr;
302  const char **extension_names = NULL;
303  VulkanDevicePriv *p = ctx->internal->priv;
304  AVVulkanDeviceContext *hwctx = ctx->hwctx;
305  int err = 0, found, extensions_found = 0;
306 
307  const char *mod;
308  int optional_exts_num;
309  uint32_t sup_ext_count;
310  char *user_exts_str = NULL;
311  AVDictionaryEntry *user_exts;
312  VkExtensionProperties *sup_ext;
313  const VulkanOptExtension *optional_exts;
314 
315  if (!dev) {
316  mod = "instance";
317  optional_exts = optional_instance_exts;
318  optional_exts_num = FF_ARRAY_ELEMS(optional_instance_exts);
319  user_exts = av_dict_get(opts, "instance_extensions", NULL, 0);
320  if (user_exts) {
321  user_exts_str = av_strdup(user_exts->value);
322  if (!user_exts_str) {
323  err = AVERROR(ENOMEM);
324  goto fail;
325  }
326  }
327  vkEnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL);
328  sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
329  if (!sup_ext)
330  return AVERROR(ENOMEM);
331  vkEnumerateInstanceExtensionProperties(NULL, &sup_ext_count, sup_ext);
332  } else {
333  mod = "device";
334  optional_exts = optional_device_exts;
335  optional_exts_num = FF_ARRAY_ELEMS(optional_device_exts);
336  user_exts = av_dict_get(opts, "device_extensions", NULL, 0);
337  if (user_exts) {
338  user_exts_str = av_strdup(user_exts->value);
339  if (!user_exts_str) {
340  err = AVERROR(ENOMEM);
341  goto fail;
342  }
343  }
344  vkEnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
345  &sup_ext_count, NULL);
346  sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
347  if (!sup_ext)
348  return AVERROR(ENOMEM);
349  vkEnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
350  &sup_ext_count, sup_ext);
351  }
352 
353  for (int i = 0; i < optional_exts_num; i++) {
354  tstr = optional_exts[i].name;
355  found = 0;
356  for (int j = 0; j < sup_ext_count; j++) {
357  if (!strcmp(tstr, sup_ext[j].extensionName)) {
358  found = 1;
359  break;
360  }
361  }
362  if (!found)
363  continue;
364 
365  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, tstr);
366  p->extensions |= optional_exts[i].flag;
367  ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
368  }
369 
370  if (debug && !dev) {
371  tstr = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
372  found = 0;
373  for (int j = 0; j < sup_ext_count; j++) {
374  if (!strcmp(tstr, sup_ext[j].extensionName)) {
375  found = 1;
376  break;
377  }
378  }
379  if (found) {
380  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, tstr);
381  ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
382  } else {
383  av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n",
384  tstr);
385  err = AVERROR(EINVAL);
386  goto fail;
387  }
388  }
389 
390  if (user_exts_str) {
391  char *save, *token = av_strtok(user_exts_str, "+", &save);
392  while (token) {
393  found = 0;
394  for (int j = 0; j < sup_ext_count; j++) {
395  if (!strcmp(token, sup_ext[j].extensionName)) {
396  found = 1;
397  break;
398  }
399  }
400  if (found) {
401  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, token);
402  ADD_VAL_TO_LIST(extension_names, extensions_found, token);
403  } else {
404  av_log(ctx, AV_LOG_WARNING, "%s extension \"%s\" not found, excluding.\n",
405  mod, token);
406  }
407  token = av_strtok(NULL, "+", &save);
408  }
409  }
410 
411  *dst = extension_names;
412  *num = extensions_found;
413 
414  av_free(user_exts_str);
415  av_free(sup_ext);
416  return 0;
417 
418 fail:
419  if (extension_names)
420  for (int i = 0; i < extensions_found; i++)
421  av_free((void *)extension_names[i]);
422  av_free(extension_names);
423  av_free(user_exts_str);
424  av_free(sup_ext);
425  return err;
426 }
427 
428 /* Creates a VkInstance */
430 {
431  int err = 0;
432  VkResult ret;
433  VulkanDevicePriv *p = ctx->internal->priv;
434  AVVulkanDeviceContext *hwctx = ctx->hwctx;
435  AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
436  const int debug_mode = debug_opt && strtol(debug_opt->value, NULL, 10);
437  VkApplicationInfo application_info = {
438  .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
439  .pEngineName = "libavutil",
440  .apiVersion = VK_API_VERSION_1_1,
441  .engineVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR,
444  };
445  VkInstanceCreateInfo inst_props = {
446  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
447  .pApplicationInfo = &application_info,
448  };
449 
450  /* Check for present/missing extensions */
451  err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames,
452  &inst_props.enabledExtensionCount, debug_mode);
453  if (err < 0)
454  return err;
455 
456  if (debug_mode) {
457  static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
458  inst_props.ppEnabledLayerNames = layers;
459  inst_props.enabledLayerCount = FF_ARRAY_ELEMS(layers);
460  }
461 
462  /* Try to create the instance */
463  ret = vkCreateInstance(&inst_props, hwctx->alloc, &hwctx->inst);
464 
465  /* Check for errors */
466  if (ret != VK_SUCCESS) {
467  av_log(ctx, AV_LOG_ERROR, "Instance creation failure: %s\n",
468  vk_ret2str(ret));
469  for (int i = 0; i < inst_props.enabledExtensionCount; i++)
470  av_free((void *)inst_props.ppEnabledExtensionNames[i]);
471  av_free((void *)inst_props.ppEnabledExtensionNames);
472  return AVERROR_EXTERNAL;
473  }
474 
475  if (debug_mode) {
476  VkDebugUtilsMessengerCreateInfoEXT dbg = {
477  .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
478  .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
479  VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
480  VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
481  VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
482  .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
483  VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
484  VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
485  .pfnUserCallback = vk_dbg_callback,
486  .pUserData = ctx,
487  };
488  VK_LOAD_PFN(hwctx->inst, vkCreateDebugUtilsMessengerEXT);
489 
490  pfn_vkCreateDebugUtilsMessengerEXT(hwctx->inst, &dbg,
491  hwctx->alloc, &p->debug_ctx);
492  }
493 
494  hwctx->enabled_inst_extensions = inst_props.ppEnabledExtensionNames;
495  hwctx->nb_enabled_inst_extensions = inst_props.enabledExtensionCount;
496 
497  return 0;
498 }
499 
500 typedef struct VulkanDeviceSelection {
501  uint8_t uuid[VK_UUID_SIZE]; /* Will use this first unless !has_uuid */
502  int has_uuid;
503  const char *name; /* Will use this second unless NULL */
504  uint32_t pci_device; /* Will use this third unless 0x0 */
505  uint32_t vendor_id; /* Last resort to find something deterministic */
506  int index; /* Finally fall back to index */
508 
509 static const char *vk_dev_type(enum VkPhysicalDeviceType type)
510 {
511  switch (type) {
512  case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "integrated";
513  case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "discrete";
514  case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "virtual";
515  case VK_PHYSICAL_DEVICE_TYPE_CPU: return "software";
516  default: return "unknown";
517  }
518 }
519 
520 /* Finds a device */
522 {
523  int err = 0, choice = -1;
524  uint32_t num;
525  VkResult ret;
526  VkPhysicalDevice *devices = NULL;
527  VkPhysicalDeviceIDProperties *idp = NULL;
528  VkPhysicalDeviceProperties2 *prop = NULL;
529  AVVulkanDeviceContext *hwctx = ctx->hwctx;
530 
531  ret = vkEnumeratePhysicalDevices(hwctx->inst, &num, NULL);
532  if (ret != VK_SUCCESS || !num) {
533  av_log(ctx, AV_LOG_ERROR, "No devices found: %s!\n", vk_ret2str(ret));
534  return AVERROR(ENODEV);
535  }
536 
537  devices = av_malloc_array(num, sizeof(VkPhysicalDevice));
538  if (!devices)
539  return AVERROR(ENOMEM);
540 
541  ret = vkEnumeratePhysicalDevices(hwctx->inst, &num, devices);
542  if (ret != VK_SUCCESS) {
543  av_log(ctx, AV_LOG_ERROR, "Failed enumerating devices: %s\n",
544  vk_ret2str(ret));
545  err = AVERROR(ENODEV);
546  goto end;
547  }
548 
549  prop = av_mallocz_array(num, sizeof(*prop));
550  if (!prop) {
551  err = AVERROR(ENOMEM);
552  goto end;
553  }
554 
555  idp = av_mallocz_array(num, sizeof(*idp));
556  if (!idp) {
557  err = AVERROR(ENOMEM);
558  goto end;
559  }
560 
561  av_log(ctx, AV_LOG_VERBOSE, "GPU listing:\n");
562  for (int i = 0; i < num; i++) {
563  idp[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
564  prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
565  prop[i].pNext = &idp[i];
566 
567  vkGetPhysicalDeviceProperties2(devices[i], &prop[i]);
568  av_log(ctx, AV_LOG_VERBOSE, " %d: %s (%s) (0x%x)\n", i,
569  prop[i].properties.deviceName,
570  vk_dev_type(prop[i].properties.deviceType),
571  prop[i].properties.deviceID);
572  }
573 
574  if (select->has_uuid) {
575  for (int i = 0; i < num; i++) {
576  if (!strncmp(idp[i].deviceUUID, select->uuid, VK_UUID_SIZE)) {
577  choice = i;
578  goto end;
579  }
580  }
581  av_log(ctx, AV_LOG_ERROR, "Unable to find device by given UUID!\n");
582  err = AVERROR(ENODEV);
583  goto end;
584  } else if (select->name) {
585  av_log(ctx, AV_LOG_VERBOSE, "Requested device: %s\n", select->name);
586  for (int i = 0; i < num; i++) {
587  if (strstr(prop[i].properties.deviceName, select->name)) {
588  choice = i;
589  goto end;
590  }
591  }
592  av_log(ctx, AV_LOG_ERROR, "Unable to find device \"%s\"!\n",
593  select->name);
594  err = AVERROR(ENODEV);
595  goto end;
596  } else if (select->pci_device) {
597  av_log(ctx, AV_LOG_VERBOSE, "Requested device: 0x%x\n", select->pci_device);
598  for (int i = 0; i < num; i++) {
599  if (select->pci_device == prop[i].properties.deviceID) {
600  choice = i;
601  goto end;
602  }
603  }
604  av_log(ctx, AV_LOG_ERROR, "Unable to find device with PCI ID 0x%x!\n",
605  select->pci_device);
606  err = AVERROR(EINVAL);
607  goto end;
608  } else if (select->vendor_id) {
609  av_log(ctx, AV_LOG_VERBOSE, "Requested vendor: 0x%x\n", select->vendor_id);
610  for (int i = 0; i < num; i++) {
611  if (select->vendor_id == prop[i].properties.vendorID) {
612  choice = i;
613  goto end;
614  }
615  }
616  av_log(ctx, AV_LOG_ERROR, "Unable to find device with Vendor ID 0x%x!\n",
617  select->vendor_id);
618  err = AVERROR(ENODEV);
619  goto end;
620  } else {
621  if (select->index < num) {
622  choice = select->index;
623  goto end;
624  }
625  av_log(ctx, AV_LOG_ERROR, "Unable to find device with index %i!\n",
626  select->index);
627  err = AVERROR(ENODEV);
628  goto end;
629  }
630 
631 end:
632  if (choice > -1)
633  hwctx->phys_dev = devices[choice];
634 
635  av_free(devices);
636  av_free(prop);
637  av_free(idp);
638 
639  return err;
640 }
641 
642 static int search_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
643 {
644  uint32_t num;
645  float *weights;
646  VkQueueFamilyProperties *qs = NULL;
647  AVVulkanDeviceContext *hwctx = ctx->hwctx;
648  int graph_index = -1, comp_index = -1, tx_index = -1;
649  VkDeviceQueueCreateInfo *pc = (VkDeviceQueueCreateInfo *)cd->pQueueCreateInfos;
650 
651  /* First get the number of queue families */
652  vkGetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, NULL);
653  if (!num) {
654  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
655  return AVERROR_EXTERNAL;
656  }
657 
658  /* Then allocate memory */
659  qs = av_malloc_array(num, sizeof(VkQueueFamilyProperties));
660  if (!qs)
661  return AVERROR(ENOMEM);
662 
663  /* Finally retrieve the queue families */
664  vkGetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, qs);
665 
666 #define SEARCH_FLAGS(expr, out) \
667  for (int i = 0; i < num; i++) { \
668  const VkQueueFlagBits flags = qs[i].queueFlags; \
669  if (expr) { \
670  out = i; \
671  break; \
672  } \
673  }
674 
675  SEARCH_FLAGS(flags & VK_QUEUE_GRAPHICS_BIT, graph_index)
676 
677  SEARCH_FLAGS((flags & VK_QUEUE_COMPUTE_BIT) && (i != graph_index),
678  comp_index)
679 
680  SEARCH_FLAGS((flags & VK_QUEUE_TRANSFER_BIT) && (i != graph_index) &&
681  (i != comp_index), tx_index)
682 
683 #undef SEARCH_FLAGS
684 #define ADD_QUEUE(fidx, graph, comp, tx) \
685  av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (total queues: %i) for %s%s%s\n", \
686  fidx, qs[fidx].queueCount, graph ? "graphics " : "", \
687  comp ? "compute " : "", tx ? "transfers " : ""); \
688  av_log(ctx, AV_LOG_VERBOSE, " QF %i flags: %s%s%s%s\n", fidx, \
689  ((qs[fidx].queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? "(graphics) " : "", \
690  ((qs[fidx].queueFlags) & VK_QUEUE_COMPUTE_BIT) ? "(compute) " : "", \
691  ((qs[fidx].queueFlags) & VK_QUEUE_TRANSFER_BIT) ? "(transfers) " : "", \
692  ((qs[fidx].queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? "(sparse) " : ""); \
693  pc[cd->queueCreateInfoCount].queueFamilyIndex = fidx; \
694  pc[cd->queueCreateInfoCount].queueCount = qs[fidx].queueCount; \
695  weights = av_malloc(qs[fidx].queueCount * sizeof(float)); \
696  pc[cd->queueCreateInfoCount].pQueuePriorities = weights; \
697  if (!weights) \
698  goto fail; \
699  for (int i = 0; i < qs[fidx].queueCount; i++) \
700  weights[i] = 1.0f; \
701  cd->queueCreateInfoCount++;
702 
703  ADD_QUEUE(graph_index, 1, comp_index < 0, tx_index < 0 && comp_index < 0)
704  hwctx->queue_family_index = graph_index;
705  hwctx->queue_family_comp_index = graph_index;
706  hwctx->queue_family_tx_index = graph_index;
707  hwctx->nb_graphics_queues = qs[graph_index].queueCount;
708 
709  if (comp_index != -1) {
710  ADD_QUEUE(comp_index, 0, 1, tx_index < 0)
711  hwctx->queue_family_tx_index = comp_index;
712  hwctx->queue_family_comp_index = comp_index;
713  hwctx->nb_comp_queues = qs[comp_index].queueCount;
714  }
715 
716  if (tx_index != -1) {
717  ADD_QUEUE(tx_index, 0, 0, 1)
718  hwctx->queue_family_tx_index = tx_index;
719  hwctx->nb_tx_queues = qs[tx_index].queueCount;
720  }
721 
722 #undef ADD_QUEUE
723  av_free(qs);
724 
725  return 0;
726 
727 fail:
728  av_freep(&pc[0].pQueuePriorities);
729  av_freep(&pc[1].pQueuePriorities);
730  av_freep(&pc[2].pQueuePriorities);
731  av_free(qs);
732 
733  return AVERROR(ENOMEM);
734 }
735 
737  int queue_family_index, int num_queues)
738 {
739  VkResult ret;
740  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
741 
742  VkCommandPoolCreateInfo cqueue_create = {
743  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
744  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
745  .queueFamilyIndex = queue_family_index,
746  };
747  VkCommandBufferAllocateInfo cbuf_create = {
748  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
749  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
750  .commandBufferCount = num_queues,
751  };
752 
753  cmd->nb_queues = num_queues;
754 
755  cmd->queues = av_mallocz(num_queues * sizeof(*cmd->queues));
756  if (!cmd->queues)
757  return AVERROR(ENOMEM);
758 
759  cmd->bufs = av_mallocz(num_queues * sizeof(*cmd->bufs));
760  if (!cmd->bufs)
761  return AVERROR(ENOMEM);
762 
763  /* Create command pool */
764  ret = vkCreateCommandPool(hwctx->act_dev, &cqueue_create,
765  hwctx->alloc, &cmd->pool);
766  if (ret != VK_SUCCESS) {
767  av_log(hwfc, AV_LOG_ERROR, "Command pool creation failure: %s\n",
768  vk_ret2str(ret));
769  return AVERROR_EXTERNAL;
770  }
771 
772  cbuf_create.commandPool = cmd->pool;
773 
774  /* Allocate command buffer */
775  ret = vkAllocateCommandBuffers(hwctx->act_dev, &cbuf_create, cmd->bufs);
776  if (ret != VK_SUCCESS) {
777  av_log(hwfc, AV_LOG_ERROR, "Command buffer alloc failure: %s\n",
778  vk_ret2str(ret));
779  return AVERROR_EXTERNAL;
780  }
781 
782  for (int i = 0; i < num_queues; i++) {
783  VulkanQueueCtx *q = &cmd->queues[i];
784  vkGetDeviceQueue(hwctx->act_dev, queue_family_index, i, &q->queue);
785  q->was_synchronous = 1;
786  }
787 
788  return 0;
789 }
790 
792 {
793  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
794 
795  /* Make sure all queues have finished executing */
796  for (int i = 0; i < cmd->nb_queues; i++) {
797  VulkanQueueCtx *q = &cmd->queues[i];
798 
799  if (q->fence && !q->was_synchronous) {
800  vkWaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
801  vkResetFences(hwctx->act_dev, 1, &q->fence);
802  }
803 
804  /* Free the fence */
805  if (q->fence)
806  vkDestroyFence(hwctx->act_dev, q->fence, hwctx->alloc);
807 
808  /* Free buffer dependencies */
809  for (int j = 0; j < q->nb_buf_deps; j++)
810  av_buffer_unref(&q->buf_deps[j]);
811  av_free(q->buf_deps);
812  }
813 
814  if (cmd->bufs)
815  vkFreeCommandBuffers(hwctx->act_dev, cmd->pool, cmd->nb_queues, cmd->bufs);
816  if (cmd->pool)
817  vkDestroyCommandPool(hwctx->act_dev, cmd->pool, hwctx->alloc);
818 
819  av_freep(&cmd->bufs);
820  av_freep(&cmd->queues);
821 }
822 
823 static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
824 {
825  return cmd->bufs[cmd->cur_queue_idx];
826 }
827 
829 {
830  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
831 
832  for (int j = 0; j < q->nb_buf_deps; j++)
833  av_buffer_unref(&q->buf_deps[j]);
834  q->nb_buf_deps = 0;
835 }
836 
838 {
839  VkResult ret;
840  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
841  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
842 
843  VkCommandBufferBeginInfo cmd_start = {
844  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
845  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
846  };
847 
848  /* Create the fence and don't wait for it initially */
849  if (!q->fence) {
850  VkFenceCreateInfo fence_spawn = {
851  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
852  };
853  ret = vkCreateFence(hwctx->act_dev, &fence_spawn, hwctx->alloc,
854  &q->fence);
855  if (ret != VK_SUCCESS) {
856  av_log(hwfc, AV_LOG_ERROR, "Failed to queue frame fence: %s\n",
857  vk_ret2str(ret));
858  return AVERROR_EXTERNAL;
859  }
860  } else if (!q->was_synchronous) {
861  vkWaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
862  vkResetFences(hwctx->act_dev, 1, &q->fence);
863  }
864 
865  /* Discard queue dependencies */
866  unref_exec_ctx_deps(hwfc, cmd);
867 
868  ret = vkBeginCommandBuffer(cmd->bufs[cmd->cur_queue_idx], &cmd_start);
869  if (ret != VK_SUCCESS) {
870  av_log(hwfc, AV_LOG_ERROR, "Unable to init command buffer: %s\n",
871  vk_ret2str(ret));
872  return AVERROR_EXTERNAL;
873  }
874 
875  return 0;
876 }
877 
879  AVBufferRef * const *deps, int nb_deps)
880 {
881  AVBufferRef **dst;
882  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
883 
884  if (!deps || !nb_deps)
885  return 0;
886 
888  (q->nb_buf_deps + nb_deps) * sizeof(*dst));
889  if (!dst)
890  goto err;
891 
892  q->buf_deps = dst;
893 
894  for (int i = 0; i < nb_deps; i++) {
895  q->buf_deps[q->nb_buf_deps] = av_buffer_ref(deps[i]);
896  if (!q->buf_deps[q->nb_buf_deps])
897  goto err;
898  q->nb_buf_deps++;
899  }
900 
901  return 0;
902 
903 err:
904  unref_exec_ctx_deps(hwfc, cmd);
905  return AVERROR(ENOMEM);
906 }
907 
909  VkSubmitInfo *s_info, int synchronous)
910 {
911  VkResult ret;
912  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
913 
914  ret = vkEndCommandBuffer(cmd->bufs[cmd->cur_queue_idx]);
915  if (ret != VK_SUCCESS) {
916  av_log(hwfc, AV_LOG_ERROR, "Unable to finish command buffer: %s\n",
917  vk_ret2str(ret));
918  unref_exec_ctx_deps(hwfc, cmd);
919  return AVERROR_EXTERNAL;
920  }
921 
922  s_info->pCommandBuffers = &cmd->bufs[cmd->cur_queue_idx];
923  s_info->commandBufferCount = 1;
924 
925  ret = vkQueueSubmit(q->queue, 1, s_info, q->fence);
926  if (ret != VK_SUCCESS) {
927  unref_exec_ctx_deps(hwfc, cmd);
928  return AVERROR_EXTERNAL;
929  }
930 
931  q->was_synchronous = synchronous;
932 
933  if (synchronous) {
934  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
935  vkWaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
936  vkResetFences(hwctx->act_dev, 1, &q->fence);
937  unref_exec_ctx_deps(hwfc, cmd);
938  } else { /* Rotate queues */
939  cmd->cur_queue_idx = (cmd->cur_queue_idx + 1) % cmd->nb_queues;
940  }
941 
942  return 0;
943 }
944 
946 {
947  VulkanDevicePriv *p = ctx->internal->priv;
948  AVVulkanDeviceContext *hwctx = ctx->hwctx;
949 
950  vkDestroyDevice(hwctx->act_dev, hwctx->alloc);
951 
952  if (p->debug_ctx) {
953  VK_LOAD_PFN(hwctx->inst, vkDestroyDebugUtilsMessengerEXT);
954  pfn_vkDestroyDebugUtilsMessengerEXT(hwctx->inst, p->debug_ctx,
955  hwctx->alloc);
956  }
957 
958  vkDestroyInstance(hwctx->inst, hwctx->alloc);
959 
960  for (int i = 0; i < hwctx->nb_enabled_inst_extensions; i++)
961  av_free((void *)hwctx->enabled_inst_extensions[i]);
962  av_free((void *)hwctx->enabled_inst_extensions);
963 
964  for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++)
965  av_free((void *)hwctx->enabled_dev_extensions[i]);
966  av_free((void *)hwctx->enabled_dev_extensions);
967 }
968 
970  VulkanDeviceSelection *dev_select,
971  AVDictionary *opts, int flags)
972 {
973  int err = 0;
974  VkResult ret;
975  AVDictionaryEntry *opt_d;
976  VulkanDevicePriv *p = ctx->internal->priv;
977  AVVulkanDeviceContext *hwctx = ctx->hwctx;
978  VkPhysicalDeviceFeatures dev_features = { 0 };
979  VkDeviceQueueCreateInfo queue_create_info[3] = {
980  { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, },
981  { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, },
982  { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, },
983  };
984 
985  VkDeviceCreateInfo dev_info = {
986  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
987  .pNext = &hwctx->device_features,
988  .pQueueCreateInfos = queue_create_info,
989  .queueCreateInfoCount = 0,
990  };
991 
992  hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
993  ctx->free = vulkan_device_free;
994 
995  /* Create an instance if not given one */
996  if ((err = create_instance(ctx, opts)))
997  goto end;
998 
999  /* Find a device (if not given one) */
1000  if ((err = find_device(ctx, dev_select)))
1001  goto end;
1002 
1003  vkGetPhysicalDeviceFeatures(hwctx->phys_dev, &dev_features);
1004 #define COPY_FEATURE(DST, NAME) (DST).features.NAME = dev_features.NAME;
1005  COPY_FEATURE(hwctx->device_features, shaderImageGatherExtended)
1006  COPY_FEATURE(hwctx->device_features, fragmentStoresAndAtomics)
1007  COPY_FEATURE(hwctx->device_features, vertexPipelineStoresAndAtomics)
1008  COPY_FEATURE(hwctx->device_features, shaderInt64)
1009 #undef COPY_FEATURE
1010 
1011  /* Search queue family */
1012  if ((err = search_queue_families(ctx, &dev_info)))
1013  goto end;
1014 
1015  if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
1016  &dev_info.enabledExtensionCount, 0))) {
1017  av_free((void *)queue_create_info[0].pQueuePriorities);
1018  av_free((void *)queue_create_info[1].pQueuePriorities);
1019  av_free((void *)queue_create_info[2].pQueuePriorities);
1020  goto end;
1021  }
1022 
1023  ret = vkCreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
1024  &hwctx->act_dev);
1025 
1026  av_free((void *)queue_create_info[0].pQueuePriorities);
1027  av_free((void *)queue_create_info[1].pQueuePriorities);
1028  av_free((void *)queue_create_info[2].pQueuePriorities);
1029 
1030  if (ret != VK_SUCCESS) {
1031  av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n",
1032  vk_ret2str(ret));
1033  for (int i = 0; i < dev_info.enabledExtensionCount; i++)
1034  av_free((void *)dev_info.ppEnabledExtensionNames[i]);
1035  av_free((void *)dev_info.ppEnabledExtensionNames);
1036  err = AVERROR_EXTERNAL;
1037  goto end;
1038  }
1039 
1040  /* Tiled images setting, use them by default */
1041  opt_d = av_dict_get(opts, "linear_images", NULL, 0);
1042  if (opt_d)
1043  p->use_linear_images = strtol(opt_d->value, NULL, 10);
1044 
1045  hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames;
1046  hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount;
1047 
1048 end:
1049  return err;
1050 }
1051 
1053 {
1054  uint32_t queue_num;
1055  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1056  VulkanDevicePriv *p = ctx->internal->priv;
1057 
1058  /* Set device extension flags */
1059  for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) {
1060  for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) {
1061  if (!strcmp(hwctx->enabled_dev_extensions[i],
1062  optional_device_exts[j].name)) {
1063  av_log(ctx, AV_LOG_VERBOSE, "Using device extension %s\n",
1064  hwctx->enabled_dev_extensions[i]);
1065  p->extensions |= optional_device_exts[j].flag;
1066  break;
1067  }
1068  }
1069  }
1070 
1071  p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1072  p->props.pNext = &p->hprops;
1073  p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
1074 
1075  vkGetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props);
1076  av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n",
1077  p->props.properties.deviceName);
1078  av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n");
1079  av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %li\n",
1080  p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
1081  av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %li\n",
1082  p->props.properties.limits.minMemoryMapAlignment);
1084  av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %li\n",
1085  p->hprops.minImportedHostPointerAlignment);
1086 
1087  p->dev_is_nvidia = (p->props.properties.vendorID == 0x10de);
1088 
1089  vkGetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &queue_num, NULL);
1090  if (!queue_num) {
1091  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1092  return AVERROR_EXTERNAL;
1093  }
1094 
1095 #define CHECK_QUEUE(type, n) \
1096 if (n >= queue_num) { \
1097  av_log(ctx, AV_LOG_ERROR, "Invalid %s queue index %i (device has %i queues)!\n", \
1098  type, n, queue_num); \
1099  return AVERROR(EINVAL); \
1100 }
1101 
1102  CHECK_QUEUE("graphics", hwctx->queue_family_index)
1103  CHECK_QUEUE("upload", hwctx->queue_family_tx_index)
1104  CHECK_QUEUE("compute", hwctx->queue_family_comp_index)
1105 
1106 #undef CHECK_QUEUE
1107 
1108  p->qfs[p->num_qfs++] = hwctx->queue_family_index;
1109  if ((hwctx->queue_family_tx_index != hwctx->queue_family_index) &&
1111  p->qfs[p->num_qfs++] = hwctx->queue_family_tx_index;
1112  if ((hwctx->queue_family_comp_index != hwctx->queue_family_index) &&
1114  p->qfs[p->num_qfs++] = hwctx->queue_family_comp_index;
1115 
1116  /* Get device capabilities */
1117  vkGetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
1118 
1119  return 0;
1120 }
1121 
1122 static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device,
1123  AVDictionary *opts, int flags)
1124 {
1125  VulkanDeviceSelection dev_select = { 0 };
1126  if (device && device[0]) {
1127  char *end = NULL;
1128  dev_select.index = strtol(device, &end, 10);
1129  if (end == device) {
1130  dev_select.index = 0;
1131  dev_select.name = device;
1132  }
1133  }
1134 
1135  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1136 }
1137 
1139  AVHWDeviceContext *src_ctx,
1140  AVDictionary *opts, int flags)
1141 {
1142  av_unused VulkanDeviceSelection dev_select = { 0 };
1143 
1144  /* If there's only one device on the system, then even if its not covered
1145  * by the following checks (e.g. non-PCIe ARM GPU), having an empty
1146  * dev_select will mean it'll get picked. */
1147  switch(src_ctx->type) {
1148 #if CONFIG_LIBDRM
1149 #if CONFIG_VAAPI
1150  case AV_HWDEVICE_TYPE_VAAPI: {
1151  AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
1152 
1153  const char *vendor = vaQueryVendorString(src_hwctx->display);
1154  if (!vendor) {
1155  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n");
1156  return AVERROR_EXTERNAL;
1157  }
1158 
1159  if (strstr(vendor, "Intel"))
1160  dev_select.vendor_id = 0x8086;
1161  if (strstr(vendor, "AMD"))
1162  dev_select.vendor_id = 0x1002;
1163 
1164  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1165  }
1166 #endif
1167  case AV_HWDEVICE_TYPE_DRM: {
1168  AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1169 
1170  drmDevice *drm_dev_info;
1171  int err = drmGetDevice(src_hwctx->fd, &drm_dev_info);
1172  if (err) {
1173  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd!\n");
1174  return AVERROR_EXTERNAL;
1175  }
1176 
1177  if (drm_dev_info->bustype == DRM_BUS_PCI)
1178  dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id;
1179 
1180  drmFreeDevice(&drm_dev_info);
1181 
1182  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1183  }
1184 #endif
1185 #if CONFIG_CUDA
1186  case AV_HWDEVICE_TYPE_CUDA: {
1187  AVHWDeviceContext *cuda_cu = src_ctx;
1188  AVCUDADeviceContext *src_hwctx = src_ctx->hwctx;
1189  AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal;
1190  CudaFunctions *cu = cu_internal->cuda_dl;
1191 
1192  int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid,
1193  cu_internal->cuda_device));
1194  if (ret < 0) {
1195  av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n");
1196  return AVERROR_EXTERNAL;
1197  }
1198 
1199  dev_select.has_uuid = 1;
1200 
1201  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1202  }
1203 #endif
1204  default:
1205  return AVERROR(ENOSYS);
1206  }
1207 }
1208 
1210  const void *hwconfig,
1211  AVHWFramesConstraints *constraints)
1212 {
1213  int count = 0;
1214  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1215  VulkanDevicePriv *p = ctx->internal->priv;
1216 
1217  for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++)
1218  count += pixfmt_is_supported(hwctx, i, p->use_linear_images);
1219 
1220 #if CONFIG_CUDA
1221  if (p->dev_is_nvidia)
1222  count++;
1223 #endif
1224 
1225  constraints->valid_sw_formats = av_malloc_array(count + 1,
1226  sizeof(enum AVPixelFormat));
1227  if (!constraints->valid_sw_formats)
1228  return AVERROR(ENOMEM);
1229 
1230  count = 0;
1231  for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++)
1232  if (pixfmt_is_supported(hwctx, i, p->use_linear_images))
1233  constraints->valid_sw_formats[count++] = i;
1234 
1235 #if CONFIG_CUDA
1236  if (p->dev_is_nvidia)
1237  constraints->valid_sw_formats[count++] = AV_PIX_FMT_CUDA;
1238 #endif
1239  constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE;
1240 
1241  constraints->min_width = 0;
1242  constraints->min_height = 0;
1243  constraints->max_width = p->props.properties.limits.maxImageDimension2D;
1244  constraints->max_height = p->props.properties.limits.maxImageDimension2D;
1245 
1246  constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat));
1247  if (!constraints->valid_hw_formats)
1248  return AVERROR(ENOMEM);
1249 
1250  constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN;
1251  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1252 
1253  return 0;
1254 }
1255 
1256 static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
1257  VkMemoryPropertyFlagBits req_flags, const void *alloc_extension,
1258  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
1259 {
1260  VkResult ret;
1261  int index = -1;
1262  VulkanDevicePriv *p = ctx->internal->priv;
1263  AVVulkanDeviceContext *dev_hwctx = ctx->hwctx;
1264  VkMemoryAllocateInfo alloc_info = {
1265  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1266  .pNext = alloc_extension,
1267  .allocationSize = req->size,
1268  };
1269 
1270  /* The vulkan spec requires memory types to be sorted in the "optimal"
1271  * order, so the first matching type we find will be the best/fastest one */
1272  for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
1273  /* The memory type must be supported by the requirements (bitfield) */
1274  if (!(req->memoryTypeBits & (1 << i)))
1275  continue;
1276 
1277  /* The memory type flags must include our properties */
1278  if ((p->mprops.memoryTypes[i].propertyFlags & req_flags) != req_flags)
1279  continue;
1280 
1281  /* Found a suitable memory type */
1282  index = i;
1283  break;
1284  }
1285 
1286  if (index < 0) {
1287  av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
1288  req_flags);
1289  return AVERROR(EINVAL);
1290  }
1291 
1292  alloc_info.memoryTypeIndex = index;
1293 
1294  ret = vkAllocateMemory(dev_hwctx->act_dev, &alloc_info,
1295  dev_hwctx->alloc, mem);
1296  if (ret != VK_SUCCESS) {
1297  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
1298  vk_ret2str(ret));
1299  return AVERROR(ENOMEM);
1300  }
1301 
1302  *mem_flags |= p->mprops.memoryTypes[index].propertyFlags;
1303 
1304  return 0;
1305 }
1306 
1308 {
1309  if (!internal)
1310  return;
1311 
1312 #if CONFIG_CUDA
1313  if (internal->cuda_fc_ref) {
1314  AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
1315  int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
1316  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
1317  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
1318  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
1319  CudaFunctions *cu = cu_internal->cuda_dl;
1320 
1321  for (int i = 0; i < planes; i++) {
1322  if (internal->cu_sem[i])
1323  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
1324  if (internal->cu_mma[i])
1325  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
1326  if (internal->ext_mem[i])
1327  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
1328  }
1329 
1330  av_buffer_unref(&internal->cuda_fc_ref);
1331  }
1332 #endif
1333 
1334  av_free(internal);
1335 }
1336 
1337 static void vulkan_frame_free(void *opaque, uint8_t *data)
1338 {
1339  AVVkFrame *f = (AVVkFrame *)data;
1340  AVHWFramesContext *hwfc = opaque;
1341  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1343 
1345 
1346  for (int i = 0; i < planes; i++) {
1347  vkDestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
1348  vkFreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
1349  vkDestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
1350  }
1351 
1352  av_free(f);
1353 }
1354 
1356  void *alloc_pnext, size_t alloc_pnext_stride)
1357 {
1358  int err;
1359  VkResult ret;
1360  AVHWDeviceContext *ctx = hwfc->device_ctx;
1361  VulkanDevicePriv *p = ctx->internal->priv;
1362  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1363  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
1364 
1365  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1366 
1367  for (int i = 0; i < planes; i++) {
1368  int use_ded_mem;
1369  VkImageMemoryRequirementsInfo2 req_desc = {
1370  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
1371  .image = f->img[i],
1372  };
1373  VkMemoryDedicatedAllocateInfo ded_alloc = {
1374  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1375  .pNext = (void *)(((uint8_t *)alloc_pnext) + i*alloc_pnext_stride),
1376  };
1377  VkMemoryDedicatedRequirements ded_req = {
1378  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
1379  };
1380  VkMemoryRequirements2 req = {
1381  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
1382  .pNext = &ded_req,
1383  };
1384 
1385  vkGetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
1386 
1387  if (f->tiling == VK_IMAGE_TILING_LINEAR)
1388  req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
1389  p->props.properties.limits.minMemoryMapAlignment);
1390 
1391  /* In case the implementation prefers/requires dedicated allocation */
1392  use_ded_mem = ded_req.prefersDedicatedAllocation |
1393  ded_req.requiresDedicatedAllocation;
1394  if (use_ded_mem)
1395  ded_alloc.image = f->img[i];
1396 
1397  /* Allocate memory */
1398  if ((err = alloc_mem(ctx, &req.memoryRequirements,
1399  f->tiling == VK_IMAGE_TILING_LINEAR ?
1400  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1401  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1402  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
1403  &f->flags, &f->mem[i])))
1404  return err;
1405 
1406  f->size[i] = req.memoryRequirements.size;
1407  bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1408  bind_info[i].image = f->img[i];
1409  bind_info[i].memory = f->mem[i];
1410  }
1411 
1412  /* Bind the allocated memory to the images */
1413  ret = vkBindImageMemory2(hwctx->act_dev, planes, bind_info);
1414  if (ret != VK_SUCCESS) {
1415  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
1416  vk_ret2str(ret));
1417  return AVERROR_EXTERNAL;
1418  }
1419 
1420  return 0;
1421 }
1422 
1423 enum PrepMode {
1427 };
1428 
1430  AVVkFrame *frame, enum PrepMode pmode)
1431 {
1432  int err;
1433  uint32_t dst_qf;
1434  VkImageLayout new_layout;
1435  VkAccessFlags new_access;
1436  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1437 
1438  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
1439 
1440  VkSubmitInfo s_info = {
1441  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1442  .pSignalSemaphores = frame->sem,
1443  .signalSemaphoreCount = planes,
1444  };
1445 
1446  VkPipelineStageFlagBits wait_st[AV_NUM_DATA_POINTERS];
1447  for (int i = 0; i < planes; i++)
1448  wait_st[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1449 
1450  switch (pmode) {
1451  case PREP_MODE_WRITE:
1452  new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1453  new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
1454  dst_qf = VK_QUEUE_FAMILY_IGNORED;
1455  break;
1456  case PREP_MODE_RO_SHADER:
1457  new_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1458  new_access = VK_ACCESS_TRANSFER_READ_BIT;
1459  dst_qf = VK_QUEUE_FAMILY_IGNORED;
1460  break;
1462  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1463  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1464  dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
1465  s_info.pWaitSemaphores = frame->sem;
1466  s_info.pWaitDstStageMask = wait_st;
1467  s_info.waitSemaphoreCount = planes;
1468  break;
1469  }
1470 
1471  if ((err = wait_start_exec_ctx(hwfc, ectx)))
1472  return err;
1473 
1474  /* Change the image layout to something more optimal for writes.
1475  * This also signals the newly created semaphore, making it usable
1476  * for synchronization */
1477  for (int i = 0; i < planes; i++) {
1478  img_bar[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1479  img_bar[i].srcAccessMask = 0x0;
1480  img_bar[i].dstAccessMask = new_access;
1481  img_bar[i].oldLayout = frame->layout[i];
1482  img_bar[i].newLayout = new_layout;
1483  img_bar[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1484  img_bar[i].dstQueueFamilyIndex = dst_qf;
1485  img_bar[i].image = frame->img[i];
1486  img_bar[i].subresourceRange.levelCount = 1;
1487  img_bar[i].subresourceRange.layerCount = 1;
1488  img_bar[i].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1489 
1490  frame->layout[i] = img_bar[i].newLayout;
1491  frame->access[i] = img_bar[i].dstAccessMask;
1492  }
1493 
1494  vkCmdPipelineBarrier(get_buf_exec_ctx(hwfc, ectx),
1495  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1496  VK_PIPELINE_STAGE_TRANSFER_BIT,
1497  0, 0, NULL, 0, NULL, planes, img_bar);
1498 
1499  return submit_exec_ctx(hwfc, ectx, &s_info, 0);
1500 }
1501 
1503  VkImageTiling tiling, VkImageUsageFlagBits usage,
1504  void *create_pnext)
1505 {
1506  int err;
1507  VkResult ret;
1508  AVHWDeviceContext *ctx = hwfc->device_ctx;
1509  VulkanDevicePriv *p = ctx->internal->priv;
1510  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1511  enum AVPixelFormat format = hwfc->sw_format;
1512  const VkFormat *img_fmts = av_vkfmt_from_pixfmt(format);
1513  const int planes = av_pix_fmt_count_planes(format);
1514 
1515  VkExportSemaphoreCreateInfo ext_sem_info = {
1516  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
1517  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1518  };
1519 
1520  VkSemaphoreCreateInfo sem_spawn = {
1521  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1522  .pNext = p->extensions & EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL,
1523  };
1524 
1526  if (!f) {
1527  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
1528  return AVERROR(ENOMEM);
1529  }
1530 
1531  /* Create the images */
1532  for (int i = 0; i < planes; i++) {
1533  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
1534  int w = hwfc->width;
1535  int h = hwfc->height;
1536  const int p_w = i > 0 ? AV_CEIL_RSHIFT(w, desc->log2_chroma_w) : w;
1537  const int p_h = i > 0 ? AV_CEIL_RSHIFT(h, desc->log2_chroma_h) : h;
1538 
1539  VkImageCreateInfo image_create_info = {
1540  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1541  .pNext = create_pnext,
1542  .imageType = VK_IMAGE_TYPE_2D,
1543  .format = img_fmts[i],
1544  .extent.width = p_w,
1545  .extent.height = p_h,
1546  .extent.depth = 1,
1547  .mipLevels = 1,
1548  .arrayLayers = 1,
1549  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
1550  .tiling = tiling,
1551  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1552  .usage = usage,
1553  .samples = VK_SAMPLE_COUNT_1_BIT,
1554  .pQueueFamilyIndices = p->qfs,
1555  .queueFamilyIndexCount = p->num_qfs,
1556  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
1557  VK_SHARING_MODE_EXCLUSIVE,
1558  };
1559 
1560  ret = vkCreateImage(hwctx->act_dev, &image_create_info,
1561  hwctx->alloc, &f->img[i]);
1562  if (ret != VK_SUCCESS) {
1563  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
1564  vk_ret2str(ret));
1565  err = AVERROR(EINVAL);
1566  goto fail;
1567  }
1568 
1569  /* Create semaphore */
1570  ret = vkCreateSemaphore(hwctx->act_dev, &sem_spawn,
1571  hwctx->alloc, &f->sem[i]);
1572  if (ret != VK_SUCCESS) {
1573  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
1574  vk_ret2str(ret));
1575  return AVERROR_EXTERNAL;
1576  }
1577 
1578  f->layout[i] = image_create_info.initialLayout;
1579  f->access[i] = 0x0;
1580  }
1581 
1582  f->flags = 0x0;
1583  f->tiling = tiling;
1584 
1585  *frame = f;
1586  return 0;
1587 
1588 fail:
1589  vulkan_frame_free(hwfc, (uint8_t *)f);
1590  return err;
1591 }
1592 
1593 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
1595  VkExternalMemoryHandleTypeFlags *comp_handle_types,
1596  VkExternalMemoryHandleTypeFlagBits *iexp,
1597  VkExternalMemoryHandleTypeFlagBits exp)
1598 {
1599  VkResult ret;
1600  AVVulkanFramesContext *hwctx = hwfc->hwctx;
1601  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
1602  VkExternalImageFormatProperties eprops = {
1603  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
1604  };
1605  VkImageFormatProperties2 props = {
1606  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
1607  .pNext = &eprops,
1608  };
1609  VkPhysicalDeviceExternalImageFormatInfo enext = {
1610  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
1611  .handleType = exp,
1612  };
1613  VkPhysicalDeviceImageFormatInfo2 pinfo = {
1614  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
1615  .pNext = !exp ? NULL : &enext,
1616  .format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0],
1617  .type = VK_IMAGE_TYPE_2D,
1618  .tiling = hwctx->tiling,
1619  .usage = hwctx->usage,
1620  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
1621  };
1622 
1623  ret = vkGetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
1624  &pinfo, &props);
1625  if (ret == VK_SUCCESS) {
1626  *iexp |= exp;
1627  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
1628  }
1629 }
1630 
1631 static AVBufferRef *vulkan_pool_alloc(void *opaque, int size)
1632 {
1633  int err;
1634  AVVkFrame *f;
1635  AVBufferRef *avbuf = NULL;
1636  AVHWFramesContext *hwfc = opaque;
1637  AVVulkanFramesContext *hwctx = hwfc->hwctx;
1639  VulkanFramesPriv *fp = hwfc->internal->priv;
1640  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
1641  VkExternalMemoryHandleTypeFlags e = 0x0;
1642 
1643  VkExternalMemoryImageCreateInfo eiinfo = {
1644  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
1645  .pNext = hwctx->create_pnext,
1646  };
1647 
1649  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
1650  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
1651 
1653  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
1654  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1655 
1656  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
1657  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
1658  eminfo[i].pNext = hwctx->alloc_pnext[i];
1659  eminfo[i].handleTypes = e;
1660  }
1661 
1662  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
1663  eiinfo.handleTypes ? &eiinfo : NULL);
1664  if (err)
1665  return NULL;
1666 
1667  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
1668  if (err)
1669  goto fail;
1670 
1671  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_WRITE);
1672  if (err)
1673  goto fail;
1674 
1675  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
1676  vulkan_frame_free, hwfc, 0);
1677  if (!avbuf)
1678  goto fail;
1679 
1680  return avbuf;
1681 
1682 fail:
1683  vulkan_frame_free(hwfc, (uint8_t *)f);
1684  return NULL;
1685 }
1686 
1688 {
1689  VulkanFramesPriv *fp = hwfc->internal->priv;
1690 
1691  free_exec_ctx(hwfc, &fp->conv_ctx);
1692  free_exec_ctx(hwfc, &fp->upload_ctx);
1693  free_exec_ctx(hwfc, &fp->download_ctx);
1694 }
1695 
1697 {
1698  int err;
1699  AVVkFrame *f;
1700  AVVulkanFramesContext *hwctx = hwfc->hwctx;
1701  VulkanFramesPriv *fp = hwfc->internal->priv;
1702  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
1704 
1705  /* Default pool flags */
1706  hwctx->tiling = hwctx->tiling ? hwctx->tiling : p->use_linear_images ?
1707  VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
1708 
1709  if (!hwctx->usage)
1710  hwctx->usage = DEFAULT_USAGE_FLAGS;
1711 
1712  err = create_exec_ctx(hwfc, &fp->conv_ctx,
1713  dev_hwctx->queue_family_comp_index,
1714  GET_QUEUE_COUNT(dev_hwctx, 0, 1, 0));
1715  if (err)
1716  goto fail;
1717 
1718  err = create_exec_ctx(hwfc, &fp->upload_ctx,
1719  dev_hwctx->queue_family_tx_index,
1720  GET_QUEUE_COUNT(dev_hwctx, 0, 0, 1));
1721  if (err)
1722  goto fail;
1723 
1724  err = create_exec_ctx(hwfc, &fp->download_ctx,
1725  dev_hwctx->queue_family_tx_index, 1);
1726  if (err)
1727  goto fail;
1728 
1729  /* Test to see if allocation will fail */
1730  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
1731  hwctx->create_pnext);
1732  if (err)
1733  goto fail;
1734 
1735  vulkan_frame_free(hwfc, (uint8_t *)f);
1736 
1737  /* If user did not specify a pool, hwfc->pool will be set to the internal one
1738  * in hwcontext.c just after this gets called */
1739  if (!hwfc->pool) {
1741  hwfc, vulkan_pool_alloc,
1742  NULL);
1743  if (!hwfc->internal->pool_internal) {
1744  err = AVERROR(ENOMEM);
1745  goto fail;
1746  }
1747  }
1748 
1749  return 0;
1750 
1751 fail:
1752  free_exec_ctx(hwfc, &fp->conv_ctx);
1753  free_exec_ctx(hwfc, &fp->upload_ctx);
1754  free_exec_ctx(hwfc, &fp->download_ctx);
1755 
1756  return err;
1757 }
1758 
1760 {
1761  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
1762  if (!frame->buf[0])
1763  return AVERROR(ENOMEM);
1764 
1765  frame->data[0] = frame->buf[0]->data;
1766  frame->format = AV_PIX_FMT_VULKAN;
1767  frame->width = hwfc->width;
1768  frame->height = hwfc->height;
1769 
1770  return 0;
1771 }
1772 
1774  enum AVHWFrameTransferDirection dir,
1775  enum AVPixelFormat **formats)
1776 {
1777  enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
1778  if (!fmts)
1779  return AVERROR(ENOMEM);
1780 
1781  fmts[0] = hwfc->sw_format;
1782  fmts[1] = AV_PIX_FMT_NONE;
1783 
1784  *formats = fmts;
1785  return 0;
1786 }
1787 
1788 typedef struct VulkanMapping {
1790  int flags;
1791 } VulkanMapping;
1792 
1794 {
1795  VulkanMapping *map = hwmap->priv;
1796  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1797  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1798 
1799  /* Check if buffer needs flushing */
1800  if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
1801  !(map->frame->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
1802  VkResult ret;
1803  VkMappedMemoryRange flush_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
1804 
1805  for (int i = 0; i < planes; i++) {
1806  flush_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1807  flush_ranges[i].memory = map->frame->mem[i];
1808  flush_ranges[i].size = VK_WHOLE_SIZE;
1809  }
1810 
1811  ret = vkFlushMappedMemoryRanges(hwctx->act_dev, planes,
1812  flush_ranges);
1813  if (ret != VK_SUCCESS) {
1814  av_log(hwfc, AV_LOG_ERROR, "Failed to flush memory: %s\n",
1815  vk_ret2str(ret));
1816  }
1817  }
1818 
1819  for (int i = 0; i < planes; i++)
1820  vkUnmapMemory(hwctx->act_dev, map->frame->mem[i]);
1821 
1822  av_free(map);
1823 }
1824 
1826  const AVFrame *src, int flags)
1827 {
1828  VkResult ret;
1829  int err, mapped_mem_count = 0;
1830  AVVkFrame *f = (AVVkFrame *)src->data[0];
1831  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1832  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1833 
1835  if (!map)
1836  return AVERROR(EINVAL);
1837 
1838  if (src->format != AV_PIX_FMT_VULKAN) {
1839  av_log(hwfc, AV_LOG_ERROR, "Cannot map from pixel format %s!\n",
1840  av_get_pix_fmt_name(src->format));
1841  err = AVERROR(EINVAL);
1842  goto fail;
1843  }
1844 
1845  if (!(f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ||
1846  !(f->tiling == VK_IMAGE_TILING_LINEAR)) {
1847  av_log(hwfc, AV_LOG_ERROR, "Unable to map frame, not host visible "
1848  "and linear!\n");
1849  err = AVERROR(EINVAL);
1850  goto fail;
1851  }
1852 
1853  dst->width = src->width;
1854  dst->height = src->height;
1855 
1856  for (int i = 0; i < planes; i++) {
1857  ret = vkMapMemory(hwctx->act_dev, f->mem[i], 0,
1858  VK_WHOLE_SIZE, 0, (void **)&dst->data[i]);
1859  if (ret != VK_SUCCESS) {
1860  av_log(hwfc, AV_LOG_ERROR, "Failed to map image memory: %s\n",
1861  vk_ret2str(ret));
1862  err = AVERROR_EXTERNAL;
1863  goto fail;
1864  }
1865  mapped_mem_count++;
1866  }
1867 
1868  /* Check if the memory contents matter */
1869  if (((flags & AV_HWFRAME_MAP_READ) || !(flags & AV_HWFRAME_MAP_OVERWRITE)) &&
1870  !(f->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
1871  VkMappedMemoryRange map_mem_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
1872  for (int i = 0; i < planes; i++) {
1873  map_mem_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1874  map_mem_ranges[i].size = VK_WHOLE_SIZE;
1875  map_mem_ranges[i].memory = f->mem[i];
1876  }
1877 
1878  ret = vkInvalidateMappedMemoryRanges(hwctx->act_dev, planes,
1879  map_mem_ranges);
1880  if (ret != VK_SUCCESS) {
1881  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
1882  vk_ret2str(ret));
1883  err = AVERROR_EXTERNAL;
1884  goto fail;
1885  }
1886  }
1887 
1888  for (int i = 0; i < planes; i++) {
1889  VkImageSubresource sub = {
1890  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1891  };
1892  VkSubresourceLayout layout;
1893  vkGetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
1894  dst->linesize[i] = layout.rowPitch;
1895  }
1896 
1897  map->frame = f;
1898  map->flags = flags;
1899 
1900  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1901  &vulkan_unmap_frame, map);
1902  if (err < 0)
1903  goto fail;
1904 
1905  return 0;
1906 
1907 fail:
1908  for (int i = 0; i < mapped_mem_count; i++)
1909  vkUnmapMemory(hwctx->act_dev, f->mem[i]);
1910 
1911  av_free(map);
1912  return err;
1913 }
1914 
1915 #if CONFIG_LIBDRM
1916 static void vulkan_unmap_from(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
1917 {
1918  VulkanMapping *map = hwmap->priv;
1919  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1920  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1921 
1922  for (int i = 0; i < planes; i++) {
1923  vkDestroyImage(hwctx->act_dev, map->frame->img[i], hwctx->alloc);
1924  vkFreeMemory(hwctx->act_dev, map->frame->mem[i], hwctx->alloc);
1925  vkDestroySemaphore(hwctx->act_dev, map->frame->sem[i], hwctx->alloc);
1926  }
1927 
1928  av_freep(&map->frame);
1929 }
1930 
1931 static const struct {
1932  uint32_t drm_fourcc;
1933  VkFormat vk_format;
1934 } vulkan_drm_format_map[] = {
1935  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
1936  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
1937  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
1938  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
1939  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
1940  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
1941  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
1942  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
1943  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
1944  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
1945 };
1946 
1947 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
1948 {
1949  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
1950  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
1951  return vulkan_drm_format_map[i].vk_format;
1952  return VK_FORMAT_UNDEFINED;
1953 }
1954 
1955 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
1957 {
1958  int err = 0;
1959  VkResult ret;
1960  AVVkFrame *f;
1961  int bind_counts = 0;
1962  AVHWDeviceContext *ctx = hwfc->device_ctx;
1963  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1964  VulkanDevicePriv *p = ctx->internal->priv;
1965  VulkanFramesPriv *fp = hwfc->internal->priv;
1966  AVVulkanFramesContext *frames_hwctx = hwfc->hwctx;
1967  const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(hwfc->sw_format);
1968  const int has_modifiers = p->extensions & EXT_DRM_MODIFIER_FLAGS;
1969  VkSubresourceLayout plane_data[AV_NUM_DATA_POINTERS] = { 0 };
1970  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { 0 };
1971  VkBindImagePlaneMemoryInfo plane_info[AV_NUM_DATA_POINTERS] = { 0 };
1972  VkExternalMemoryHandleTypeFlagBits htype = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1973 
1974  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdPropertiesKHR);
1975 
1976  for (int i = 0; i < desc->nb_layers; i++) {
1977  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
1978  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
1979  desc->layers[i].format);
1980  return AVERROR(EINVAL);
1981  }
1982  }
1983 
1984  if (!(f = av_vk_frame_alloc())) {
1985  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
1986  err = AVERROR(ENOMEM);
1987  goto fail;
1988  }
1989 
1990  f->tiling = has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
1991  desc->objects[0].format_modifier == DRM_FORMAT_MOD_LINEAR ?
1992  VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
1993 
1994  for (int i = 0; i < desc->nb_layers; i++) {
1995  const int planes = desc->layers[i].nb_planes;
1996  VkImageDrmFormatModifierExplicitCreateInfoEXT drm_info = {
1997  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
1998  .drmFormatModifier = desc->objects[0].format_modifier,
1999  .drmFormatModifierPlaneCount = planes,
2000  .pPlaneLayouts = (const VkSubresourceLayout *)&plane_data,
2001  };
2002 
2003  VkExternalMemoryImageCreateInfo einfo = {
2004  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2005  .pNext = has_modifiers ? &drm_info : NULL,
2006  .handleTypes = htype,
2007  };
2008 
2009  VkSemaphoreCreateInfo sem_spawn = {
2010  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2011  };
2012 
2013  const int p_w = i > 0 ? AV_CEIL_RSHIFT(hwfc->width, fmt_desc->log2_chroma_w) : hwfc->width;
2014  const int p_h = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, fmt_desc->log2_chroma_h) : hwfc->height;
2015 
2016  VkImageCreateInfo image_create_info = {
2017  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2018  .pNext = &einfo,
2019  .imageType = VK_IMAGE_TYPE_2D,
2020  .format = drm_to_vulkan_fmt(desc->layers[i].format),
2021  .extent.width = p_w,
2022  .extent.height = p_h,
2023  .extent.depth = 1,
2024  .mipLevels = 1,
2025  .arrayLayers = 1,
2026  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2027  .tiling = f->tiling,
2028  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
2029  .usage = frames_hwctx->usage,
2030  .samples = VK_SAMPLE_COUNT_1_BIT,
2031  .pQueueFamilyIndices = p->qfs,
2032  .queueFamilyIndexCount = p->num_qfs,
2033  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2034  VK_SHARING_MODE_EXCLUSIVE,
2035  };
2036 
2037  for (int j = 0; j < planes; j++) {
2038  plane_data[j].offset = desc->layers[i].planes[j].offset;
2039  plane_data[j].rowPitch = desc->layers[i].planes[j].pitch;
2040  plane_data[j].size = 0; /* The specs say so for all 3 */
2041  plane_data[j].arrayPitch = 0;
2042  plane_data[j].depthPitch = 0;
2043  }
2044 
2045  /* Create image */
2046  ret = vkCreateImage(hwctx->act_dev, &image_create_info,
2047  hwctx->alloc, &f->img[i]);
2048  if (ret != VK_SUCCESS) {
2049  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2050  vk_ret2str(ret));
2051  err = AVERROR(EINVAL);
2052  goto fail;
2053  }
2054 
2055  ret = vkCreateSemaphore(hwctx->act_dev, &sem_spawn,
2056  hwctx->alloc, &f->sem[i]);
2057  if (ret != VK_SUCCESS) {
2058  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2059  vk_ret2str(ret));
2060  return AVERROR_EXTERNAL;
2061  }
2062 
2063  /* We'd import a semaphore onto the one we created using
2064  * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
2065  * offer us anything we could import and sync with, so instead
2066  * just signal the semaphore we created. */
2067 
2068  f->layout[i] = image_create_info.initialLayout;
2069  f->access[i] = 0x0;
2070  }
2071 
2072  for (int i = 0; i < desc->nb_objects; i++) {
2073  int use_ded_mem = 0;
2074  VkMemoryFdPropertiesKHR fdmp = {
2075  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
2076  };
2077  VkMemoryRequirements req = {
2078  .size = desc->objects[i].size,
2079  };
2080  VkImportMemoryFdInfoKHR idesc = {
2081  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2082  .handleType = htype,
2083  .fd = dup(desc->objects[i].fd),
2084  };
2085  VkMemoryDedicatedAllocateInfo ded_alloc = {
2086  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2087  .pNext = &idesc,
2088  };
2089 
2090  ret = pfn_vkGetMemoryFdPropertiesKHR(hwctx->act_dev, htype,
2091  idesc.fd, &fdmp);
2092  if (ret != VK_SUCCESS) {
2093  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
2094  vk_ret2str(ret));
2095  err = AVERROR_EXTERNAL;
2096  close(idesc.fd);
2097  goto fail;
2098  }
2099 
2100  req.memoryTypeBits = fdmp.memoryTypeBits;
2101 
2102  /* Dedicated allocation only makes sense if there's a one to one mapping
2103  * between images and the memory backing them, so only check in this
2104  * case. */
2105  if (desc->nb_layers == desc->nb_objects) {
2106  VkImageMemoryRequirementsInfo2 req_desc = {
2107  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2108  .image = f->img[i],
2109  };
2110  VkMemoryDedicatedRequirements ded_req = {
2111  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2112  };
2113  VkMemoryRequirements2 req2 = {
2114  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2115  .pNext = &ded_req,
2116  };
2117 
2118  vkGetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
2119 
2120  use_ded_mem = ded_req.prefersDedicatedAllocation |
2121  ded_req.requiresDedicatedAllocation;
2122  if (use_ded_mem)
2123  ded_alloc.image = f->img[i];
2124  }
2125 
2126  err = alloc_mem(ctx, &req, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2127  use_ded_mem ? &ded_alloc : ded_alloc.pNext,
2128  &f->flags, &f->mem[i]);
2129  if (err) {
2130  close(idesc.fd);
2131  return err;
2132  }
2133 
2134  f->size[i] = desc->objects[i].size;
2135  }
2136 
2137  for (int i = 0; i < desc->nb_layers; i++) {
2138  const int planes = desc->layers[i].nb_planes;
2139  const int signal_p = has_modifiers && (planes > 1);
2140  for (int j = 0; j < planes; j++) {
2141  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2142  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
2143  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
2144 
2145  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
2146  plane_info[bind_counts].planeAspect = aspect;
2147 
2148  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2149  bind_info[bind_counts].pNext = signal_p ? &plane_info[bind_counts] : NULL;
2150  bind_info[bind_counts].image = f->img[i];
2151  bind_info[bind_counts].memory = f->mem[desc->layers[i].planes[j].object_index];
2152  bind_info[bind_counts].memoryOffset = desc->layers[i].planes[j].offset;
2153  bind_counts++;
2154  }
2155  }
2156 
2157  /* Bind the allocated memory to the images */
2158  ret = vkBindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
2159  if (ret != VK_SUCCESS) {
2160  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2161  vk_ret2str(ret));
2162  return AVERROR_EXTERNAL;
2163  }
2164 
2165  /* NOTE: This is completely uneccesary and unneeded once we can import
2166  * semaphores from DRM. Otherwise we have to activate the semaphores.
2167  * We're reusing the exec context that's also used for uploads/downloads. */
2168  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_RO_SHADER);
2169  if (err)
2170  goto fail;
2171 
2172  *frame = f;
2173 
2174  return 0;
2175 
2176 fail:
2177  for (int i = 0; i < desc->nb_layers; i++) {
2178  vkDestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2179  vkDestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2180  }
2181  for (int i = 0; i < desc->nb_objects; i++)
2182  vkFreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2183 
2184  av_free(f);
2185 
2186  return err;
2187 }
2188 
2189 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2190  const AVFrame *src, int flags)
2191 {
2192  int err = 0;
2193  AVVkFrame *f;
2194  VulkanMapping *map = NULL;
2195 
2196  err = vulkan_map_from_drm_frame_desc(hwfc, &f,
2197  (AVDRMFrameDescriptor *)src->data[0]);
2198  if (err)
2199  return err;
2200 
2201  /* The unmapping function will free this */
2202  dst->data[0] = (uint8_t *)f;
2203  dst->width = src->width;
2204  dst->height = src->height;
2205 
2206  map = av_mallocz(sizeof(VulkanMapping));
2207  if (!map)
2208  goto fail;
2209 
2210  map->frame = f;
2211  map->flags = flags;
2212 
2213  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2214  &vulkan_unmap_from, map);
2215  if (err < 0)
2216  goto fail;
2217 
2218  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
2219 
2220  return 0;
2221 
2222 fail:
2223  vulkan_frame_free(hwfc->device_ctx->hwctx, (uint8_t *)f);
2224  av_free(map);
2225  return err;
2226 }
2227 
2228 #if CONFIG_VAAPI
2229 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
2230  AVFrame *dst, const AVFrame *src,
2231  int flags)
2232 {
2233  int err;
2234  AVFrame *tmp = av_frame_alloc();
2236  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
2237  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
2238 
2239  if (!tmp)
2240  return AVERROR(ENOMEM);
2241 
2242  /* We have to sync since like the previous comment said, no semaphores */
2243  vaSyncSurface(vaapi_ctx->display, surface_id);
2244 
2246 
2247  err = av_hwframe_map(tmp, src, flags);
2248  if (err < 0)
2249  goto fail;
2250 
2251  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
2252  if (err < 0)
2253  goto fail;
2254 
2255  err = ff_hwframe_map_replace(dst, src);
2256 
2257 fail:
2258  av_frame_free(&tmp);
2259  return err;
2260 }
2261 #endif
2262 #endif
2263 
2264 #if CONFIG_CUDA
2265 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
2266  AVBufferRef *cuda_hwfc,
2267  const AVFrame *frame)
2268 {
2269  int err;
2270  VkResult ret;
2271  AVVkFrame *dst_f;
2272  AVVkFrameInternal *dst_int;
2273  AVHWDeviceContext *ctx = hwfc->device_ctx;
2274  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2275  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2276  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
2277  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdKHR);
2278  VK_LOAD_PFN(hwctx->inst, vkGetSemaphoreFdKHR);
2279 
2280  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
2281  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2282  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2283  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2284  CudaFunctions *cu = cu_internal->cuda_dl;
2285  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
2286  CU_AD_FORMAT_UNSIGNED_INT8;
2287 
2288  dst_f = (AVVkFrame *)frame->data[0];
2289 
2290  dst_int = dst_f->internal;
2291  if (!dst_int || !dst_int->cuda_fc_ref) {
2292  if (!dst_f->internal)
2293  dst_f->internal = dst_int = av_mallocz(sizeof(*dst_f->internal));
2294 
2295  if (!dst_int) {
2296  err = AVERROR(ENOMEM);
2297  goto fail;
2298  }
2299 
2300  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
2301  if (!dst_int->cuda_fc_ref) {
2302  err = AVERROR(ENOMEM);
2303  goto fail;
2304  }
2305 
2306  for (int i = 0; i < planes; i++) {
2307  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
2308  .offset = 0,
2309  .arrayDesc = {
2310  .Width = i > 0 ? AV_CEIL_RSHIFT(hwfc->width, desc->log2_chroma_w)
2311  : hwfc->width,
2312  .Height = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, desc->log2_chroma_h)
2313  : hwfc->height,
2314  .Depth = 0,
2315  .Format = cufmt,
2316  .NumChannels = 1 + ((planes == 2) && i),
2317  .Flags = 0,
2318  },
2319  .numLevels = 1,
2320  };
2321  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
2322  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
2323  .size = dst_f->size[i],
2324  };
2325  VkMemoryGetFdInfoKHR export_info = {
2326  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2327  .memory = dst_f->mem[i],
2328  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
2329  };
2330  VkSemaphoreGetFdInfoKHR sem_export = {
2331  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
2332  .semaphore = dst_f->sem[i],
2333  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2334  };
2335  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
2336  .type = CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD,
2337  };
2338 
2339  ret = pfn_vkGetMemoryFdKHR(hwctx->act_dev, &export_info,
2340  &ext_desc.handle.fd);
2341  if (ret != VK_SUCCESS) {
2342  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
2343  err = AVERROR_EXTERNAL;
2344  goto fail;
2345  }
2346 
2347  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
2348  if (ret < 0) {
2349  err = AVERROR_EXTERNAL;
2350  goto fail;
2351  }
2352 
2353  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
2354  dst_int->ext_mem[i],
2355  &tex_desc));
2356  if (ret < 0) {
2357  err = AVERROR_EXTERNAL;
2358  goto fail;
2359  }
2360 
2361  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
2362  dst_int->cu_mma[i], 0));
2363  if (ret < 0) {
2364  err = AVERROR_EXTERNAL;
2365  goto fail;
2366  }
2367 
2368  ret = pfn_vkGetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
2369  &ext_sem_desc.handle.fd);
2370  if (ret != VK_SUCCESS) {
2371  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
2372  vk_ret2str(ret));
2373  err = AVERROR_EXTERNAL;
2374  goto fail;
2375  }
2376 
2377  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i],
2378  &ext_sem_desc));
2379  if (ret < 0) {
2380  err = AVERROR_EXTERNAL;
2381  goto fail;
2382  }
2383  }
2384  }
2385 
2386  return 0;
2387 
2388 fail:
2389  return err;
2390 }
2391 
2392 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
2393  AVFrame *dst, const AVFrame *src)
2394 {
2395  int err;
2396  VkResult ret;
2397  CUcontext dummy;
2398  AVVkFrame *dst_f;
2399  AVVkFrameInternal *dst_int;
2400  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2401  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
2402 
2404  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2405  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2406  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2407  CudaFunctions *cu = cu_internal->cuda_dl;
2408  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
2409  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
2410 
2411  ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
2412  if (ret < 0) {
2413  err = AVERROR_EXTERNAL;
2414  goto fail;
2415  }
2416 
2417  dst_f = (AVVkFrame *)dst->data[0];
2418 
2419  ret = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
2420  if (ret < 0) {
2421  goto fail;
2422  }
2423  dst_int = dst_f->internal;
2424 
2425  ret = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
2426  planes, cuda_dev->stream));
2427  if (ret < 0) {
2428  err = AVERROR_EXTERNAL;
2429  goto fail;
2430  }
2431 
2432  for (int i = 0; i < planes; i++) {
2433  CUDA_MEMCPY2D cpy = {
2434  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
2435  .srcDevice = (CUdeviceptr)src->data[i],
2436  .srcPitch = src->linesize[i],
2437  .srcY = 0,
2438 
2439  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
2440  .dstArray = dst_int->cu_array[i],
2441  .WidthInBytes = (i > 0 ? AV_CEIL_RSHIFT(hwfc->width, desc->log2_chroma_w)
2442  : hwfc->width) * desc->comp[i].step,
2443  .Height = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, desc->log2_chroma_h)
2444  : hwfc->height,
2445  };
2446 
2447  ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
2448  if (ret < 0) {
2449  err = AVERROR_EXTERNAL;
2450  goto fail;
2451  }
2452  }
2453 
2454  ret = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
2455  planes, cuda_dev->stream));
2456  if (ret < 0) {
2457  err = AVERROR_EXTERNAL;
2458  goto fail;
2459  }
2460 
2461  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2462 
2463  av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n");
2464 
2465  return 0;
2466 
2467 fail:
2468  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2469  vulkan_free_internal(dst_int);
2470  dst_f->internal = NULL;
2471  av_buffer_unref(&dst->buf[0]);
2472  return err;
2473 }
2474 #endif
2475 
2476 static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
2477  const AVFrame *src, int flags)
2478 {
2480 
2481  switch (src->format) {
2482 #if CONFIG_LIBDRM
2483 #if CONFIG_VAAPI
2484  case AV_PIX_FMT_VAAPI:
2485  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2486  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
2487 #endif
2488  case AV_PIX_FMT_DRM_PRIME:
2489  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2490  return vulkan_map_from_drm(hwfc, dst, src, flags);
2491 #endif
2492  default:
2493  return AVERROR(ENOSYS);
2494  }
2495 }
2496 
2497 #if CONFIG_LIBDRM
2498 typedef struct VulkanDRMMapping {
2499  AVDRMFrameDescriptor drm_desc;
2500  AVVkFrame *source;
2501 } VulkanDRMMapping;
2502 
2503 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
2504 {
2505  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
2506 
2507  for (int i = 0; i < drm_desc->nb_objects; i++)
2508  close(drm_desc->objects[i].fd);
2509 
2510  av_free(drm_desc);
2511 }
2512 
2513 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
2514 {
2515  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
2516  if (vulkan_drm_format_map[i].vk_format == vkfmt)
2517  return vulkan_drm_format_map[i].drm_fourcc;
2518  return DRM_FORMAT_INVALID;
2519 }
2520 
2521 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2522  const AVFrame *src, int flags)
2523 {
2524  int err = 0;
2525  VkResult ret;
2526  AVVkFrame *f = (AVVkFrame *)src->data[0];
2528  VulkanFramesPriv *fp = hwfc->internal->priv;
2529  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2530  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2531  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdKHR);
2532  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
2533  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
2534  };
2535 
2536  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
2537  if (!drm_desc)
2538  return AVERROR(ENOMEM);
2539 
2540  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_EXPORT);
2541  if (err < 0)
2542  goto end;
2543 
2544  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
2545  if (err < 0)
2546  goto end;
2547 
2548  if (p->extensions & EXT_DRM_MODIFIER_FLAGS) {
2549  VK_LOAD_PFN(hwctx->inst, vkGetImageDrmFormatModifierPropertiesEXT);
2550  ret = pfn_vkGetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
2551  &drm_mod);
2552  if (ret != VK_SUCCESS) {
2553  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
2554  err = AVERROR_EXTERNAL;
2555  goto end;
2556  }
2557  }
2558 
2559  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
2560  VkMemoryGetFdInfoKHR export_info = {
2561  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2562  .memory = f->mem[i],
2563  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2564  };
2565 
2566  ret = pfn_vkGetMemoryFdKHR(hwctx->act_dev, &export_info,
2567  &drm_desc->objects[i].fd);
2568  if (ret != VK_SUCCESS) {
2569  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
2570  err = AVERROR_EXTERNAL;
2571  goto end;
2572  }
2573 
2574  drm_desc->nb_objects++;
2575  drm_desc->objects[i].size = f->size[i];
2576  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
2577  }
2578 
2579  drm_desc->nb_layers = planes;
2580  for (int i = 0; i < drm_desc->nb_layers; i++) {
2581  VkSubresourceLayout layout;
2582  VkImageSubresource sub = {
2583  .aspectMask = p->extensions & EXT_DRM_MODIFIER_FLAGS ?
2584  VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2585  VK_IMAGE_ASPECT_COLOR_BIT,
2586  };
2587  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
2588 
2589  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
2590  drm_desc->layers[i].nb_planes = 1;
2591 
2592  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
2593  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
2594  err = AVERROR_PATCHWELCOME;
2595  goto end;
2596  }
2597 
2598  drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
2599 
2600  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
2601  continue;
2602 
2603  vkGetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
2604  drm_desc->layers[i].planes[0].offset = layout.offset;
2605  drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
2606  }
2607 
2608  dst->width = src->width;
2609  dst->height = src->height;
2610  dst->data[0] = (uint8_t *)drm_desc;
2611 
2612  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
2613 
2614  return 0;
2615 
2616 end:
2617  av_free(drm_desc);
2618  return err;
2619 }
2620 
2621 #if CONFIG_VAAPI
2622 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
2623  const AVFrame *src, int flags)
2624 {
2625  int err;
2626  AVFrame *tmp = av_frame_alloc();
2627  if (!tmp)
2628  return AVERROR(ENOMEM);
2629 
2631 
2632  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
2633  if (err < 0)
2634  goto fail;
2635 
2636  err = av_hwframe_map(dst, tmp, flags);
2637  if (err < 0)
2638  goto fail;
2639 
2640  err = ff_hwframe_map_replace(dst, src);
2641 
2642 fail:
2643  av_frame_free(&tmp);
2644  return err;
2645 }
2646 #endif
2647 #endif
2648 
2650  const AVFrame *src, int flags)
2651 {
2653 
2654  switch (dst->format) {
2655 #if CONFIG_LIBDRM
2656  case AV_PIX_FMT_DRM_PRIME:
2657  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2658  return vulkan_map_to_drm(hwfc, dst, src, flags);
2659 #if CONFIG_VAAPI
2660  case AV_PIX_FMT_VAAPI:
2661  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2662  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
2663 #endif
2664 #endif
2665  default:
2666  return vulkan_map_frame_to_mem(hwfc, dst, src, flags);
2667  }
2668 }
2669 
2670 typedef struct ImageBuffer {
2671  VkBuffer buf;
2672  VkDeviceMemory mem;
2673  VkMemoryPropertyFlagBits flags;
2675 } ImageBuffer;
2676 
2677 static void free_buf(void *opaque, uint8_t *data)
2678 {
2679  AVHWDeviceContext *ctx = opaque;
2680  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2681  ImageBuffer *vkbuf = (ImageBuffer *)data;
2682 
2683  if (vkbuf->buf)
2684  vkDestroyBuffer(hwctx->act_dev, vkbuf->buf, hwctx->alloc);
2685  if (vkbuf->mem)
2686  vkFreeMemory(hwctx->act_dev, vkbuf->mem, hwctx->alloc);
2687 
2688  av_free(data);
2689 }
2690 
2691 static int create_buf(AVHWDeviceContext *ctx, AVBufferRef **buf, size_t imp_size,
2692  int height, int *stride, VkBufferUsageFlags usage,
2693  VkMemoryPropertyFlagBits flags, void *create_pnext,
2694  void *alloc_pnext)
2695 {
2696  int err;
2697  VkResult ret;
2698  int use_ded_mem;
2699  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2700  VulkanDevicePriv *p = ctx->internal->priv;
2701 
2702  VkBufferCreateInfo buf_spawn = {
2703  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
2704  .pNext = create_pnext,
2705  .usage = usage,
2706  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
2707  };
2708 
2709  VkBufferMemoryRequirementsInfo2 req_desc = {
2710  .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
2711  };
2712  VkMemoryDedicatedAllocateInfo ded_alloc = {
2713  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2714  .pNext = alloc_pnext,
2715  };
2716  VkMemoryDedicatedRequirements ded_req = {
2717  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2718  };
2719  VkMemoryRequirements2 req = {
2720  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2721  .pNext = &ded_req,
2722  };
2723 
2724  ImageBuffer *vkbuf = av_mallocz(sizeof(*vkbuf));
2725  if (!vkbuf)
2726  return AVERROR(ENOMEM);
2727 
2728  vkbuf->mapped_mem = !!imp_size;
2729 
2730  if (!vkbuf->mapped_mem) {
2731  *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
2732  buf_spawn.size = height*(*stride);
2733  buf_spawn.size = FFALIGN(buf_spawn.size, p->props.properties.limits.minMemoryMapAlignment);
2734  } else {
2735  buf_spawn.size = imp_size;
2736  }
2737 
2738  ret = vkCreateBuffer(hwctx->act_dev, &buf_spawn, NULL, &vkbuf->buf);
2739  if (ret != VK_SUCCESS) {
2740  av_log(ctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
2741  vk_ret2str(ret));
2742  return AVERROR_EXTERNAL;
2743  }
2744 
2745  req_desc.buffer = vkbuf->buf;
2746 
2747  vkGetBufferMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
2748 
2749  /* In case the implementation prefers/requires dedicated allocation */
2750  use_ded_mem = ded_req.prefersDedicatedAllocation |
2751  ded_req.requiresDedicatedAllocation;
2752  if (use_ded_mem)
2753  ded_alloc.buffer = vkbuf->buf;
2754 
2755  err = alloc_mem(ctx, &req.memoryRequirements, flags,
2756  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
2757  &vkbuf->flags, &vkbuf->mem);
2758  if (err)
2759  return err;
2760 
2761  ret = vkBindBufferMemory(hwctx->act_dev, vkbuf->buf, vkbuf->mem, 0);
2762  if (ret != VK_SUCCESS) {
2763  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
2764  vk_ret2str(ret));
2765  free_buf(ctx, (uint8_t *)vkbuf);
2766  return AVERROR_EXTERNAL;
2767  }
2768 
2769  *buf = av_buffer_create((uint8_t *)vkbuf, sizeof(*vkbuf), free_buf, ctx, 0);
2770  if (!(*buf)) {
2771  free_buf(ctx, (uint8_t *)vkbuf);
2772  return AVERROR(ENOMEM);
2773  }
2774 
2775  return 0;
2776 }
2777 
2778 /* Skips mapping of host mapped buffers but still invalidates them */
2780  int nb_buffers, int invalidate)
2781 {
2782  VkResult ret;
2783  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2784  VkMappedMemoryRange invalidate_ctx[AV_NUM_DATA_POINTERS];
2785  int invalidate_count = 0;
2786 
2787  for (int i = 0; i < nb_buffers; i++) {
2788  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2789  if (vkbuf->mapped_mem)
2790  continue;
2791 
2792  ret = vkMapMemory(hwctx->act_dev, vkbuf->mem, 0,
2793  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
2794  if (ret != VK_SUCCESS) {
2795  av_log(ctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
2796  vk_ret2str(ret));
2797  return AVERROR_EXTERNAL;
2798  }
2799  }
2800 
2801  if (!invalidate)
2802  return 0;
2803 
2804  for (int i = 0; i < nb_buffers; i++) {
2805  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2806  const VkMappedMemoryRange ival_buf = {
2807  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
2808  .memory = vkbuf->mem,
2809  .size = VK_WHOLE_SIZE,
2810  };
2811  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
2812  continue;
2813  invalidate_ctx[invalidate_count++] = ival_buf;
2814  }
2815 
2816  if (invalidate_count) {
2817  ret = vkInvalidateMappedMemoryRanges(hwctx->act_dev, invalidate_count,
2818  invalidate_ctx);
2819  if (ret != VK_SUCCESS)
2820  av_log(ctx, AV_LOG_WARNING, "Failed to invalidate memory: %s\n",
2821  vk_ret2str(ret));
2822  }
2823 
2824  return 0;
2825 }
2826 
2828  int nb_buffers, int flush)
2829 {
2830  int err = 0;
2831  VkResult ret;
2832  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2833  VkMappedMemoryRange flush_ctx[AV_NUM_DATA_POINTERS];
2834  int flush_count = 0;
2835 
2836  if (flush) {
2837  for (int i = 0; i < nb_buffers; i++) {
2838  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2839  const VkMappedMemoryRange flush_buf = {
2840  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
2841  .memory = vkbuf->mem,
2842  .size = VK_WHOLE_SIZE,
2843  };
2844  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
2845  continue;
2846  flush_ctx[flush_count++] = flush_buf;
2847  }
2848  }
2849 
2850  if (flush_count) {
2851  ret = vkFlushMappedMemoryRanges(hwctx->act_dev, flush_count, flush_ctx);
2852  if (ret != VK_SUCCESS) {
2853  av_log(ctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
2854  vk_ret2str(ret));
2855  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
2856  }
2857  }
2858 
2859  for (int i = 0; i < nb_buffers; i++) {
2860  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2861  if (vkbuf->mapped_mem)
2862  continue;
2863 
2864  vkUnmapMemory(hwctx->act_dev, vkbuf->mem);
2865  }
2866 
2867  return err;
2868 }
2869 
2871  AVBufferRef **bufs, const int *buf_stride, int w,
2872  int h, enum AVPixelFormat pix_fmt, int to_buf)
2873 {
2874  int err;
2875  AVVkFrame *frame = (AVVkFrame *)f->data[0];
2876  VulkanFramesPriv *fp = hwfc->internal->priv;
2877 
2878  int bar_num = 0;
2879  VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS];
2880 
2881  const int planes = av_pix_fmt_count_planes(pix_fmt);
2882  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
2883 
2884  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
2885  VulkanExecCtx *ectx = to_buf ? &fp->download_ctx : &fp->upload_ctx;
2886  VkCommandBuffer cmd_buf = get_buf_exec_ctx(hwfc, ectx);
2887 
2888  VkSubmitInfo s_info = {
2889  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
2890  .pSignalSemaphores = frame->sem,
2891  .pWaitSemaphores = frame->sem,
2892  .pWaitDstStageMask = sem_wait_dst,
2893  .signalSemaphoreCount = planes,
2894  .waitSemaphoreCount = planes,
2895  };
2896 
2897  if ((err = wait_start_exec_ctx(hwfc, ectx)))
2898  return err;
2899 
2900  /* Change the image layout to something more optimal for transfers */
2901  for (int i = 0; i < planes; i++) {
2902  VkImageLayout new_layout = to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL :
2903  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2904  VkAccessFlags new_access = to_buf ? VK_ACCESS_TRANSFER_READ_BIT :
2905  VK_ACCESS_TRANSFER_WRITE_BIT;
2906 
2907  sem_wait_dst[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2908 
2909  /* If the layout matches and we have read access skip the barrier */
2910  if ((frame->layout[i] == new_layout) && (frame->access[i] & new_access))
2911  continue;
2912 
2913  img_bar[bar_num].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2914  img_bar[bar_num].srcAccessMask = 0x0;
2915  img_bar[bar_num].dstAccessMask = new_access;
2916  img_bar[bar_num].oldLayout = frame->layout[i];
2917  img_bar[bar_num].newLayout = new_layout;
2918  img_bar[bar_num].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2919  img_bar[bar_num].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2920  img_bar[bar_num].image = frame->img[i];
2921  img_bar[bar_num].subresourceRange.levelCount = 1;
2922  img_bar[bar_num].subresourceRange.layerCount = 1;
2923  img_bar[bar_num].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2924 
2925  frame->layout[i] = img_bar[bar_num].newLayout;
2926  frame->access[i] = img_bar[bar_num].dstAccessMask;
2927 
2928  bar_num++;
2929  }
2930 
2931  if (bar_num)
2932  vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2933  VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
2934  0, NULL, 0, NULL, bar_num, img_bar);
2935 
2936  /* Schedule a copy for each plane */
2937  for (int i = 0; i < planes; i++) {
2938  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2939  const int p_w = i > 0 ? AV_CEIL_RSHIFT(w, desc->log2_chroma_w) : w;
2940  const int p_h = i > 0 ? AV_CEIL_RSHIFT(h, desc->log2_chroma_h) : h;
2941  VkBufferImageCopy buf_reg = {
2942  .bufferOffset = 0,
2943  /* Buffer stride isn't in bytes, it's in samples, the implementation
2944  * uses the image's VkFormat to know how many bytes per sample
2945  * the buffer has. So we have to convert by dividing. Stupid.
2946  * Won't work with YUVA or other planar formats with alpha. */
2947  .bufferRowLength = buf_stride[i] / desc->comp[i].step,
2948  .bufferImageHeight = p_h,
2949  .imageSubresource.layerCount = 1,
2950  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2951  .imageOffset = { 0, 0, 0, },
2952  .imageExtent = { p_w, p_h, 1, },
2953  };
2954 
2955  if (to_buf)
2956  vkCmdCopyImageToBuffer(cmd_buf, frame->img[i], frame->layout[i],
2957  vkbuf->buf, 1, &buf_reg);
2958  else
2959  vkCmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[i],
2960  frame->layout[i], 1, &buf_reg);
2961  }
2962 
2963  /* When uploading, do this asynchronously if the source is refcounted by
2964  * keeping the buffers as a submission dependency.
2965  * The hwcontext is guaranteed to not be freed until all frames are freed
2966  * in the frames_unint function.
2967  * When downloading to buffer, do this synchronously and wait for the
2968  * queue submission to finish executing */
2969  if (!to_buf) {
2970  int ref;
2971  for (ref = 0; ref < AV_NUM_DATA_POINTERS; ref++) {
2972  if (!f->buf[ref])
2973  break;
2974  if ((err = add_buf_dep_exec_ctx(hwfc, ectx, &f->buf[ref], 1)))
2975  return err;
2976  }
2977  if (ref && (err = add_buf_dep_exec_ctx(hwfc, ectx, bufs, planes)))
2978  return err;
2979  return submit_exec_ctx(hwfc, ectx, &s_info, !ref);
2980  } else {
2981  return submit_exec_ctx(hwfc, ectx, &s_info, 1);
2982  }
2983 }
2984 
2986  const AVFrame *src)
2987 {
2988  int err = 0;
2989  AVFrame tmp;
2990  AVVkFrame *f = (AVVkFrame *)dst->data[0];
2991  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
2992  AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 };
2993  const int planes = av_pix_fmt_count_planes(src->format);
2994  int log2_chroma = av_pix_fmt_desc_get(src->format)->log2_chroma_h;
2996  int host_mapped[AV_NUM_DATA_POINTERS] = { 0 };
2997  int map_host = p->extensions & EXT_EXTERNAL_HOST_MEMORY;
2998 
2999  if ((src->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(src->format))) {
3000  av_log(hwfc, AV_LOG_ERROR, "Unsupported source pixel format!\n");
3001  return AVERROR(EINVAL);
3002  }
3003 
3004  if (src->width > hwfc->width || src->height > hwfc->height)
3005  return AVERROR(EINVAL);
3006 
3007  /* For linear, host visiable images */
3008  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
3009  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
3010  AVFrame *map = av_frame_alloc();
3011  if (!map)
3012  return AVERROR(ENOMEM);
3013  map->format = src->format;
3014 
3015  err = vulkan_map_frame_to_mem(hwfc, map, dst, AV_HWFRAME_MAP_WRITE);
3016  if (err)
3017  return err;
3018 
3019  err = av_frame_copy(map, src);
3020  av_frame_free(&map);
3021  return err;
3022  }
3023 
3024  /* Create buffers */
3025  for (int i = 0; i < planes; i++) {
3026  int h = src->height;
3027  int p_height = i > 0 ? AV_CEIL_RSHIFT(h, log2_chroma) : h;
3028  size_t p_size = FFALIGN(FFABS(src->linesize[i]) * p_height,
3029  p->hprops.minImportedHostPointerAlignment);
3030 
3031  VkImportMemoryHostPointerInfoEXT import_desc = {
3032  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3033  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3034  .pHostPointer = src->data[i],
3035  };
3036 
3037  /* We can only map images with positive stride and alignment appropriate
3038  * for the device. */
3039  host_mapped[i] = map_host && src->linesize[i] > 0 &&
3040  !(((uintptr_t)import_desc.pHostPointer) %
3041  p->hprops.minImportedHostPointerAlignment);
3042  p_size = host_mapped[i] ? p_size : 0;
3043 
3044  tmp.linesize[i] = FFABS(src->linesize[i]);
3045  err = create_buf(dev_ctx, &bufs[i], p_size, p_height, &tmp.linesize[i],
3046  VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
3047  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, NULL,
3048  host_mapped[i] ? &import_desc : NULL);
3049  if (err)
3050  goto end;
3051  }
3052 
3053  /* Map, copy image to buffer, unmap */
3054  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3055  goto end;
3056 
3057  for (int i = 0; i < planes; i++) {
3058  int h = src->height;
3059  int p_height = i > 0 ? AV_CEIL_RSHIFT(h, log2_chroma) : h;
3060 
3061  if (host_mapped[i])
3062  continue;
3063 
3064  av_image_copy_plane(tmp.data[i], tmp.linesize[i],
3065  (const uint8_t *)src->data[i], src->linesize[i],
3066  FFMIN(tmp.linesize[i], FFABS(src->linesize[i])),
3067  p_height);
3068  }
3069 
3070  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3071  goto end;
3072 
3073  /* Copy buffers to image */
3074  err = transfer_image_buf(hwfc, dst, bufs, tmp.linesize,
3075  src->width, src->height, src->format, 0);
3076 
3077 end:
3078  for (int i = 0; i < planes; i++)
3079  av_buffer_unref(&bufs[i]);
3080 
3081  return err;
3082 }
3083 
3085  const AVFrame *src)
3086 {
3088 
3089  switch (src->format) {
3090 #if CONFIG_CUDA
3091  case AV_PIX_FMT_CUDA:
3092  if ((p->extensions & EXT_EXTERNAL_FD_MEMORY) &&
3093  (p->extensions & EXT_EXTERNAL_FD_SEM))
3094  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
3095 #endif
3096  default:
3097  if (src->hw_frames_ctx)
3098  return AVERROR(ENOSYS);
3099  else
3100  return vulkan_transfer_data_from_mem(hwfc, dst, src);
3101  }
3102 }
3103 
3104 #if CONFIG_CUDA
3105 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
3106  const AVFrame *src)
3107 {
3108  int err;
3109  VkResult ret;
3110  CUcontext dummy;
3111  AVVkFrame *dst_f;
3112  AVVkFrameInternal *dst_int;
3113  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3114  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
3115 
3117  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3118  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3119  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3120  CudaFunctions *cu = cu_internal->cuda_dl;
3121 
3122  ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
3123  if (ret < 0) {
3124  err = AVERROR_EXTERNAL;
3125  goto fail;
3126  }
3127 
3128  dst_f = (AVVkFrame *)src->data[0];
3129 
3130  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
3131  if (err < 0) {
3132  goto fail;
3133  }
3134 
3135  dst_int = dst_f->internal;
3136 
3137  for (int i = 0; i < planes; i++) {
3138  CUDA_MEMCPY2D cpy = {
3139  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
3140  .dstDevice = (CUdeviceptr)dst->data[i],
3141  .dstPitch = dst->linesize[i],
3142  .dstY = 0,
3143 
3144  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
3145  .srcArray = dst_int->cu_array[i],
3146  .WidthInBytes = (i > 0 ? AV_CEIL_RSHIFT(hwfc->width, desc->log2_chroma_w)
3147  : hwfc->width) * desc->comp[i].step,
3148  .Height = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, desc->log2_chroma_h)
3149  : hwfc->height,
3150  };
3151 
3152  ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
3153  if (ret < 0) {
3154  err = AVERROR_EXTERNAL;
3155  goto fail;
3156  }
3157  }
3158 
3159  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3160 
3161  av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n");
3162 
3163  return 0;
3164 
3165 fail:
3166  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3167  vulkan_free_internal(dst_int);
3168  dst_f->internal = NULL;
3169  av_buffer_unref(&dst->buf[0]);
3170  return err;
3171 }
3172 #endif
3173 
3175  const AVFrame *src)
3176 {
3177  int err = 0;
3178  AVFrame tmp;
3179  AVVkFrame *f = (AVVkFrame *)src->data[0];
3180  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
3181  AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 };
3182  const int planes = av_pix_fmt_count_planes(dst->format);
3183  int log2_chroma = av_pix_fmt_desc_get(dst->format)->log2_chroma_h;
3185  int host_mapped[AV_NUM_DATA_POINTERS] = { 0 };
3186  int map_host = p->extensions & EXT_EXTERNAL_HOST_MEMORY;
3187 
3188  if (dst->width > hwfc->width || dst->height > hwfc->height)
3189  return AVERROR(EINVAL);
3190 
3191  /* For linear, host visiable images */
3192  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
3193  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
3194  AVFrame *map = av_frame_alloc();
3195  if (!map)
3196  return AVERROR(ENOMEM);
3197  map->format = dst->format;
3198 
3199  err = vulkan_map_frame_to_mem(hwfc, map, src, AV_HWFRAME_MAP_READ);
3200  if (err)
3201  return err;
3202 
3203  err = av_frame_copy(dst, map);
3204  av_frame_free(&map);
3205  return err;
3206  }
3207 
3208  /* Create buffers */
3209  for (int i = 0; i < planes; i++) {
3210  int h = dst->height;
3211  int p_height = i > 0 ? AV_CEIL_RSHIFT(h, log2_chroma) : h;
3212  size_t p_size = FFALIGN(FFABS(dst->linesize[i]) * p_height,
3213  p->hprops.minImportedHostPointerAlignment);
3214 
3215  VkImportMemoryHostPointerInfoEXT import_desc = {
3216  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3217  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3218  .pHostPointer = dst->data[i],
3219  };
3220 
3221  /* We can only map images with positive stride and alignment appropriate
3222  * for the device. */
3223  host_mapped[i] = map_host && dst->linesize[i] > 0 &&
3224  !(((uintptr_t)import_desc.pHostPointer) %
3225  p->hprops.minImportedHostPointerAlignment);
3226  p_size = host_mapped[i] ? p_size : 0;
3227 
3228  tmp.linesize[i] = FFABS(dst->linesize[i]);
3229  err = create_buf(dev_ctx, &bufs[i], p_size, p_height,
3230  &tmp.linesize[i], VK_BUFFER_USAGE_TRANSFER_DST_BIT,
3231  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, NULL,
3232  host_mapped[i] ? &import_desc : NULL);
3233  if (err)
3234  goto end;
3235  }
3236 
3237  /* Copy image to buffer */
3238  if ((err = transfer_image_buf(hwfc, src, bufs, tmp.linesize,
3239  dst->width, dst->height, dst->format, 1)))
3240  goto end;
3241 
3242  /* Map, copy buffer to frame, unmap */
3243  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 1)))
3244  goto end;
3245 
3246  for (int i = 0; i < planes; i++) {
3247  int h = dst->height;
3248  int p_height = i > 0 ? AV_CEIL_RSHIFT(h, log2_chroma) : h;
3249 
3250  if (host_mapped[i])
3251  continue;
3252 
3253  av_image_copy_plane(dst->data[i], dst->linesize[i],
3254  (const uint8_t *)tmp.data[i], tmp.linesize[i],
3255  FFMIN(tmp.linesize[i], FFABS(dst->linesize[i])),
3256  p_height);
3257  }
3258 
3259  err = unmap_buffers(dev_ctx, bufs, planes, 0);
3260 
3261 end:
3262  for (int i = 0; i < planes; i++)
3263  av_buffer_unref(&bufs[i]);
3264 
3265  return err;
3266 }
3267 
3269  const AVFrame *src)
3270 {
3272 
3273  switch (dst->format) {
3274 #if CONFIG_CUDA
3275  case AV_PIX_FMT_CUDA:
3276  if ((p->extensions & EXT_EXTERNAL_FD_MEMORY) &&
3277  (p->extensions & EXT_EXTERNAL_FD_SEM))
3278  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
3279 #endif
3280  default:
3281  if (dst->hw_frames_ctx)
3282  return AVERROR(ENOSYS);
3283  else
3284  return vulkan_transfer_data_to_mem(hwfc, dst, src);
3285  }
3286 }
3287 
3289  AVHWFramesContext *src_fc, int flags)
3290 {
3291  return vulkan_frames_init(dst_fc);
3292 }
3293 
3295 {
3296  return av_mallocz(sizeof(AVVkFrame));
3297 }
3298 
3301  .name = "Vulkan",
3302 
3303  .device_hwctx_size = sizeof(AVVulkanDeviceContext),
3304  .device_priv_size = sizeof(VulkanDevicePriv),
3305  .frames_hwctx_size = sizeof(AVVulkanFramesContext),
3306  .frames_priv_size = sizeof(VulkanFramesPriv),
3307 
3308  .device_init = &vulkan_device_init,
3309  .device_create = &vulkan_device_create,
3310  .device_derive = &vulkan_device_derive,
3311 
3312  .frames_get_constraints = &vulkan_frames_get_constraints,
3313  .frames_init = vulkan_frames_init,
3314  .frames_get_buffer = vulkan_get_buffer,
3315  .frames_uninit = vulkan_frames_uninit,
3316 
3317  .transfer_get_formats = vulkan_transfer_get_formats,
3318  .transfer_data_to = vulkan_transfer_data_to,
3319  .transfer_data_from = vulkan_transfer_data_from,
3320 
3321  .map_to = vulkan_map_to,
3322  .map_from = vulkan_map_from,
3323  .frames_derive_to = &vulkan_frames_derive_to,
3324 
3325  .pix_fmts = (const enum AVPixelFormat []) {
3328  },
3329 };
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
#define NULL
Definition: coverity.c:32
static void vulkan_frame_free(void *opaque, uint8_t *data)
ptrdiff_t const GLvoid GLenum usage
Definition: opengl_enc.c:100
static enum AVPixelFormat pix_fmt
static void unref_exec_ctx_deps(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
#define AV_NUM_DATA_POINTERS
Definition: frame.h:309
static const char * vk_dev_type(enum VkPhysicalDeviceType type)
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:125
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2573
This structure describes decoded (raw) audio or video data.
Definition: frame.h:308
static int transfer_image_buf(AVHWFramesContext *hwfc, const AVFrame *f, AVBufferRef **bufs, const int *buf_stride, int w, int h, enum AVPixelFormat pix_fmt, int to_buf)
static int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[], int nb_buffers, int invalidate)
#define CASE(VAL)
static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *data, void *priv)
struct AVVkFrameInternal * internal
Internal data.
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static void flush(AVCodecContext *avctx)
#define LIBAVUTIL_VERSION_MAJOR
Definition: version.h:81
#define VK_LOAD_PFN(inst, name)
const char * desc
Definition: libsvtav1.c:79
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:121
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
misc image utilities
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2613
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, const char *const **dst, uint32_t *num, int debug)
VkDeviceMemory mem[AV_NUM_DATA_POINTERS]
Memory backing the images.
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:499
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:389
VulkanQueueCtx * queues
AVCUDADeviceContextInternal * internal
The mapping must be writeable.
Definition: hwcontext.h:528
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
VkDevice act_dev
Active device.
GLint GLenum type
Definition: opengl_enc.c:104
static int vulkan_map_frame_to_mem(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static const char * vk_ret2str(VkResult res)
int queue_family_tx_index
Queue family index to use for transfer operations, and the amount of queues enabled.
VulkanExecCtx download_ctx
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:239
static void free_buf(void *opaque, uint8_t *data)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate.The lists are not just lists
const HWContextType ff_hwcontext_type_vulkan
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.
AVVkFrame * frame
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:92
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:478
int nb_objects
Number of DRM objects making up this frame.
const char *const * enabled_dev_extensions
Enabled device extensions.
VkMemoryPropertyFlagBits flags
OR&#39;d flags for all memory allocated.
VkImage img[AV_NUM_DATA_POINTERS]
Vulkan images to which the memory is bound to.
VulkanExtensions
API-specific header for AV_HWDEVICE_TYPE_VAAPI.
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:647
void * create_pnext
Extension data for image creation.
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation...
#define AV_PIX_FMT_P016
Definition: pixfmt.h:449
static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static int search_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
DRM frame descriptor.
#define AV_PIX_FMT_P010
Definition: pixfmt.h:448
static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
VkPhysicalDeviceProperties2 props
#define CHECK_QUEUE(type, n)
AVBufferPool * pool_internal
static int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame, VkImageTiling tiling, VkImageUsageFlagBits usage, void *create_pnext)
enum AVHWDeviceType type
int queue_family_index
Queue family index for graphics.
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
uint8_t
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
#define f(width, name)
Definition: cbs_vp9.c:255
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
size_t size
Total size of the object.
Definition: hwcontext_drm.h:58
VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
int queue_family_comp_index
Queue family index for compute ops, and the amount of queues enabled.
static int find_device(AVHWDeviceContext *ctx, VulkanDeviceSelection *select)
static cqueue * cqueue_create(int size, int max_size)
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
#define height
AVBufferRef ** buf_deps
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
AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]
Array of layers in the frame.
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:412
const char *const * enabled_inst_extensions
Enabled instance extensions.
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
ptrdiff_t size
Definition: opengl_enc.c:100
static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req, VkMemoryPropertyFlagBits req_flags, const void *alloc_extension, VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
static int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
int fd
DRM PRIME fd for the object.
Definition: hwcontext_drm.h:52
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
#define src
Definition: vp8dsp.c:254
int nb_layers
Number of layers in the frame.
VkCommandBuffer * bufs
static const struct @323 planes[]
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor...
Definition: hwcontext_drm.h:79
int width
Definition: frame.h:366
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
VulkanExecCtx conv_ctx
static void try_export_flags(AVHWFramesContext *hwfc, VkExternalMemoryHandleTypeFlags *comp_handle_types, VkExternalMemoryHandleTypeFlagBits *iexp, VkExternalMemoryHandleTypeFlagBits exp)
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
ptrdiff_t pitch
Pitch (linesize) of this plane.
Definition: hwcontext_drm.h:87
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
#define LIBAVUTIL_VERSION_MICRO
Definition: version.h:83
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
static int wait_start_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
VkDebugUtilsMessengerEXT debug_ctx
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:385
API-specific header for AV_HWDEVICE_TYPE_VULKAN.
int nb_planes
Number of planes in the layer.
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
static int vulkan_transfer_data_to_mem(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:79
GLsizei count
Definition: opengl_enc.c:108
#define fail()
Definition: checkasm.h:123
int8_t exp
Definition: eval.c:72
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:812
static int create_buf(AVHWDeviceContext *ctx, AVBufferRef **buf, size_t imp_size, int height, int *stride, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags, void *create_pnext, void *alloc_pnext)
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
static void free_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
static int vulkan_transfer_data_from_mem(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
AVDictionary * opts
Definition: movenc.c:50
void * alloc_pnext[AV_NUM_DATA_POINTERS]
Extension data for memory allocation.
VkInstance inst
Vulkan instance.
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:383
#define FFMIN(a, b)
Definition: common.h:96
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:149
uint8_t w
Definition: llviddspenc.c:38
static const VulkanOptExtension optional_instance_exts[]
VkAccessFlagBits access[AV_NUM_DATA_POINTERS]
Updated after every barrier.
static const struct @311 vk_pixfmt_map[]
VkMemoryPropertyFlagBits flags
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
AVFormatContext * ctx
Definition: movenc.c:48
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
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
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:478
FFmpeg internal API for CUDA.
static void vulkan_free_internal(AVVkFrameInternal *internal)
VkImageUsageFlagBits usage
Defines extra usage of output frames.
int dummy
Definition: motion.c:64
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
static AVBufferRef * vulkan_pool_alloc(void *opaque, int size)
uint64_t format_modifier
Format modifier applied to the object (DRM_FORMAT_MOD_*).
Definition: hwcontext_drm.h:65
HW acceleration through CUDA.
Definition: pixfmt.h:235
AVBufferPool * av_buffer_pool_init2(int size, void *opaque, AVBufferRef *(*alloc)(void *opaque, int size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:219
#define FF_ARRAY_ELEMS(a)
static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
if(ret)
static int unmap_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, int nb_buffers, int flush)
VADisplay display
The VADisplay handle, to be filled by the user.
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:410
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:381
VulkanExecCtx upload_ctx
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:471
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
enum AVPixelFormat pixfmt
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
void * priv
Hardware-specific private data associated with the mapping.
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:534
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:431
static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:453
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:339
static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, AVVkFrame *frame, enum PrepMode pmode)
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VulkanDeviceSelection *dev_select, AVDictionary *opts, int flags)
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:675
uint8_t * data
The data buffer.
Definition: buffer.h:89
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
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:162
#define fp
Definition: regdef.h:44
static int vulkan_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, AVDictionary *opts, int flags)
This struct is allocated as AVHWDeviceContext.hwctx.
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
int index
Definition: gxfenc.c:89
DRM-managed buffers exposed through PRIME buffer sharing.
Definition: pixfmt.h:328
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
#define htype
#define GET_QUEUE_COUNT(hwctx, graph, comp, tx)
#define SEARCH_FLAGS(expr, out)
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
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
const VDPAUPixFmtMap * map
API-specific header for AV_HWDEVICE_TYPE_DRM.
AVHWFramesInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:134
const VkFormat vkfmts[3]
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:391
#define flags(name, subs,...)
Definition: cbs_av1.c:560
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:322
static int add_buf_dep_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, AVBufferRef *const *deps, int nb_deps)
VkImageTiling tiling
The same tiling must be used for all images in the frame.
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
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:428
A reference to a data buffer.
Definition: buffer.h:81
Vulkan hardware images.
Definition: pixfmt.h:356
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:104
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
static const VulkanOptExtension optional_device_exts[]
Y , 8bpp.
Definition: pixfmt.h:74
#define DEFAULT_USAGE_FLAGS
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
int fd
File descriptor of DRM device.
size_t size[AV_NUM_DATA_POINTERS]
static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, void *alloc_pnext, size_t alloc_pnext_stride)
#define LIBAVUTIL_VERSION_MINOR
Definition: version.h:82
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization semaphores.
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:789
#define ADD_VAL_TO_LIST(list, count, val)
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
static int vulkan_frames_init(AVHWFramesContext *hwfc)
static void vulkan_device_free(AVHWDeviceContext *ctx)
uint32_t format
Format of the layer (DRM_FORMAT_*).
VkPhysicalDeviceMemoryProperties mprops
uint8_t uuid[VK_UUID_SIZE]
#define CHECK_CU(x)
Definition: cuviddec.c:104
static int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags)
static int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static int vulkan_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
AVHWFrameTransferDirection
Definition: hwcontext.h:415
static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:190
#define av_free(p)
char * value
Definition: dict.h:87
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
AVVkFrame * av_vk_frame_alloc(void)
Allocates a single AVVkFrame and initializes everything as 0.
static int pixfmt_is_supported(AVVulkanDeviceContext *hwctx, enum AVPixelFormat p, int linear)
VkDeviceMemory mem
static int vulkan_device_init(AVHWDeviceContext *ctx)
ptrdiff_t offset
Offset within that object of this plane.
Definition: hwcontext_drm.h:83
static int submit_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, VkSubmitInfo *s_info, int synchronous)
static void vulkan_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
VAAPI connection details.
VkPhysicalDevice phys_dev
Physical device.
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:386
VkImageLayout layout[AV_NUM_DATA_POINTERS]
number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of...
Definition: pixfmt.h:363
VkImageTiling tiling
Controls the tiling of allocated frames.
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition: hwcontext.h:104
int height
Definition: frame.h:366
#define av_freep(p)
static float sub(float src0, float src1)
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:338
The mapping must be readable.
Definition: hwcontext.h:524
#define av_malloc_array(a, b)
formats
Definition: signature.h:48
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:373
AVHWDeviceInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:71
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:2489
VkCommandPool pool
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
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
int depth
Number of bits in the component.
Definition: pixdesc.h:58
static int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues)
#define ADD_QUEUE(fidx, graph, comp, tx)
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
#define COPY_FEATURE(DST, NAME)
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:411
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
int i
Definition: input.c:407
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
#define av_unused
Definition: attributes.h:131
int step
Number of elements between 2 horizontally consecutive pixels.
Definition: pixdesc.h:41
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:190
static uint8_t tmp[11]
Definition: aes_ctr.c:26