FFmpeg  4.3.9
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 = FFABS(src->linesize[i]) * p_height;
3029 
3030  VkImportMemoryHostPointerInfoEXT import_desc = {
3031  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3032  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3033  .pHostPointer = src->data[i],
3034  };
3035 
3036  /* We can only map images with positive stride and alignment appropriate
3037  * for the device. */
3038  host_mapped[i] = map_host && src->linesize[i] > 0 &&
3039  !(p_size % p->hprops.minImportedHostPointerAlignment) &&
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 = FFABS(dst->linesize[i]) * p_height;
3213 
3214  VkImportMemoryHostPointerInfoEXT import_desc = {
3215  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3216  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3217  .pHostPointer = dst->data[i],
3218  };
3219 
3220  /* We can only map images with positive stride and alignment appropriate
3221  * for the device. */
3222  host_mapped[i] = map_host && dst->linesize[i] > 0 &&
3223  !(p_size % p->hprops.minImportedHostPointerAlignment) &&
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)
static enum AVPixelFormat pix_fmt
static void unref_exec_ctx_deps(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
#define AV_NUM_DATA_POINTERS
Definition: frame.h:301
static const char * vk_dev_type(enum VkPhysicalDeviceType type)
static const char * format[]
Definition: af_aiir.c:339
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
int size
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2549
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
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.
static void flush(AVCodecContext *avctx)
#define LIBAVUTIL_VERSION_MAJOR
Definition: version.h:81
#define VK_LOAD_PFN(inst, name)
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:182
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2589
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:491
const char * desc
Definition: nvenc.c:79
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:387
VulkanQueueCtx * queues
AVCUDADeviceContextInternal * internal
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
VkDevice act_dev
Active device.
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
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:239
static void free_buf(void *opaque, uint8_t *data)
const HWContextType ff_hwcontext_type_vulkan
int stride
Definition: mace.c:144
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:639
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:447
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:446
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
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:534
#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
static AVFrame * frame
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
const char data[16]
Definition: mxf.c:91
#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:192
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:410
const char *const * enabled_inst_extensions
Enabled instance extensions.
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
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
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:358
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
VulkanExecCtx conv_ctx
#define AVERROR(e)
Definition: error.h:43
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:197
#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:383
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
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
The mapping must be readable.
Definition: hwcontext.h:524
#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:800
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
static const struct @315 planes[]
void * alloc_pnext[AV_NUM_DATA_POINTERS]
Extension data for memory allocation.
VkInstance inst
Vulkan instance.
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:381
#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.
VkMemoryPropertyFlagBits flags
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
AVFormatContext * ctx
Definition: movenc.c:48
#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
static const struct @303 vk_pixfmt_map[]
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:218
#define FF_ARRAY_ELEMS(a)
static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
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:408
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:373
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:187
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.
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:429
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:331
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:671
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
The mapping must be writeable.
Definition: hwcontext.h:528
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)
cl_device_type type
#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:389
#define flags(name, subs,...)
Definition: cbs_av1.c:576
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:314
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:184
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:426
A reference to a data buffer.
Definition: buffer.h:81
Vulkan hardware images.
Definition: pixfmt.h:356
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
if(ret< 0)
Definition: vf_mcdeint.c:279
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)
static void usage(const char *program_name)
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.
uint64_t layout
VkPhysicalDevice phys_dev
Physical device.
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:384
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:361
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:358
#define av_freep(p)
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:343
#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:338
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:2465
VkCommandPool pool
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
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:409
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)
Allocate a memory block for an array with av_mallocz().
Definition: mem.c:190
static uint8_t tmp[11]
Definition: aes_ctr.c:26