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