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