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;
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  if (internal->cu_sem)
1046  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem));
1047 
1048  for (int i = 0; i < planes; i++) {
1049  if (internal->cu_mma[i])
1050  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
1051  if (internal->ext_mem[i])
1052  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
1053  }
1054 
1055  av_buffer_unref(&internal->cuda_fc_ref);
1056  }
1057 #endif
1058 
1059  av_free(internal);
1060 }
1061 
1062 static void vulkan_frame_free(void *opaque, uint8_t *data)
1063 {
1064  AVVkFrame *f = (AVVkFrame *)data;
1065  AVHWFramesContext *hwfc = opaque;
1066  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1068 
1070 
1071  for (int i = 0; i < planes; i++) {
1072  vkDestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
1073  vkFreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
1074  }
1075 
1076  vkDestroySemaphore(hwctx->act_dev, f->sem, hwctx->alloc);
1077 
1078  av_free(f);
1079 }
1080 
1082  void *alloc_pnext, size_t alloc_pnext_stride)
1083 {
1084  int err;
1085  VkResult ret;
1086  AVHWDeviceContext *ctx = hwfc->device_ctx;
1087  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1088  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
1089 
1090  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1091 
1092  for (int i = 0; i < planes; i++) {
1093  int use_ded_mem;
1094  VkImageMemoryRequirementsInfo2 req_desc = {
1095  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
1096  .image = f->img[i],
1097  };
1098  VkMemoryDedicatedAllocateInfo ded_alloc = {
1099  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1100  .pNext = (void *)(((uint8_t *)alloc_pnext) + i*alloc_pnext_stride),
1101  };
1102  VkMemoryDedicatedRequirements ded_req = {
1103  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
1104  };
1105  VkMemoryRequirements2 req = {
1106  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
1107  .pNext = &ded_req,
1108  };
1109 
1110  vkGetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
1111 
1112  /* In case the implementation prefers/requires dedicated allocation */
1113  use_ded_mem = ded_req.prefersDedicatedAllocation |
1114  ded_req.requiresDedicatedAllocation;
1115  if (use_ded_mem)
1116  ded_alloc.image = f->img[i];
1117 
1118  /* Allocate memory */
1119  if ((err = alloc_mem(ctx, &req.memoryRequirements,
1120  f->tiling == VK_IMAGE_TILING_LINEAR ?
1121  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1122  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1123  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
1124  &f->flags, &f->mem[i])))
1125  return err;
1126 
1127  f->size[i] = req.memoryRequirements.size;
1128  bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1129  bind_info[i].image = f->img[i];
1130  bind_info[i].memory = f->mem[i];
1131  }
1132 
1133  /* Bind the allocated memory to the images */
1134  ret = vkBindImageMemory2(hwctx->act_dev, planes, bind_info);
1135  if (ret != VK_SUCCESS) {
1136  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
1137  vk_ret2str(ret));
1138  return AVERROR_EXTERNAL;
1139  }
1140 
1141  return 0;
1142 }
1143 
1144 enum PrepMode {
1147 };
1148 
1150  AVVkFrame *frame, enum PrepMode pmode)
1151 {
1152  VkResult ret;
1153  VkImageLayout new_layout;
1154  VkAccessFlags new_access;
1155  AVHWDeviceContext *ctx = hwfc->device_ctx;
1156  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1157  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1158 
1159  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
1160 
1161  VkCommandBufferBeginInfo cmd_start = {
1162  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1163  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1164  };
1165 
1166  VkSubmitInfo s_info = {
1167  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1168  .commandBufferCount = 1,
1169  .pCommandBuffers = &ectx->buf,
1170 
1171  .pSignalSemaphores = &frame->sem,
1172  .signalSemaphoreCount = 1,
1173  };
1174 
1175  switch (pmode) {
1176  case PREP_MODE_WRITE:
1177  new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1178  new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
1179  break;
1180  case PREP_MODE_RO_SHADER:
1181  new_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1182  new_access = VK_ACCESS_TRANSFER_READ_BIT;
1183  break;
1184  }
1185 
1186  ret = vkBeginCommandBuffer(ectx->buf, &cmd_start);
1187  if (ret != VK_SUCCESS)
1188  return AVERROR_EXTERNAL;
1189 
1190  /* Change the image layout to something more optimal for writes.
1191  * This also signals the newly created semaphore, making it usable
1192  * for synchronization */
1193  for (int i = 0; i < planes; i++) {
1194  img_bar[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1195  img_bar[i].srcAccessMask = 0x0;
1196  img_bar[i].dstAccessMask = new_access;
1197  img_bar[i].oldLayout = frame->layout[i];
1198  img_bar[i].newLayout = new_layout;
1199  img_bar[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1200  img_bar[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1201  img_bar[i].image = frame->img[i];
1202  img_bar[i].subresourceRange.levelCount = 1;
1203  img_bar[i].subresourceRange.layerCount = 1;
1204  img_bar[i].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1205 
1206  frame->layout[i] = img_bar[i].newLayout;
1207  frame->access[i] = img_bar[i].dstAccessMask;
1208  }
1209 
1210  vkCmdPipelineBarrier(ectx->buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1211  VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
1212  0, NULL, 0, NULL, planes, img_bar);
1213 
1214  ret = vkEndCommandBuffer(ectx->buf);
1215  if (ret != VK_SUCCESS)
1216  return AVERROR_EXTERNAL;
1217 
1218  ret = vkQueueSubmit(ectx->queue, 1, &s_info, ectx->fence);
1219  if (ret != VK_SUCCESS) {
1220  return AVERROR_EXTERNAL;
1221  } else {
1222  vkWaitForFences(hwctx->act_dev, 1, &ectx->fence, VK_TRUE, UINT64_MAX);
1223  vkResetFences(hwctx->act_dev, 1, &ectx->fence);
1224  }
1225 
1226  return 0;
1227 }
1228 
1230  VkImageTiling tiling, VkImageUsageFlagBits usage,
1231  void *create_pnext)
1232 {
1233  int err;
1234  VkResult ret;
1235  AVHWDeviceContext *ctx = hwfc->device_ctx;
1236  VulkanDevicePriv *p = ctx->internal->priv;
1237  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1238  enum AVPixelFormat format = hwfc->sw_format;
1239  const VkFormat *img_fmts = av_vkfmt_from_pixfmt(format);
1240  const int planes = av_pix_fmt_count_planes(format);
1241 
1242  VkExportSemaphoreCreateInfo ext_sem_info = {
1243  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
1244  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1245  };
1246 
1247  VkSemaphoreCreateInfo sem_spawn = {
1248  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1249  .pNext = p->extensions & EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL,
1250  };
1251 
1253  if (!f) {
1254  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
1255  return AVERROR(ENOMEM);
1256  }
1257 
1258  /* Create the images */
1259  for (int i = 0; i < planes; i++) {
1260  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
1261  int w = hwfc->width;
1262  int h = hwfc->height;
1263  const int p_w = i > 0 ? AV_CEIL_RSHIFT(w, desc->log2_chroma_w) : w;
1264  const int p_h = i > 0 ? AV_CEIL_RSHIFT(h, desc->log2_chroma_h) : h;
1265 
1266  VkImageCreateInfo image_create_info = {
1267  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1268  .pNext = create_pnext,
1269  .imageType = VK_IMAGE_TYPE_2D,
1270  .format = img_fmts[i],
1271  .extent.width = p_w,
1272  .extent.height = p_h,
1273  .extent.depth = 1,
1274  .mipLevels = 1,
1275  .arrayLayers = 1,
1276  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
1277  .tiling = tiling,
1278  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1279  .usage = usage,
1280  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
1281  .samples = VK_SAMPLE_COUNT_1_BIT,
1282  };
1283 
1284  ret = vkCreateImage(hwctx->act_dev, &image_create_info,
1285  hwctx->alloc, &f->img[i]);
1286  if (ret != VK_SUCCESS) {
1287  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
1288  vk_ret2str(ret));
1289  err = AVERROR(EINVAL);
1290  goto fail;
1291  }
1292 
1293  f->layout[i] = image_create_info.initialLayout;
1294  f->access[i] = 0x0;
1295  }
1296 
1297  /* Create semaphore */
1298  ret = vkCreateSemaphore(hwctx->act_dev, &sem_spawn,
1299  hwctx->alloc, &f->sem);
1300  if (ret != VK_SUCCESS) {
1301  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
1302  vk_ret2str(ret));
1303  return AVERROR_EXTERNAL;
1304  }
1305 
1306  f->flags = 0x0;
1307  f->tiling = tiling;
1308 
1309  *frame = f;
1310  return 0;
1311 
1312 fail:
1313  vulkan_frame_free(hwfc, (uint8_t *)f);
1314  return err;
1315 }
1316 
1317 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
1319  VkExternalMemoryHandleTypeFlags *comp_handle_types,
1320  VkExternalMemoryHandleTypeFlagBits *iexp,
1321  VkExternalMemoryHandleTypeFlagBits exp)
1322 {
1323  VkResult ret;
1324  AVVulkanFramesContext *hwctx = hwfc->hwctx;
1325  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
1326  VkExternalImageFormatProperties eprops = {
1327  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
1328  };
1329  VkImageFormatProperties2 props = {
1330  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
1331  .pNext = &eprops,
1332  };
1333  VkPhysicalDeviceExternalImageFormatInfo enext = {
1334  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
1335  .handleType = exp,
1336  };
1337  VkPhysicalDeviceImageFormatInfo2 pinfo = {
1338  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
1339  .pNext = !exp ? NULL : &enext,
1340  .format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0],
1341  .type = VK_IMAGE_TYPE_2D,
1342  .tiling = hwctx->tiling,
1343  .usage = hwctx->usage,
1344  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
1345  };
1346 
1347  ret = vkGetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
1348  &pinfo, &props);
1349  if (ret == VK_SUCCESS) {
1350  *iexp |= exp;
1351  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
1352  }
1353 }
1354 
1355 static AVBufferRef *vulkan_pool_alloc(void *opaque, int size)
1356 {
1357  int err;
1358  AVVkFrame *f;
1359  AVBufferRef *avbuf = NULL;
1360  AVHWFramesContext *hwfc = opaque;
1361  AVVulkanFramesContext *hwctx = hwfc->hwctx;
1363  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
1364  VkExternalMemoryHandleTypeFlags e = 0x0;
1365 
1366  VkExternalMemoryImageCreateInfo eiinfo = {
1367  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
1368  .pNext = hwctx->create_pnext,
1369  };
1370 
1372  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
1373  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
1374 
1376  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
1377  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1378 
1379  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
1380  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
1381  eminfo[i].pNext = hwctx->alloc_pnext[i];
1382  eminfo[i].handleTypes = e;
1383  }
1384 
1385  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
1386  eiinfo.handleTypes ? &eiinfo : NULL);
1387  if (err)
1388  return NULL;
1389 
1390  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
1391  if (err)
1392  goto fail;
1393 
1394  err = prepare_frame(hwfc, &p->cmd, f, PREP_MODE_WRITE);
1395  if (err)
1396  goto fail;
1397 
1398  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
1399  vulkan_frame_free, hwfc, 0);
1400  if (!avbuf)
1401  goto fail;
1402 
1403  return avbuf;
1404 
1405 fail:
1406  vulkan_frame_free(hwfc, (uint8_t *)f);
1407  return NULL;
1408 }
1409 
1411 {
1412  VulkanFramesPriv *fp = hwfc->internal->priv;
1413 
1414  free_exec_ctx(hwfc->device_ctx, &fp->cmd);
1415 }
1416 
1418 {
1419  int err;
1420  AVVkFrame *f;
1421  AVVulkanFramesContext *hwctx = hwfc->hwctx;
1422  VulkanFramesPriv *fp = hwfc->internal->priv;
1423  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
1425 
1426  if (hwfc->pool)
1427  return 0;
1428 
1429  /* Default pool flags */
1430  hwctx->tiling = hwctx->tiling ? hwctx->tiling : p->use_linear_images ?
1431  VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
1432 
1433  hwctx->usage |= DEFAULT_USAGE_FLAGS;
1434 
1435  err = create_exec_ctx(hwfc->device_ctx, &fp->cmd,
1436  dev_hwctx->queue_family_tx_index);
1437  if (err)
1438  return err;
1439 
1440  /* Test to see if allocation will fail */
1441  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
1442  hwctx->create_pnext);
1443  if (err) {
1444  free_exec_ctx(hwfc->device_ctx, &p->cmd);
1445  return err;
1446  }
1447 
1448  vulkan_frame_free(hwfc, (uint8_t *)f);
1449 
1451  hwfc, vulkan_pool_alloc,
1452  NULL);
1453  if (!hwfc->internal->pool_internal) {
1454  free_exec_ctx(hwfc->device_ctx, &p->cmd);
1455  return AVERROR(ENOMEM);
1456  }
1457 
1458  return 0;
1459 }
1460 
1462 {
1463  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
1464  if (!frame->buf[0])
1465  return AVERROR(ENOMEM);
1466 
1467  frame->data[0] = frame->buf[0]->data;
1468  frame->format = AV_PIX_FMT_VULKAN;
1469  frame->width = hwfc->width;
1470  frame->height = hwfc->height;
1471 
1472  return 0;
1473 }
1474 
1476  enum AVHWFrameTransferDirection dir,
1477  enum AVPixelFormat **formats)
1478 {
1479  enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
1480  if (!fmts)
1481  return AVERROR(ENOMEM);
1482 
1483  fmts[0] = hwfc->sw_format;
1484  fmts[1] = AV_PIX_FMT_NONE;
1485 
1486  *formats = fmts;
1487  return 0;
1488 }
1489 
1490 typedef struct VulkanMapping {
1492  int flags;
1493 } VulkanMapping;
1494 
1496 {
1497  VulkanMapping *map = hwmap->priv;
1498  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1499  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1500 
1501  /* Check if buffer needs flushing */
1502  if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
1503  !(map->frame->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
1504  VkResult ret;
1505  VkMappedMemoryRange flush_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
1506 
1507  for (int i = 0; i < planes; i++) {
1508  flush_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1509  flush_ranges[i].memory = map->frame->mem[i];
1510  flush_ranges[i].size = VK_WHOLE_SIZE;
1511  }
1512 
1513  ret = vkFlushMappedMemoryRanges(hwctx->act_dev, planes,
1514  flush_ranges);
1515  if (ret != VK_SUCCESS) {
1516  av_log(hwfc, AV_LOG_ERROR, "Failed to flush memory: %s\n",
1517  vk_ret2str(ret));
1518  }
1519  }
1520 
1521  for (int i = 0; i < planes; i++)
1522  vkUnmapMemory(hwctx->act_dev, map->frame->mem[i]);
1523 
1524  av_free(map);
1525 }
1526 
1528  const AVFrame *src, int flags)
1529 {
1530  VkResult ret;
1531  int err, mapped_mem_count = 0;
1532  AVVkFrame *f = (AVVkFrame *)src->data[0];
1533  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1534  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1535 
1537  if (!map)
1538  return AVERROR(EINVAL);
1539 
1540  if (src->format != AV_PIX_FMT_VULKAN) {
1541  av_log(hwfc, AV_LOG_ERROR, "Cannot map from pixel format %s!\n",
1542  av_get_pix_fmt_name(src->format));
1543  err = AVERROR(EINVAL);
1544  goto fail;
1545  }
1546 
1547  if (!(f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ||
1548  !(f->tiling == VK_IMAGE_TILING_LINEAR)) {
1549  av_log(hwfc, AV_LOG_ERROR, "Unable to map frame, not host visible "
1550  "and linear!\n");
1551  err = AVERROR(EINVAL);
1552  goto fail;
1553  }
1554 
1555  dst->width = src->width;
1556  dst->height = src->height;
1557 
1558  for (int i = 0; i < planes; i++) {
1559  ret = vkMapMemory(hwctx->act_dev, f->mem[i], 0,
1560  VK_WHOLE_SIZE, 0, (void **)&dst->data[i]);
1561  if (ret != VK_SUCCESS) {
1562  av_log(hwfc, AV_LOG_ERROR, "Failed to map image memory: %s\n",
1563  vk_ret2str(ret));
1564  err = AVERROR_EXTERNAL;
1565  goto fail;
1566  }
1567  mapped_mem_count++;
1568  }
1569 
1570  /* Check if the memory contents matter */
1571  if (((flags & AV_HWFRAME_MAP_READ) || !(flags & AV_HWFRAME_MAP_OVERWRITE)) &&
1572  !(f->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
1573  VkMappedMemoryRange map_mem_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
1574  for (int i = 0; i < planes; i++) {
1575  map_mem_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1576  map_mem_ranges[i].size = VK_WHOLE_SIZE;
1577  map_mem_ranges[i].memory = f->mem[i];
1578  }
1579 
1580  ret = vkInvalidateMappedMemoryRanges(hwctx->act_dev, planes,
1581  map_mem_ranges);
1582  if (ret != VK_SUCCESS) {
1583  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
1584  vk_ret2str(ret));
1585  err = AVERROR_EXTERNAL;
1586  goto fail;
1587  }
1588  }
1589 
1590  for (int i = 0; i < planes; i++) {
1591  VkImageSubresource sub = {
1592  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1593  };
1594  VkSubresourceLayout layout;
1595  vkGetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
1596  dst->linesize[i] = layout.rowPitch;
1597  }
1598 
1599  map->frame = f;
1600  map->flags = flags;
1601 
1602  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1603  &vulkan_unmap_frame, map);
1604  if (err < 0)
1605  goto fail;
1606 
1607  return 0;
1608 
1609 fail:
1610  for (int i = 0; i < mapped_mem_count; i++)
1611  vkUnmapMemory(hwctx->act_dev, f->mem[i]);
1612 
1613  av_free(map);
1614  return err;
1615 }
1616 
1617 #if CONFIG_LIBDRM
1618 static void vulkan_unmap_from(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
1619 {
1620  VulkanMapping *map = hwmap->priv;
1621  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1622  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1623 
1624  for (int i = 0; i < planes; i++) {
1625  vkDestroyImage(hwctx->act_dev, map->frame->img[i], hwctx->alloc);
1626  vkFreeMemory(hwctx->act_dev, map->frame->mem[i], hwctx->alloc);
1627  }
1628 
1629  vkDestroySemaphore(hwctx->act_dev, map->frame->sem, hwctx->alloc);
1630 
1631  av_freep(&map->frame);
1632 }
1633 
1634 static const struct {
1635  uint32_t drm_fourcc;
1636  VkFormat vk_format;
1637 } vulkan_drm_format_map[] = {
1638  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
1639  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
1640  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
1641  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
1642  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
1643  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
1644  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
1645  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
1646  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
1647  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
1648 };
1649 
1650 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
1651 {
1652  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
1653  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
1654  return vulkan_drm_format_map[i].vk_format;
1655  return VK_FORMAT_UNDEFINED;
1656 }
1657 
1658 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
1660 {
1661  int err = 0;
1662  VkResult ret;
1663  AVVkFrame *f;
1664  int bind_counts = 0;
1665  AVHWDeviceContext *ctx = hwfc->device_ctx;
1666  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1667  VulkanDevicePriv *p = ctx->internal->priv;
1668  const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(hwfc->sw_format);
1669  const int has_modifiers = p->extensions & EXT_DRM_MODIFIER_FLAGS;
1670  VkSubresourceLayout plane_data[AV_NUM_DATA_POINTERS] = { 0 };
1671  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { 0 };
1672  VkBindImagePlaneMemoryInfo plane_info[AV_NUM_DATA_POINTERS] = { 0 };
1673  VkExternalMemoryHandleTypeFlagBits htype = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1674  VkSemaphoreCreateInfo sem_spawn = {
1675  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1676  };
1677 
1678  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdPropertiesKHR);
1679 
1680  for (int i = 0; i < desc->nb_layers; i++) {
1681  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
1682  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
1683  desc->layers[i].format);
1684  return AVERROR(EINVAL);
1685  }
1686  }
1687 
1688  if (!(f = av_vk_frame_alloc())) {
1689  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
1690  err = AVERROR(ENOMEM);
1691  goto fail;
1692  }
1693 
1694  for (int i = 0; i < desc->nb_objects; i++) {
1695  VkMemoryFdPropertiesKHR fdmp = {
1696  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
1697  };
1698  VkMemoryRequirements req = {
1699  .size = desc->objects[i].size,
1700  };
1701  VkImportMemoryFdInfoKHR idesc = {
1702  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
1703  .handleType = htype,
1704  .fd = dup(desc->objects[i].fd),
1705  };
1706 
1707  ret = pfn_vkGetMemoryFdPropertiesKHR(hwctx->act_dev, htype,
1708  idesc.fd, &fdmp);
1709  if (ret != VK_SUCCESS) {
1710  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
1711  vk_ret2str(ret));
1712  err = AVERROR_EXTERNAL;
1713  close(idesc.fd);
1714  goto fail;
1715  }
1716 
1717  req.memoryTypeBits = fdmp.memoryTypeBits;
1718 
1719  err = alloc_mem(ctx, &req, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1720  &idesc, &f->flags, &f->mem[i]);
1721  if (err) {
1722  close(idesc.fd);
1723  return err;
1724  }
1725 
1726  f->size[i] = desc->objects[i].size;
1727  }
1728 
1729  f->tiling = has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
1730  desc->objects[0].format_modifier == DRM_FORMAT_MOD_LINEAR ?
1731  VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
1732 
1733  for (int i = 0; i < desc->nb_layers; i++) {
1734  const int planes = desc->layers[i].nb_planes;
1735  const int signal_p = has_modifiers && (planes > 1);
1736 
1737  VkImageDrmFormatModifierExplicitCreateInfoEXT drm_info = {
1738  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
1739  .drmFormatModifier = desc->objects[0].format_modifier,
1740  .drmFormatModifierPlaneCount = planes,
1741  .pPlaneLayouts = (const VkSubresourceLayout *)&plane_data,
1742  };
1743 
1744  VkExternalMemoryImageCreateInfo einfo = {
1745  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
1746  .pNext = has_modifiers ? &drm_info : NULL,
1747  .handleTypes = htype,
1748  };
1749 
1750  const int p_w = i > 0 ? AV_CEIL_RSHIFT(hwfc->width, fmt_desc->log2_chroma_w) : hwfc->width;
1751  const int p_h = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, fmt_desc->log2_chroma_h) : hwfc->height;
1752 
1753  VkImageCreateInfo image_create_info = {
1754  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1755  .pNext = &einfo,
1756  .imageType = VK_IMAGE_TYPE_2D,
1757  .format = drm_to_vulkan_fmt(desc->layers[i].format),
1758  .extent.width = p_w,
1759  .extent.height = p_h,
1760  .extent.depth = 1,
1761  .mipLevels = 1,
1762  .arrayLayers = 1,
1763  .flags = VK_IMAGE_CREATE_ALIAS_BIT |
1764  (signal_p ? VK_IMAGE_CREATE_DISJOINT_BIT : 0x0),
1765  .tiling = f->tiling,
1766  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
1767  .usage = DEFAULT_USAGE_FLAGS,
1768  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
1769  .samples = VK_SAMPLE_COUNT_1_BIT,
1770  };
1771 
1772  for (int j = 0; j < planes; j++) {
1773  plane_data[j].offset = desc->layers[i].planes[j].offset;
1774  plane_data[j].rowPitch = desc->layers[i].planes[j].pitch;
1775  plane_data[j].size = 0; /* The specs say so for all 3 */
1776  plane_data[j].arrayPitch = 0;
1777  plane_data[j].depthPitch = 0;
1778  }
1779 
1780  /* Create image */
1781  ret = vkCreateImage(hwctx->act_dev, &image_create_info,
1782  hwctx->alloc, &f->img[i]);
1783  if (ret != VK_SUCCESS) {
1784  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
1785  vk_ret2str(ret));
1786  err = AVERROR(EINVAL);
1787  goto fail;
1788  }
1789 
1790  f->layout[i] = image_create_info.initialLayout;
1791  f->access[i] = 0x0;
1792 
1793  for (int j = 0; j < planes; j++) {
1794  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
1795  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
1796  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
1797 
1798  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
1799  plane_info[bind_counts].planeAspect = aspect;
1800 
1801  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1802  bind_info[bind_counts].pNext = signal_p ? &plane_info[bind_counts] : NULL;
1803  bind_info[bind_counts].image = f->img[i];
1804  bind_info[bind_counts].memory = f->mem[desc->layers[i].planes[j].object_index];
1805  bind_info[bind_counts].memoryOffset = desc->layers[i].planes[j].offset;
1806  bind_counts++;
1807  }
1808  }
1809 
1810  ret = vkCreateSemaphore(hwctx->act_dev, &sem_spawn,
1811  hwctx->alloc, &f->sem);
1812  if (ret != VK_SUCCESS) {
1813  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
1814  vk_ret2str(ret));
1815  return AVERROR_EXTERNAL;
1816  }
1817 
1818  /* We'd import a semaphore onto the one we created using
1819  * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
1820  * offer us anything we could import and sync with, so instead
1821  * just signal the semaphore we created. */
1822 
1823  /* Bind the allocated memory to the images */
1824  ret = vkBindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
1825  if (ret != VK_SUCCESS) {
1826  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
1827  vk_ret2str(ret));
1828  return AVERROR_EXTERNAL;
1829  }
1830 
1831  /* NOTE: This is completely uneccesary and unneeded once we can import
1832  * semaphores from DRM. Otherwise we have to activate the semaphores.
1833  * We're reusing the exec context that's also used for uploads/downloads. */
1834  err = prepare_frame(hwfc, &p->cmd, f, PREP_MODE_RO_SHADER);
1835  if (err)
1836  goto fail;
1837 
1838  *frame = f;
1839 
1840  return 0;
1841 
1842 fail:
1843  for (int i = 0; i < desc->nb_layers; i++)
1844  vkDestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
1845  for (int i = 0; i < desc->nb_objects; i++)
1846  vkFreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
1847  vkDestroySemaphore(hwctx->act_dev, f->sem, hwctx->alloc);
1848 
1849  av_free(f);
1850 
1851  return err;
1852 }
1853 
1854 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1855  const AVFrame *src, int flags)
1856 {
1857  int err = 0;
1858  AVVkFrame *f;
1859  VulkanMapping *map = NULL;
1860 
1861  err = vulkan_map_from_drm_frame_desc(hwfc, &f,
1862  (AVDRMFrameDescriptor *)src->data[0]);
1863  if (err)
1864  return err;
1865 
1866  /* The unmapping function will free this */
1867  dst->data[0] = (uint8_t *)f;
1868  dst->width = src->width;
1869  dst->height = src->height;
1870 
1871  map = av_mallocz(sizeof(VulkanMapping));
1872  if (!map)
1873  goto fail;
1874 
1875  map->frame = f;
1876  map->flags = flags;
1877 
1878  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1879  &vulkan_unmap_from, map);
1880  if (err < 0)
1881  goto fail;
1882 
1883  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
1884 
1885  return 0;
1886 
1887 fail:
1888  vulkan_frame_free(hwfc->device_ctx->hwctx, (uint8_t *)f);
1889  av_free(map);
1890  return err;
1891 }
1892 
1893 #if CONFIG_VAAPI
1894 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
1895  AVFrame *dst, const AVFrame *src,
1896  int flags)
1897 {
1898  int err;
1899  AVFrame *tmp = av_frame_alloc();
1901  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
1902  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1903 
1904  if (!tmp)
1905  return AVERROR(ENOMEM);
1906 
1907  /* We have to sync since like the previous comment said, no semaphores */
1908  vaSyncSurface(vaapi_ctx->display, surface_id);
1909 
1911 
1912  err = av_hwframe_map(tmp, src, flags);
1913  if (err < 0)
1914  goto fail;
1915 
1916  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
1917  if (err < 0)
1918  goto fail;
1919 
1920  err = ff_hwframe_map_replace(dst, src);
1921 
1922 fail:
1923  av_frame_free(&tmp);
1924  return err;
1925 }
1926 #endif
1927 #endif
1928 
1929 #if CONFIG_CUDA
1930 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
1931  AVBufferRef *cuda_hwfc,
1932  const AVFrame *frame)
1933 {
1934  int err;
1935  VkResult ret;
1936  AVVkFrame *dst_f;
1937  AVVkFrameInternal *dst_int;
1938  AVHWDeviceContext *ctx = hwfc->device_ctx;
1939  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1940  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1941  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
1942  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdKHR);
1943  VK_LOAD_PFN(hwctx->inst, vkGetSemaphoreFdKHR);
1944 
1945  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
1946  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
1947  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
1948  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
1949  CudaFunctions *cu = cu_internal->cuda_dl;
1950  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
1951  CU_AD_FORMAT_UNSIGNED_INT8;
1952 
1953  dst_f = (AVVkFrame *)frame->data[0];
1954 
1955  dst_int = dst_f->internal;
1956  if (!dst_int || !dst_int->cuda_fc_ref) {
1957  VkSemaphoreGetFdInfoKHR sem_export = {
1958  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
1959  .semaphore = dst_f->sem,
1960  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1961  };
1962  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
1963  .type = CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD,
1964  };
1965 
1966  if (!dst_f->internal)
1967  dst_f->internal = dst_int = av_mallocz(sizeof(*dst_f->internal));
1968 
1969  if (!dst_int) {
1970  err = AVERROR(ENOMEM);
1971  goto fail;
1972  }
1973 
1974  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
1975  if (!dst_int->cuda_fc_ref) {
1976  err = AVERROR(ENOMEM);
1977  goto fail;
1978  }
1979 
1980  for (int i = 0; i < planes; i++) {
1981  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
1982  .offset = 0,
1983  .arrayDesc = {
1984  .Width = i > 0 ? AV_CEIL_RSHIFT(hwfc->width, desc->log2_chroma_w)
1985  : hwfc->width,
1986  .Height = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, desc->log2_chroma_h)
1987  : hwfc->height,
1988  .Depth = 0,
1989  .Format = cufmt,
1990  .NumChannels = 1 + ((planes == 2) && i),
1991  .Flags = 0,
1992  },
1993  .numLevels = 1,
1994  };
1995  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
1996  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
1997  .size = dst_f->size[i],
1998  };
1999  VkMemoryGetFdInfoKHR export_info = {
2000  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2001  .memory = dst_f->mem[i],
2002  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
2003  };
2004 
2005  ret = pfn_vkGetMemoryFdKHR(hwctx->act_dev, &export_info,
2006  &ext_desc.handle.fd);
2007  if (ret != VK_SUCCESS) {
2008  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
2009  err = AVERROR_EXTERNAL;
2010  goto fail;
2011  }
2012 
2013  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
2014  if (ret < 0) {
2015  err = AVERROR_EXTERNAL;
2016  goto fail;
2017  }
2018 
2019  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
2020  dst_int->ext_mem[i],
2021  &tex_desc));
2022  if (ret < 0) {
2023  err = AVERROR_EXTERNAL;
2024  goto fail;
2025  }
2026 
2027  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
2028  dst_int->cu_mma[i], 0));
2029  if (ret < 0) {
2030  err = AVERROR_EXTERNAL;
2031  goto fail;
2032  }
2033  }
2034 
2035  ret = pfn_vkGetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
2036  &ext_sem_desc.handle.fd);
2037  if (ret != VK_SUCCESS) {
2038  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
2039  vk_ret2str(ret));
2040  err = AVERROR_EXTERNAL;
2041  goto fail;
2042  }
2043 
2044  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem,
2045  &ext_sem_desc));
2046  if (ret < 0) {
2047  err = AVERROR_EXTERNAL;
2048  goto fail;
2049  }
2050  }
2051 
2052  return 0;
2053 
2054 fail:
2055  return err;
2056 }
2057 
2058 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
2059  AVFrame *dst, const AVFrame *src)
2060 {
2061  int err;
2062  VkResult ret;
2063  CUcontext dummy;
2064  AVVkFrame *dst_f;
2065  AVVkFrameInternal *dst_int;
2066  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2067  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
2068 
2070  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2071  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2072  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2073  CudaFunctions *cu = cu_internal->cuda_dl;
2074  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par = { 0 };
2075  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par = { 0 };
2076 
2077  ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
2078  if (ret < 0) {
2079  err = AVERROR_EXTERNAL;
2080  goto fail;
2081  }
2082 
2083  dst_f = (AVVkFrame *)dst->data[0];
2084 
2085  ret = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
2086  if (ret < 0) {
2087  goto fail;
2088  }
2089  dst_int = dst_f->internal;
2090 
2091  ret = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(&dst_int->cu_sem, &s_w_par,
2092  1, cuda_dev->stream));
2093  if (ret < 0) {
2094  err = AVERROR_EXTERNAL;
2095  goto fail;
2096  }
2097 
2098  for (int i = 0; i < planes; i++) {
2099  CUDA_MEMCPY2D cpy = {
2100  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
2101  .srcDevice = (CUdeviceptr)src->data[i],
2102  .srcPitch = src->linesize[i],
2103  .srcY = 0,
2104 
2105  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
2106  .dstArray = dst_int->cu_array[i],
2107  .WidthInBytes = (i > 0 ? AV_CEIL_RSHIFT(hwfc->width, desc->log2_chroma_w)
2108  : hwfc->width) * desc->comp[i].step,
2109  .Height = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, desc->log2_chroma_h)
2110  : hwfc->height,
2111  };
2112 
2113  ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
2114  if (ret < 0) {
2115  err = AVERROR_EXTERNAL;
2116  goto fail;
2117  }
2118  }
2119 
2120  ret = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(&dst_int->cu_sem, &s_s_par,
2121  1, cuda_dev->stream));
2122  if (ret < 0) {
2123  err = AVERROR_EXTERNAL;
2124  goto fail;
2125  }
2126 
2127  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2128 
2129  av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n");
2130 
2131  return 0;
2132 
2133 fail:
2134  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2135  vulkan_free_internal(dst_int);
2136  dst_f->internal = NULL;
2137  av_buffer_unref(&dst->buf[0]);
2138  return err;
2139 }
2140 #endif
2141 
2142 static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
2143  const AVFrame *src, int flags)
2144 {
2146 
2147  switch (src->format) {
2148 #if CONFIG_LIBDRM
2149 #if CONFIG_VAAPI
2150  case AV_PIX_FMT_VAAPI:
2151  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2152  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
2153 #endif
2154  case AV_PIX_FMT_DRM_PRIME:
2155  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2156  return vulkan_map_from_drm(hwfc, dst, src, flags);
2157 #endif
2158  default:
2159  return AVERROR(ENOSYS);
2160  }
2161 }
2162 
2163 #if CONFIG_LIBDRM
2164 typedef struct VulkanDRMMapping {
2165  AVDRMFrameDescriptor drm_desc;
2166  AVVkFrame *source;
2167 } VulkanDRMMapping;
2168 
2169 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
2170 {
2171  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
2172 
2173  for (int i = 0; i < drm_desc->nb_objects; i++)
2174  close(drm_desc->objects[i].fd);
2175 
2176  av_free(drm_desc);
2177 }
2178 
2179 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
2180 {
2181  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
2182  if (vulkan_drm_format_map[i].vk_format == vkfmt)
2183  return vulkan_drm_format_map[i].drm_fourcc;
2184  return DRM_FORMAT_INVALID;
2185 }
2186 
2187 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2188  const AVFrame *src, int flags)
2189 {
2190  int err = 0;
2191  VkResult ret;
2192  AVVkFrame *f = (AVVkFrame *)src->data[0];
2194  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2195  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2196  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdKHR);
2197  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
2198  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
2199  };
2200 
2201  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
2202  if (!drm_desc)
2203  return AVERROR(ENOMEM);
2204 
2205  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
2206  if (err < 0)
2207  goto end;
2208 
2209  if (p->extensions & EXT_DRM_MODIFIER_FLAGS) {
2210  VK_LOAD_PFN(hwctx->inst, vkGetImageDrmFormatModifierPropertiesEXT);
2211  ret = pfn_vkGetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
2212  &drm_mod);
2213  if (ret != VK_SUCCESS) {
2214  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
2215  err = AVERROR_EXTERNAL;
2216  goto end;
2217  }
2218  }
2219 
2220  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
2221  VkMemoryGetFdInfoKHR export_info = {
2222  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2223  .memory = f->mem[i],
2224  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2225  };
2226 
2227  ret = pfn_vkGetMemoryFdKHR(hwctx->act_dev, &export_info,
2228  &drm_desc->objects[i].fd);
2229  if (ret != VK_SUCCESS) {
2230  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
2231  err = AVERROR_EXTERNAL;
2232  goto end;
2233  }
2234 
2235  drm_desc->nb_objects++;
2236  drm_desc->objects[i].size = f->size[i];
2237  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
2238  }
2239 
2240  drm_desc->nb_layers = planes;
2241  for (int i = 0; i < drm_desc->nb_layers; i++) {
2242  VkSubresourceLayout layout;
2243  VkImageSubresource sub = {
2244  .aspectMask = p->extensions & EXT_DRM_MODIFIER_FLAGS ?
2245  VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2246  VK_IMAGE_ASPECT_COLOR_BIT,
2247  };
2248  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
2249 
2250  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
2251  drm_desc->layers[i].nb_planes = 1;
2252 
2253  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
2254  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
2255  err = AVERROR_PATCHWELCOME;
2256  goto end;
2257  }
2258 
2259  drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
2260 
2261  if (f->tiling != VK_IMAGE_TILING_OPTIMAL)
2262  continue;
2263 
2264  vkGetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
2265  drm_desc->layers[i].planes[0].offset = layout.offset;
2266  drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
2267  }
2268 
2269  dst->width = src->width;
2270  dst->height = src->height;
2271  dst->data[0] = (uint8_t *)drm_desc;
2272 
2273  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
2274 
2275  return 0;
2276 
2277 end:
2278  av_free(drm_desc);
2279  return err;
2280 }
2281 
2282 #if CONFIG_VAAPI
2283 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
2284  const AVFrame *src, int flags)
2285 {
2286  int err;
2287  AVFrame *tmp = av_frame_alloc();
2288  if (!tmp)
2289  return AVERROR(ENOMEM);
2290 
2292 
2293  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
2294  if (err < 0)
2295  goto fail;
2296 
2297  err = av_hwframe_map(dst, tmp, flags);
2298  if (err < 0)
2299  goto fail;
2300 
2301  err = ff_hwframe_map_replace(dst, src);
2302 
2303 fail:
2304  av_frame_free(&tmp);
2305  return err;
2306 }
2307 #endif
2308 #endif
2309 
2311  const AVFrame *src, int flags)
2312 {
2314 
2315  switch (dst->format) {
2316 #if CONFIG_LIBDRM
2317  case AV_PIX_FMT_DRM_PRIME:
2318  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2319  return vulkan_map_to_drm(hwfc, dst, src, flags);
2320 #if CONFIG_VAAPI
2321  case AV_PIX_FMT_VAAPI:
2322  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2323  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
2324 #endif
2325 #endif
2326  default:
2327  return vulkan_map_frame_to_mem(hwfc, dst, src, flags);
2328  }
2329 }
2330 
2331 typedef struct ImageBuffer {
2332  VkBuffer buf;
2333  VkDeviceMemory mem;
2334  VkMemoryPropertyFlagBits flags;
2335 } ImageBuffer;
2336 
2338 {
2339  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2340  if (!buf)
2341  return;
2342 
2343  vkDestroyBuffer(hwctx->act_dev, buf->buf, hwctx->alloc);
2344  vkFreeMemory(hwctx->act_dev, buf->mem, hwctx->alloc);
2345 }
2346 
2348  int *stride, VkBufferUsageFlags usage,
2349  VkMemoryPropertyFlagBits flags, void *create_pnext,
2350  void *alloc_pnext)
2351 {
2352  int err;
2353  VkResult ret;
2354  VkMemoryRequirements req;
2355  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2356  VulkanDevicePriv *p = ctx->internal->priv;
2357 
2358  VkBufferCreateInfo buf_spawn = {
2359  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
2360  .pNext = create_pnext,
2361  .usage = usage,
2362  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
2363  };
2364 
2365  *stride = FFALIGN(*stride, p->props.limits.optimalBufferCopyRowPitchAlignment);
2366  buf_spawn.size = height*(*stride);
2367 
2368  ret = vkCreateBuffer(hwctx->act_dev, &buf_spawn, NULL, &buf->buf);
2369  if (ret != VK_SUCCESS) {
2370  av_log(ctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
2371  vk_ret2str(ret));
2372  return AVERROR_EXTERNAL;
2373  }
2374 
2375  vkGetBufferMemoryRequirements(hwctx->act_dev, buf->buf, &req);
2376 
2377  err = alloc_mem(ctx, &req, flags, alloc_pnext, &buf->flags, &buf->mem);
2378  if (err)
2379  return err;
2380 
2381  ret = vkBindBufferMemory(hwctx->act_dev, buf->buf, buf->mem, 0);
2382  if (ret != VK_SUCCESS) {
2383  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
2384  vk_ret2str(ret));
2385  free_buf(ctx, buf);
2386  return AVERROR_EXTERNAL;
2387  }
2388 
2389  return 0;
2390 }
2391 
2393  int nb_buffers, int invalidate)
2394 {
2395  VkResult ret;
2396  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2397  VkMappedMemoryRange invalidate_ctx[AV_NUM_DATA_POINTERS];
2398  int invalidate_count = 0;
2399 
2400  for (int i = 0; i < nb_buffers; i++) {
2401  ret = vkMapMemory(hwctx->act_dev, buf[i].mem, 0,
2402  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
2403  if (ret != VK_SUCCESS) {
2404  av_log(ctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
2405  vk_ret2str(ret));
2406  return AVERROR_EXTERNAL;
2407  }
2408  }
2409 
2410  if (!invalidate)
2411  return 0;
2412 
2413  for (int i = 0; i < nb_buffers; i++) {
2414  const VkMappedMemoryRange ival_buf = {
2415  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
2416  .memory = buf[i].mem,
2417  .size = VK_WHOLE_SIZE,
2418  };
2419  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
2420  continue;
2421  invalidate_ctx[invalidate_count++] = ival_buf;
2422  }
2423 
2424  if (invalidate_count) {
2425  ret = vkInvalidateMappedMemoryRanges(hwctx->act_dev, invalidate_count,
2426  invalidate_ctx);
2427  if (ret != VK_SUCCESS)
2428  av_log(ctx, AV_LOG_WARNING, "Failed to invalidate memory: %s\n",
2429  vk_ret2str(ret));
2430  }
2431 
2432  return 0;
2433 }
2434 
2436  int nb_buffers, int flush)
2437 {
2438  int err = 0;
2439  VkResult ret;
2440  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2441  VkMappedMemoryRange flush_ctx[AV_NUM_DATA_POINTERS];
2442  int flush_count = 0;
2443 
2444  if (flush) {
2445  for (int i = 0; i < nb_buffers; i++) {
2446  const VkMappedMemoryRange flush_buf = {
2447  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
2448  .memory = buf[i].mem,
2449  .size = VK_WHOLE_SIZE,
2450  };
2451  if (buf[i].flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
2452  continue;
2453  flush_ctx[flush_count++] = flush_buf;
2454  }
2455  }
2456 
2457  if (flush_count) {
2458  ret = vkFlushMappedMemoryRanges(hwctx->act_dev, flush_count, flush_ctx);
2459  if (ret != VK_SUCCESS) {
2460  av_log(ctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
2461  vk_ret2str(ret));
2462  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
2463  }
2464  }
2465 
2466  for (int i = 0; i < nb_buffers; i++)
2467  vkUnmapMemory(hwctx->act_dev, buf[i].mem);
2468 
2469  return err;
2470 }
2471 
2473  ImageBuffer *buffer, const int *buf_stride, int w,
2474  int h, enum AVPixelFormat pix_fmt, int to_buf)
2475 {
2476  VkResult ret;
2477  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2478  VulkanDevicePriv *s = ctx->internal->priv;
2479 
2480  int bar_num = 0;
2481  VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS];
2482 
2483  const int planes = av_pix_fmt_count_planes(pix_fmt);
2484  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
2485 
2486  VkCommandBufferBeginInfo cmd_start = {
2487  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2488  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
2489  };
2490 
2491  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
2492 
2493  VkSubmitInfo s_info = {
2494  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
2495  .commandBufferCount = 1,
2496  .pCommandBuffers = &s->cmd.buf,
2497  .pSignalSemaphores = &frame->sem,
2498  .pWaitSemaphores = &frame->sem,
2499  .pWaitDstStageMask = sem_wait_dst,
2500  .signalSemaphoreCount = 1,
2501  .waitSemaphoreCount = 1,
2502  };
2503 
2504  ret = vkBeginCommandBuffer(s->cmd.buf, &cmd_start);
2505  if (ret != VK_SUCCESS) {
2506  av_log(ctx, AV_LOG_ERROR, "Unable to init command buffer: %s\n",
2507  vk_ret2str(ret));
2508  return AVERROR_EXTERNAL;
2509  }
2510 
2511  /* Change the image layout to something more optimal for transfers */
2512  for (int i = 0; i < planes; i++) {
2513  VkImageLayout new_layout = to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL :
2514  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2515  VkAccessFlags new_access = to_buf ? VK_ACCESS_TRANSFER_READ_BIT :
2516  VK_ACCESS_TRANSFER_WRITE_BIT;
2517 
2518  sem_wait_dst[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2519 
2520  /* If the layout matches and we have read access skip the barrier */
2521  if ((frame->layout[i] == new_layout) && (frame->access[i] & new_access))
2522  continue;
2523 
2524  img_bar[bar_num].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2525  img_bar[bar_num].srcAccessMask = 0x0;
2526  img_bar[bar_num].dstAccessMask = new_access;
2527  img_bar[bar_num].oldLayout = frame->layout[i];
2528  img_bar[bar_num].newLayout = new_layout;
2529  img_bar[bar_num].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2530  img_bar[bar_num].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2531  img_bar[bar_num].image = frame->img[i];
2532  img_bar[bar_num].subresourceRange.levelCount = 1;
2533  img_bar[bar_num].subresourceRange.layerCount = 1;
2534  img_bar[bar_num].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2535 
2536  frame->layout[i] = img_bar[bar_num].newLayout;
2537  frame->access[i] = img_bar[bar_num].dstAccessMask;
2538 
2539  bar_num++;
2540  }
2541 
2542  if (bar_num)
2543  vkCmdPipelineBarrier(s->cmd.buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2544  VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
2545  0, NULL, 0, NULL, bar_num, img_bar);
2546 
2547  /* Schedule a copy for each plane */
2548  for (int i = 0; i < planes; i++) {
2549  const int p_w = i > 0 ? AV_CEIL_RSHIFT(w, desc->log2_chroma_w) : w;
2550  const int p_h = i > 0 ? AV_CEIL_RSHIFT(h, desc->log2_chroma_h) : h;
2551  VkBufferImageCopy buf_reg = {
2552  .bufferOffset = 0,
2553  /* Buffer stride isn't in bytes, it's in samples, the implementation
2554  * uses the image's VkFormat to know how many bytes per sample
2555  * the buffer has. So we have to convert by dividing. Stupid.
2556  * Won't work with YUVA or other planar formats with alpha. */
2557  .bufferRowLength = buf_stride[i] / desc->comp[i].step,
2558  .bufferImageHeight = p_h,
2559  .imageSubresource.layerCount = 1,
2560  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2561  .imageOffset = { 0, 0, 0, },
2562  .imageExtent = { p_w, p_h, 1, },
2563  };
2564 
2565  if (to_buf)
2566  vkCmdCopyImageToBuffer(s->cmd.buf, frame->img[i], frame->layout[i],
2567  buffer[i].buf, 1, &buf_reg);
2568  else
2569  vkCmdCopyBufferToImage(s->cmd.buf, buffer[i].buf, frame->img[i],
2570  frame->layout[i], 1, &buf_reg);
2571  }
2572 
2573  ret = vkEndCommandBuffer(s->cmd.buf);
2574  if (ret != VK_SUCCESS) {
2575  av_log(ctx, AV_LOG_ERROR, "Unable to finish command buffer: %s\n",
2576  vk_ret2str(ret));
2577  return AVERROR_EXTERNAL;
2578  }
2579 
2580  /* Wait for the download/upload to finish if uploading, otherwise the
2581  * semaphore will take care of synchronization when uploading */
2582  ret = vkQueueSubmit(s->cmd.queue, 1, &s_info, s->cmd.fence);
2583  if (ret != VK_SUCCESS) {
2584  av_log(ctx, AV_LOG_ERROR, "Unable to submit command buffer: %s\n",
2585  vk_ret2str(ret));
2586  return AVERROR_EXTERNAL;
2587  } else {
2588  vkWaitForFences(hwctx->act_dev, 1, &s->cmd.fence, VK_TRUE, UINT64_MAX);
2589  vkResetFences(hwctx->act_dev, 1, &s->cmd.fence);
2590  }
2591 
2592  return 0;
2593 }
2594 
2595 /* Technically we can use VK_EXT_external_memory_host to upload and download,
2596  * however the alignment requirements make this unfeasible as both the pointer
2597  * and the size of each plane need to be aligned to the minimum alignment
2598  * requirement, which on all current implementations (anv, radv) is 4096.
2599  * If the requirement gets relaxed (unlikely) this can easily be implemented. */
2601  const AVFrame *src)
2602 {
2603  int err = 0;
2604  AVFrame tmp;
2605  AVVkFrame *f = (AVVkFrame *)dst->data[0];
2606  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
2607  ImageBuffer buf[AV_NUM_DATA_POINTERS] = { { 0 } };
2608  const int planes = av_pix_fmt_count_planes(src->format);
2609  int log2_chroma = av_pix_fmt_desc_get(src->format)->log2_chroma_h;
2610 
2611  if ((src->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(src->format))) {
2612  av_log(hwfc, AV_LOG_ERROR, "Unsupported source pixel format!\n");
2613  return AVERROR(EINVAL);
2614  }
2615 
2616  if (src->width > hwfc->width || src->height > hwfc->height)
2617  return AVERROR(EINVAL);
2618 
2619  /* For linear, host visiable images */
2620  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
2621  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
2622  AVFrame *map = av_frame_alloc();
2623  if (!map)
2624  return AVERROR(ENOMEM);
2625  map->format = src->format;
2626 
2627  err = vulkan_map_frame_to_mem(hwfc, map, dst, AV_HWFRAME_MAP_WRITE);
2628  if (err)
2629  goto end;
2630 
2631  err = av_frame_copy(map, src);
2632  av_frame_free(&map);
2633  goto end;
2634  }
2635 
2636  /* Create buffers */
2637  for (int i = 0; i < planes; i++) {
2638  int h = src->height;
2639  int p_height = i > 0 ? AV_CEIL_RSHIFT(h, log2_chroma) : h;
2640 
2641  tmp.linesize[i] = src->linesize[i];
2642  err = create_buf(dev_ctx, &buf[i], p_height,
2643  &tmp.linesize[i], VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
2644  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, NULL, NULL);
2645  if (err)
2646  goto end;
2647  }
2648 
2649  /* Map, copy image to buffer, unmap */
2650  if ((err = map_buffers(dev_ctx, buf, tmp.data, planes, 0)))
2651  goto end;
2652 
2653  av_image_copy(tmp.data, tmp.linesize, (const uint8_t **)src->data,
2654  src->linesize, src->format, src->width, src->height);
2655 
2656  if ((err = unmap_buffers(dev_ctx, buf, planes, 1)))
2657  goto end;
2658 
2659  /* Copy buffers to image */
2660  err = transfer_image_buf(dev_ctx, f, buf, tmp.linesize,
2661  src->width, src->height, src->format, 0);
2662 
2663 end:
2664  for (int i = 0; i < planes; i++)
2665  free_buf(dev_ctx, &buf[i]);
2666 
2667  return err;
2668 }
2669 
2671  const AVFrame *src)
2672 {
2674 
2675  switch (src->format) {
2676 #if CONFIG_CUDA
2677  case AV_PIX_FMT_CUDA:
2678  if ((p->extensions & EXT_EXTERNAL_FD_MEMORY) &&
2679  (p->extensions & EXT_EXTERNAL_FD_SEM))
2680  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
2681 #endif
2682  default:
2683  if (src->hw_frames_ctx)
2684  return AVERROR(ENOSYS);
2685  else
2686  return vulkan_transfer_data_from_mem(hwfc, dst, src);
2687  }
2688 }
2689 
2690 #if CONFIG_CUDA
2691 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
2692  const AVFrame *src)
2693 {
2694  int err;
2695  VkResult ret;
2696  CUcontext dummy;
2697  AVVkFrame *dst_f;
2698  AVVkFrameInternal *dst_int;
2699  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2700  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
2701 
2703  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2704  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2705  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2706  CudaFunctions *cu = cu_internal->cuda_dl;
2707 
2708  ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
2709  if (ret < 0) {
2710  err = AVERROR_EXTERNAL;
2711  goto fail;
2712  }
2713 
2714  dst_f = (AVVkFrame *)src->data[0];
2715 
2716  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
2717  if (err < 0) {
2718  goto fail;
2719  }
2720 
2721  dst_int = dst_f->internal;
2722 
2723  for (int i = 0; i < planes; i++) {
2724  CUDA_MEMCPY2D cpy = {
2725  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
2726  .dstDevice = (CUdeviceptr)dst->data[i],
2727  .dstPitch = dst->linesize[i],
2728  .dstY = 0,
2729 
2730  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
2731  .srcArray = dst_int->cu_array[i],
2732  .WidthInBytes = (i > 0 ? AV_CEIL_RSHIFT(hwfc->width, desc->log2_chroma_w)
2733  : hwfc->width) * desc->comp[i].step,
2734  .Height = i > 0 ? AV_CEIL_RSHIFT(hwfc->height, desc->log2_chroma_h)
2735  : hwfc->height,
2736  };
2737 
2738  ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
2739  if (ret < 0) {
2740  err = AVERROR_EXTERNAL;
2741  goto fail;
2742  }
2743  }
2744 
2745  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2746 
2747  av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n");
2748 
2749  return 0;
2750 
2751 fail:
2752  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2753  vulkan_free_internal(dst_int);
2754  dst_f->internal = NULL;
2755  av_buffer_unref(&dst->buf[0]);
2756  return err;
2757 }
2758 #endif
2759 
2761  const AVFrame *src)
2762 {
2763  int err = 0;
2764  AVFrame tmp;
2765  AVVkFrame *f = (AVVkFrame *)src->data[0];
2766  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
2767  ImageBuffer buf[AV_NUM_DATA_POINTERS] = { { 0 } };
2768  const int planes = av_pix_fmt_count_planes(dst->format);
2769  int log2_chroma = av_pix_fmt_desc_get(dst->format)->log2_chroma_h;
2770 
2771  if (dst->width > hwfc->width || dst->height > hwfc->height)
2772  return AVERROR(EINVAL);
2773 
2774  /* For linear, host visiable images */
2775  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
2776  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
2777  AVFrame *map = av_frame_alloc();
2778  if (!map)
2779  return AVERROR(ENOMEM);
2780  map->format = dst->format;
2781 
2782  err = vulkan_map_frame_to_mem(hwfc, map, src, AV_HWFRAME_MAP_READ);
2783  if (err)
2784  return err;
2785 
2786  err = av_frame_copy(dst, map);
2787  av_frame_free(&map);
2788  return err;
2789  }
2790 
2791  /* Create buffers */
2792  for (int i = 0; i < planes; i++) {
2793  int h = dst->height;
2794  int p_height = i > 0 ? AV_CEIL_RSHIFT(h, log2_chroma) : h;
2795 
2796  tmp.linesize[i] = dst->linesize[i];
2797  err = create_buf(dev_ctx, &buf[i], p_height,
2798  &tmp.linesize[i], VK_BUFFER_USAGE_TRANSFER_DST_BIT,
2799  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, NULL, NULL);
2800  }
2801 
2802  /* Copy image to buffer */
2803  if ((err = transfer_image_buf(dev_ctx, f, buf, tmp.linesize,
2804  dst->width, dst->height, dst->format, 1)))
2805  goto end;
2806 
2807  /* Map, copy buffer to frame, unmap */
2808  if ((err = map_buffers(dev_ctx, buf, tmp.data, planes, 1)))
2809  goto end;
2810 
2811  av_image_copy(dst->data, dst->linesize, (const uint8_t **)tmp.data,
2812  tmp.linesize, dst->format, dst->width, dst->height);
2813 
2814  err = unmap_buffers(dev_ctx, buf, planes, 0);
2815 
2816 end:
2817  for (int i = 0; i < planes; i++)
2818  free_buf(dev_ctx, &buf[i]);
2819 
2820  return err;
2821 }
2822 
2824  const AVFrame *src)
2825 {
2827 
2828  switch (dst->format) {
2829 #if CONFIG_CUDA
2830  case AV_PIX_FMT_CUDA:
2831  if ((p->extensions & EXT_EXTERNAL_FD_MEMORY) &&
2832  (p->extensions & EXT_EXTERNAL_FD_SEM))
2833  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
2834 #endif
2835  default:
2836  if (dst->hw_frames_ctx)
2837  return AVERROR(ENOSYS);
2838  else
2839  return vulkan_transfer_data_to_mem(hwfc, dst, src);
2840  }
2841 }
2842 
2844 {
2845  return av_mallocz(sizeof(AVVkFrame));
2846 }
2847 
2850  .name = "Vulkan",
2851 
2852  .device_hwctx_size = sizeof(AVVulkanDeviceContext),
2853  .device_priv_size = sizeof(VulkanDevicePriv),
2854  .frames_hwctx_size = sizeof(AVVulkanFramesContext),
2855  .frames_priv_size = sizeof(VulkanFramesPriv),
2856 
2857  .device_init = &vulkan_device_init,
2858  .device_create = &vulkan_device_create,
2859  .device_derive = &vulkan_device_derive,
2860 
2861  .frames_get_constraints = &vulkan_frames_get_constraints,
2862  .frames_init = vulkan_frames_init,
2863  .frames_get_buffer = vulkan_get_buffer,
2864  .frames_uninit = vulkan_frames_uninit,
2865 
2866  .transfer_get_formats = vulkan_transfer_get_formats,
2867  .transfer_data_to = vulkan_transfer_data_to,
2868  .transfer_data_from = vulkan_transfer_data_from,
2869 
2870  .map_to = vulkan_map_to,
2871  .map_from = vulkan_map_from,
2872 
2873  .pix_fmts = (const enum AVPixelFormat []) {
2876  },
2877 };
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
VkSemaphore sem
Per-frame semaphore.
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
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