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,
2012  const AVFrame *src)
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 AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
2024  const int has_modifiers = !!(p->extensions & EXT_DRM_MODIFIER_FLAGS);
2025  VkSubresourceLayout plane_data[AV_NUM_DATA_POINTERS] = { 0 };
2026  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { 0 };
2027  VkBindImagePlaneMemoryInfo plane_info[AV_NUM_DATA_POINTERS] = { 0 };
2028  VkExternalMemoryHandleTypeFlagBits htype = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
2029 
2030  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdPropertiesKHR);
2031 
2032  for (int i = 0; i < desc->nb_layers; i++) {
2033  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
2034  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
2035  desc->layers[i].format);
2036  return AVERROR(EINVAL);
2037  }
2038  }
2039 
2040  if (!(f = av_vk_frame_alloc())) {
2041  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2042  err = AVERROR(ENOMEM);
2043  goto fail;
2044  }
2045 
2046  f->tiling = has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
2047  desc->objects[0].format_modifier == DRM_FORMAT_MOD_LINEAR ?
2048  VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
2049 
2050  for (int i = 0; i < desc->nb_layers; i++) {
2051  const int planes = desc->layers[i].nb_planes;
2052  VkImageDrmFormatModifierExplicitCreateInfoEXT drm_info = {
2053  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
2054  .drmFormatModifier = desc->objects[0].format_modifier,
2055  .drmFormatModifierPlaneCount = planes,
2056  .pPlaneLayouts = (const VkSubresourceLayout *)&plane_data,
2057  };
2058 
2059  VkExternalMemoryImageCreateInfo einfo = {
2060  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2061  .pNext = has_modifiers ? &drm_info : NULL,
2062  .handleTypes = htype,
2063  };
2064 
2065  VkSemaphoreCreateInfo sem_spawn = {
2066  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2067  };
2068 
2069  VkImageCreateInfo create_info = {
2070  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2071  .pNext = &einfo,
2072  .imageType = VK_IMAGE_TYPE_2D,
2073  .format = drm_to_vulkan_fmt(desc->layers[i].format),
2074  .extent.depth = 1,
2075  .mipLevels = 1,
2076  .arrayLayers = 1,
2077  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2078  .tiling = f->tiling,
2079  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
2080  .usage = frames_hwctx->usage,
2081  .samples = VK_SAMPLE_COUNT_1_BIT,
2082  .pQueueFamilyIndices = p->qfs,
2083  .queueFamilyIndexCount = p->num_qfs,
2084  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2085  VK_SHARING_MODE_EXCLUSIVE,
2086  };
2087 
2088  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2089  hwfc->sw_format, src->width, src->height, i);
2090 
2091  for (int j = 0; j < planes; j++) {
2092  plane_data[j].offset = desc->layers[i].planes[j].offset;
2093  plane_data[j].rowPitch = desc->layers[i].planes[j].pitch;
2094  plane_data[j].size = 0; /* The specs say so for all 3 */
2095  plane_data[j].arrayPitch = 0;
2096  plane_data[j].depthPitch = 0;
2097  }
2098 
2099  /* Create image */
2100  ret = vkCreateImage(hwctx->act_dev, &create_info,
2101  hwctx->alloc, &f->img[i]);
2102  if (ret != VK_SUCCESS) {
2103  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2104  vk_ret2str(ret));
2105  err = AVERROR(EINVAL);
2106  goto fail;
2107  }
2108 
2109  ret = vkCreateSemaphore(hwctx->act_dev, &sem_spawn,
2110  hwctx->alloc, &f->sem[i]);
2111  if (ret != VK_SUCCESS) {
2112  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2113  vk_ret2str(ret));
2114  return AVERROR_EXTERNAL;
2115  }
2116 
2117  /* We'd import a semaphore onto the one we created using
2118  * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
2119  * offer us anything we could import and sync with, so instead
2120  * just signal the semaphore we created. */
2121 
2122  f->layout[i] = create_info.initialLayout;
2123  f->access[i] = 0x0;
2124  }
2125 
2126  for (int i = 0; i < desc->nb_objects; i++) {
2127  int use_ded_mem = 0;
2128  VkMemoryFdPropertiesKHR fdmp = {
2129  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
2130  };
2131  VkMemoryRequirements req = {
2132  .size = desc->objects[i].size,
2133  };
2134  VkImportMemoryFdInfoKHR idesc = {
2135  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2136  .handleType = htype,
2137  .fd = dup(desc->objects[i].fd),
2138  };
2139  VkMemoryDedicatedAllocateInfo ded_alloc = {
2140  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2141  .pNext = &idesc,
2142  };
2143 
2144  ret = pfn_vkGetMemoryFdPropertiesKHR(hwctx->act_dev, htype,
2145  idesc.fd, &fdmp);
2146  if (ret != VK_SUCCESS) {
2147  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
2148  vk_ret2str(ret));
2149  err = AVERROR_EXTERNAL;
2150  close(idesc.fd);
2151  goto fail;
2152  }
2153 
2154  req.memoryTypeBits = fdmp.memoryTypeBits;
2155 
2156  /* Dedicated allocation only makes sense if there's a one to one mapping
2157  * between images and the memory backing them, so only check in this
2158  * case. */
2159  if (desc->nb_layers == desc->nb_objects) {
2160  VkImageMemoryRequirementsInfo2 req_desc = {
2161  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2162  .image = f->img[i],
2163  };
2164  VkMemoryDedicatedRequirements ded_req = {
2165  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2166  };
2167  VkMemoryRequirements2 req2 = {
2168  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2169  .pNext = &ded_req,
2170  };
2171 
2172  vkGetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
2173 
2174  use_ded_mem = ded_req.prefersDedicatedAllocation |
2175  ded_req.requiresDedicatedAllocation;
2176  if (use_ded_mem)
2177  ded_alloc.image = f->img[i];
2178  }
2179 
2180  err = alloc_mem(ctx, &req, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2181  use_ded_mem ? &ded_alloc : ded_alloc.pNext,
2182  &f->flags, &f->mem[i]);
2183  if (err) {
2184  close(idesc.fd);
2185  return err;
2186  }
2187 
2188  f->size[i] = desc->objects[i].size;
2189  }
2190 
2191  for (int i = 0; i < desc->nb_layers; i++) {
2192  const int planes = desc->layers[i].nb_planes;
2193  const int signal_p = has_modifiers && (planes > 1);
2194  for (int j = 0; j < planes; j++) {
2195  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2196  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
2197  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
2198 
2199  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
2200  plane_info[bind_counts].planeAspect = aspect;
2201 
2202  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2203  bind_info[bind_counts].pNext = signal_p ? &plane_info[bind_counts] : NULL;
2204  bind_info[bind_counts].image = f->img[i];
2205  bind_info[bind_counts].memory = f->mem[desc->layers[i].planes[j].object_index];
2206  bind_info[bind_counts].memoryOffset = desc->layers[i].planes[j].offset;
2207  bind_counts++;
2208  }
2209  }
2210 
2211  /* Bind the allocated memory to the images */
2212  ret = vkBindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
2213  if (ret != VK_SUCCESS) {
2214  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2215  vk_ret2str(ret));
2216  return AVERROR_EXTERNAL;
2217  }
2218 
2219  /* NOTE: This is completely uneccesary and unneeded once we can import
2220  * semaphores from DRM. Otherwise we have to activate the semaphores.
2221  * We're reusing the exec context that's also used for uploads/downloads. */
2222  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_RO_SHADER);
2223  if (err)
2224  goto fail;
2225 
2226  *frame = f;
2227 
2228  return 0;
2229 
2230 fail:
2231  for (int i = 0; i < desc->nb_layers; i++) {
2232  vkDestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2233  vkDestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2234  }
2235  for (int i = 0; i < desc->nb_objects; i++)
2236  vkFreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2237 
2238  av_free(f);
2239 
2240  return err;
2241 }
2242 
2243 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2244  const AVFrame *src, int flags)
2245 {
2246  int err = 0;
2247  AVVkFrame *f;
2248  VulkanMapping *map = NULL;
2249 
2250  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src)))
2251  return err;
2252 
2253  /* The unmapping function will free this */
2254  dst->data[0] = (uint8_t *)f;
2255  dst->width = src->width;
2256  dst->height = src->height;
2257 
2258  map = av_mallocz(sizeof(VulkanMapping));
2259  if (!map)
2260  goto fail;
2261 
2262  map->frame = f;
2263  map->flags = flags;
2264 
2265  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2266  &vulkan_unmap_from, map);
2267  if (err < 0)
2268  goto fail;
2269 
2270  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
2271 
2272  return 0;
2273 
2274 fail:
2275  vulkan_frame_free(hwfc->device_ctx->hwctx, (uint8_t *)f);
2276  av_free(map);
2277  return err;
2278 }
2279 
2280 #if CONFIG_VAAPI
2281 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
2282  AVFrame *dst, const AVFrame *src,
2283  int flags)
2284 {
2285  int err;
2286  AVFrame *tmp = av_frame_alloc();
2288  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
2289  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
2290 
2291  if (!tmp)
2292  return AVERROR(ENOMEM);
2293 
2294  /* We have to sync since like the previous comment said, no semaphores */
2295  vaSyncSurface(vaapi_ctx->display, surface_id);
2296 
2298 
2299  err = av_hwframe_map(tmp, src, flags);
2300  if (err < 0)
2301  goto fail;
2302 
2303  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
2304  if (err < 0)
2305  goto fail;
2306 
2307  err = ff_hwframe_map_replace(dst, src);
2308 
2309 fail:
2310  av_frame_free(&tmp);
2311  return err;
2312 }
2313 #endif
2314 #endif
2315 
2316 #if CONFIG_CUDA
2317 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
2318  AVBufferRef *cuda_hwfc,
2319  const AVFrame *frame)
2320 {
2321  int err;
2322  VkResult ret;
2323  AVVkFrame *dst_f;
2324  AVVkFrameInternal *dst_int;
2325  AVHWDeviceContext *ctx = hwfc->device_ctx;
2326  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2327  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2329  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdKHR);
2330  VK_LOAD_PFN(hwctx->inst, vkGetSemaphoreFdKHR);
2331 
2332  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
2333  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2334  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2335  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2336  CudaFunctions *cu = cu_internal->cuda_dl;
2337  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
2338  CU_AD_FORMAT_UNSIGNED_INT8;
2339 
2340  dst_f = (AVVkFrame *)frame->data[0];
2341 
2342  dst_int = dst_f->internal;
2343  if (!dst_int || !dst_int->cuda_fc_ref) {
2344  if (!dst_f->internal)
2345  dst_f->internal = dst_int = av_mallocz(sizeof(*dst_f->internal));
2346 
2347  if (!dst_int) {
2348  err = AVERROR(ENOMEM);
2349  goto fail;
2350  }
2351 
2352  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
2353  if (!dst_int->cuda_fc_ref) {
2354  err = AVERROR(ENOMEM);
2355  goto fail;
2356  }
2357 
2358  for (int i = 0; i < planes; i++) {
2359  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
2360  .offset = 0,
2361  .arrayDesc = {
2362  .Depth = 0,
2363  .Format = cufmt,
2364  .NumChannels = 1 + ((planes == 2) && i),
2365  .Flags = 0,
2366  },
2367  .numLevels = 1,
2368  };
2369  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
2370  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
2371  .size = dst_f->size[i],
2372  };
2373  VkMemoryGetFdInfoKHR export_info = {
2374  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2375  .memory = dst_f->mem[i],
2376  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
2377  };
2378  VkSemaphoreGetFdInfoKHR sem_export = {
2379  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
2380  .semaphore = dst_f->sem[i],
2381  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2382  };
2383  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
2384  .type = CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD,
2385  };
2386 
2387  int p_w, p_h;
2388  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
2389 
2390  tex_desc.arrayDesc.Width = p_w;
2391  tex_desc.arrayDesc.Height = p_h;
2392 
2393  ret = pfn_vkGetMemoryFdKHR(hwctx->act_dev, &export_info,
2394  &ext_desc.handle.fd);
2395  if (ret != VK_SUCCESS) {
2396  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
2397  err = AVERROR_EXTERNAL;
2398  goto fail;
2399  }
2400 
2401  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
2402  if (ret < 0) {
2403  err = AVERROR_EXTERNAL;
2404  goto fail;
2405  }
2406 
2407  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
2408  dst_int->ext_mem[i],
2409  &tex_desc));
2410  if (ret < 0) {
2411  err = AVERROR_EXTERNAL;
2412  goto fail;
2413  }
2414 
2415  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
2416  dst_int->cu_mma[i], 0));
2417  if (ret < 0) {
2418  err = AVERROR_EXTERNAL;
2419  goto fail;
2420  }
2421 
2422  ret = pfn_vkGetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
2423  &ext_sem_desc.handle.fd);
2424  if (ret != VK_SUCCESS) {
2425  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
2426  vk_ret2str(ret));
2427  err = AVERROR_EXTERNAL;
2428  goto fail;
2429  }
2430 
2431  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i],
2432  &ext_sem_desc));
2433  if (ret < 0) {
2434  err = AVERROR_EXTERNAL;
2435  goto fail;
2436  }
2437  }
2438  }
2439 
2440  return 0;
2441 
2442 fail:
2443  return err;
2444 }
2445 
2446 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
2447  AVFrame *dst, const AVFrame *src)
2448 {
2449  int err;
2450  VkResult ret;
2451  CUcontext dummy;
2452  AVVkFrame *dst_f;
2453  AVVkFrameInternal *dst_int;
2454  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2456 
2458  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
2459  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
2460  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
2461  CudaFunctions *cu = cu_internal->cuda_dl;
2462  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
2463  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
2464 
2465  ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
2466  if (ret < 0)
2467  return AVERROR_EXTERNAL;
2468 
2469  dst_f = (AVVkFrame *)dst->data[0];
2470 
2471  ret = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
2472  if (ret < 0) {
2473  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2474  return ret;
2475  }
2476 
2477  dst_int = dst_f->internal;
2478 
2479  ret = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
2480  planes, cuda_dev->stream));
2481  if (ret < 0) {
2482  err = AVERROR_EXTERNAL;
2483  goto fail;
2484  }
2485 
2486  for (int i = 0; i < planes; i++) {
2487  CUDA_MEMCPY2D cpy = {
2488  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
2489  .srcDevice = (CUdeviceptr)src->data[i],
2490  .srcPitch = src->linesize[i],
2491  .srcY = 0,
2492 
2493  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
2494  .dstArray = dst_int->cu_array[i],
2495  };
2496 
2497  int p_w, p_h;
2498  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
2499 
2500  cpy.WidthInBytes = p_w * desc->comp[i].step;
2501  cpy.Height = p_h;
2502 
2503  ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
2504  if (ret < 0) {
2505  err = AVERROR_EXTERNAL;
2506  goto fail;
2507  }
2508  }
2509 
2510  ret = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
2511  planes, cuda_dev->stream));
2512  if (ret < 0) {
2513  err = AVERROR_EXTERNAL;
2514  goto fail;
2515  }
2516 
2517  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2518 
2519  av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n");
2520 
2521  return 0;
2522 
2523 fail:
2524  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
2525  vulkan_free_internal(dst_int);
2526  dst_f->internal = NULL;
2527  av_buffer_unref(&dst->buf[0]);
2528  return err;
2529 }
2530 #endif
2531 
2532 static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
2533  const AVFrame *src, int flags)
2534 {
2536 
2537  switch (src->format) {
2538 #if CONFIG_LIBDRM
2539 #if CONFIG_VAAPI
2540  case AV_PIX_FMT_VAAPI:
2541  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2542  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
2543 #endif
2544  case AV_PIX_FMT_DRM_PRIME:
2545  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2546  return vulkan_map_from_drm(hwfc, dst, src, flags);
2547 #endif
2548  default:
2549  return AVERROR(ENOSYS);
2550  }
2551 }
2552 
2553 #if CONFIG_LIBDRM
2554 typedef struct VulkanDRMMapping {
2555  AVDRMFrameDescriptor drm_desc;
2556  AVVkFrame *source;
2557 } VulkanDRMMapping;
2558 
2559 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
2560 {
2561  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
2562 
2563  for (int i = 0; i < drm_desc->nb_objects; i++)
2564  close(drm_desc->objects[i].fd);
2565 
2566  av_free(drm_desc);
2567 }
2568 
2569 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
2570 {
2571  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
2572  if (vulkan_drm_format_map[i].vk_format == vkfmt)
2573  return vulkan_drm_format_map[i].drm_fourcc;
2574  return DRM_FORMAT_INVALID;
2575 }
2576 
2577 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2578  const AVFrame *src, int flags)
2579 {
2580  int err = 0;
2581  VkResult ret;
2582  AVVkFrame *f = (AVVkFrame *)src->data[0];
2584  VulkanFramesPriv *fp = hwfc->internal->priv;
2585  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2586  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2587  VK_LOAD_PFN(hwctx->inst, vkGetMemoryFdKHR);
2588  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
2589  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
2590  };
2591 
2592  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
2593  if (!drm_desc)
2594  return AVERROR(ENOMEM);
2595 
2596  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_EXPORT);
2597  if (err < 0)
2598  goto end;
2599 
2600  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
2601  if (err < 0)
2602  goto end;
2603 
2604  if (p->extensions & EXT_DRM_MODIFIER_FLAGS) {
2605  VK_LOAD_PFN(hwctx->inst, vkGetImageDrmFormatModifierPropertiesEXT);
2606  ret = pfn_vkGetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
2607  &drm_mod);
2608  if (ret != VK_SUCCESS) {
2609  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
2610  err = AVERROR_EXTERNAL;
2611  goto end;
2612  }
2613  }
2614 
2615  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
2616  VkMemoryGetFdInfoKHR export_info = {
2617  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2618  .memory = f->mem[i],
2619  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2620  };
2621 
2622  ret = pfn_vkGetMemoryFdKHR(hwctx->act_dev, &export_info,
2623  &drm_desc->objects[i].fd);
2624  if (ret != VK_SUCCESS) {
2625  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
2626  err = AVERROR_EXTERNAL;
2627  goto end;
2628  }
2629 
2630  drm_desc->nb_objects++;
2631  drm_desc->objects[i].size = f->size[i];
2632  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
2633  }
2634 
2635  drm_desc->nb_layers = planes;
2636  for (int i = 0; i < drm_desc->nb_layers; i++) {
2637  VkSubresourceLayout layout;
2638  VkImageSubresource sub = {
2639  .aspectMask = p->extensions & EXT_DRM_MODIFIER_FLAGS ?
2640  VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2641  VK_IMAGE_ASPECT_COLOR_BIT,
2642  };
2643  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
2644 
2645  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
2646  drm_desc->layers[i].nb_planes = 1;
2647 
2648  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
2649  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
2650  err = AVERROR_PATCHWELCOME;
2651  goto end;
2652  }
2653 
2654  drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
2655 
2656  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
2657  continue;
2658 
2659  vkGetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
2660  drm_desc->layers[i].planes[0].offset = layout.offset;
2661  drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
2662  }
2663 
2664  dst->width = src->width;
2665  dst->height = src->height;
2666  dst->data[0] = (uint8_t *)drm_desc;
2667 
2668  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
2669 
2670  return 0;
2671 
2672 end:
2673  av_free(drm_desc);
2674  return err;
2675 }
2676 
2677 #if CONFIG_VAAPI
2678 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
2679  const AVFrame *src, int flags)
2680 {
2681  int err;
2682  AVFrame *tmp = av_frame_alloc();
2683  if (!tmp)
2684  return AVERROR(ENOMEM);
2685 
2687 
2688  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
2689  if (err < 0)
2690  goto fail;
2691 
2692  err = av_hwframe_map(dst, tmp, flags);
2693  if (err < 0)
2694  goto fail;
2695 
2696  err = ff_hwframe_map_replace(dst, src);
2697 
2698 fail:
2699  av_frame_free(&tmp);
2700  return err;
2701 }
2702 #endif
2703 #endif
2704 
2706  const AVFrame *src, int flags)
2707 {
2709 
2710  switch (dst->format) {
2711 #if CONFIG_LIBDRM
2712  case AV_PIX_FMT_DRM_PRIME:
2713  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2714  return vulkan_map_to_drm(hwfc, dst, src, flags);
2715 #if CONFIG_VAAPI
2716  case AV_PIX_FMT_VAAPI:
2717  if (p->extensions & EXT_EXTERNAL_DMABUF_MEMORY)
2718  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
2719 #endif
2720 #endif
2721  default:
2722  return vulkan_map_frame_to_mem(hwfc, dst, src, flags);
2723  }
2724 }
2725 
2726 typedef struct ImageBuffer {
2727  VkBuffer buf;
2728  VkDeviceMemory mem;
2729  VkMemoryPropertyFlagBits flags;
2731 } ImageBuffer;
2732 
2733 static void free_buf(void *opaque, uint8_t *data)
2734 {
2735  AVHWDeviceContext *ctx = opaque;
2736  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2737  ImageBuffer *vkbuf = (ImageBuffer *)data;
2738 
2739  if (vkbuf->buf)
2740  vkDestroyBuffer(hwctx->act_dev, vkbuf->buf, hwctx->alloc);
2741  if (vkbuf->mem)
2742  vkFreeMemory(hwctx->act_dev, vkbuf->mem, hwctx->alloc);
2743 
2744  av_free(data);
2745 }
2746 
2748 {
2749  size_t size;
2750  *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
2751  size = height*(*stride);
2752  size = FFALIGN(size, p->props.properties.limits.minMemoryMapAlignment);
2753  return size;
2754 }
2755 
2757  VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags,
2758  size_t size, uint32_t req_memory_bits, int host_mapped,
2759  void *create_pnext, void *alloc_pnext)
2760 {
2761  int err;
2762  VkResult ret;
2763  int use_ded_mem;
2764  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2765 
2766  VkBufferCreateInfo buf_spawn = {
2767  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
2768  .pNext = create_pnext,
2769  .usage = usage,
2770  .size = size,
2771  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
2772  };
2773 
2774  VkBufferMemoryRequirementsInfo2 req_desc = {
2775  .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
2776  };
2777  VkMemoryDedicatedAllocateInfo ded_alloc = {
2778  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2779  .pNext = alloc_pnext,
2780  };
2781  VkMemoryDedicatedRequirements ded_req = {
2782  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2783  };
2784  VkMemoryRequirements2 req = {
2785  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2786  .pNext = &ded_req,
2787  };
2788 
2789  ImageBuffer *vkbuf = av_mallocz(sizeof(*vkbuf));
2790  if (!vkbuf)
2791  return AVERROR(ENOMEM);
2792 
2793  vkbuf->mapped_mem = host_mapped;
2794 
2795  ret = vkCreateBuffer(hwctx->act_dev, &buf_spawn, NULL, &vkbuf->buf);
2796  if (ret != VK_SUCCESS) {
2797  av_log(ctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
2798  vk_ret2str(ret));
2799  err = AVERROR_EXTERNAL;
2800  goto fail;
2801  }
2802 
2803  req_desc.buffer = vkbuf->buf;
2804 
2805  vkGetBufferMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
2806 
2807  /* In case the implementation prefers/requires dedicated allocation */
2808  use_ded_mem = ded_req.prefersDedicatedAllocation |
2809  ded_req.requiresDedicatedAllocation;
2810  if (use_ded_mem)
2811  ded_alloc.buffer = vkbuf->buf;
2812 
2813  /* Additional requirements imposed on us */
2814  if (req_memory_bits)
2815  req.memoryRequirements.memoryTypeBits &= req_memory_bits;
2816 
2817  err = alloc_mem(ctx, &req.memoryRequirements, flags,
2818  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
2819  &vkbuf->flags, &vkbuf->mem);
2820  if (err)
2821  goto fail;
2822 
2823  ret = vkBindBufferMemory(hwctx->act_dev, vkbuf->buf, vkbuf->mem, 0);
2824  if (ret != VK_SUCCESS) {
2825  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
2826  vk_ret2str(ret));
2827  err = AVERROR_EXTERNAL;
2828  goto fail;
2829  }
2830 
2831  *buf = av_buffer_create((uint8_t *)vkbuf, sizeof(*vkbuf), free_buf, ctx, 0);
2832  if (!(*buf)) {
2833  err = AVERROR(ENOMEM);
2834  goto fail;
2835  }
2836 
2837  return 0;
2838 
2839 fail:
2840  free_buf(ctx, (uint8_t *)vkbuf);
2841  return err;
2842 }
2843 
2844 /* Skips mapping of host mapped buffers but still invalidates them */
2846  int nb_buffers, int invalidate)
2847 {
2848  VkResult ret;
2849  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2850  VkMappedMemoryRange invalidate_ctx[AV_NUM_DATA_POINTERS];
2851  int invalidate_count = 0;
2852 
2853  for (int i = 0; i < nb_buffers; i++) {
2854  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2855  if (vkbuf->mapped_mem)
2856  continue;
2857 
2858  ret = vkMapMemory(hwctx->act_dev, vkbuf->mem, 0,
2859  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
2860  if (ret != VK_SUCCESS) {
2861  av_log(ctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
2862  vk_ret2str(ret));
2863  return AVERROR_EXTERNAL;
2864  }
2865  }
2866 
2867  if (!invalidate)
2868  return 0;
2869 
2870  for (int i = 0; i < nb_buffers; i++) {
2871  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2872  const VkMappedMemoryRange ival_buf = {
2873  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
2874  .memory = vkbuf->mem,
2875  .size = VK_WHOLE_SIZE,
2876  };
2877 
2878  /* For host imported memory Vulkan says to use platform-defined
2879  * sync methods, but doesn't really say not to call flush or invalidate
2880  * on original host pointers. It does explicitly allow to do that on
2881  * host-mapped pointers which are then mapped again using vkMapMemory,
2882  * but known implementations return the original pointers when mapped
2883  * again. */
2884  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
2885  continue;
2886 
2887  invalidate_ctx[invalidate_count++] = ival_buf;
2888  }
2889 
2890  if (invalidate_count) {
2891  ret = vkInvalidateMappedMemoryRanges(hwctx->act_dev, invalidate_count,
2892  invalidate_ctx);
2893  if (ret != VK_SUCCESS)
2894  av_log(ctx, AV_LOG_WARNING, "Failed to invalidate memory: %s\n",
2895  vk_ret2str(ret));
2896  }
2897 
2898  return 0;
2899 }
2900 
2902  int nb_buffers, int flush)
2903 {
2904  int err = 0;
2905  VkResult ret;
2906  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2907  VkMappedMemoryRange flush_ctx[AV_NUM_DATA_POINTERS];
2908  int flush_count = 0;
2909 
2910  if (flush) {
2911  for (int i = 0; i < nb_buffers; i++) {
2912  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2913  const VkMappedMemoryRange flush_buf = {
2914  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
2915  .memory = vkbuf->mem,
2916  .size = VK_WHOLE_SIZE,
2917  };
2918 
2919  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
2920  continue;
2921 
2922  flush_ctx[flush_count++] = flush_buf;
2923  }
2924  }
2925 
2926  if (flush_count) {
2927  ret = vkFlushMappedMemoryRanges(hwctx->act_dev, flush_count, flush_ctx);
2928  if (ret != VK_SUCCESS) {
2929  av_log(ctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
2930  vk_ret2str(ret));
2931  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
2932  }
2933  }
2934 
2935  for (int i = 0; i < nb_buffers; i++) {
2936  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
2937  if (vkbuf->mapped_mem)
2938  continue;
2939 
2940  vkUnmapMemory(hwctx->act_dev, vkbuf->mem);
2941  }
2942 
2943  return err;
2944 }
2945 
2947  AVBufferRef **bufs, size_t *buf_offsets,
2948  const int *buf_stride, int w,
2949  int h, enum AVPixelFormat pix_fmt, int to_buf)
2950 {
2951  int err;
2952  AVVkFrame *frame = (AVVkFrame *)f->data[0];
2953  VulkanFramesPriv *fp = hwfc->internal->priv;
2954 
2955  int bar_num = 0;
2956  VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS];
2957 
2958  const int planes = av_pix_fmt_count_planes(pix_fmt);
2959  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
2960 
2961  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
2962  VulkanExecCtx *ectx = to_buf ? &fp->download_ctx : &fp->upload_ctx;
2963  VkCommandBuffer cmd_buf = get_buf_exec_ctx(hwfc, ectx);
2964 
2965  VkSubmitInfo s_info = {
2966  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
2967  .pSignalSemaphores = frame->sem,
2968  .pWaitSemaphores = frame->sem,
2969  .pWaitDstStageMask = sem_wait_dst,
2970  .signalSemaphoreCount = planes,
2971  .waitSemaphoreCount = planes,
2972  };
2973 
2974  if ((err = wait_start_exec_ctx(hwfc, ectx)))
2975  return err;
2976 
2977  /* Change the image layout to something more optimal for transfers */
2978  for (int i = 0; i < planes; i++) {
2979  VkImageLayout new_layout = to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL :
2980  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2981  VkAccessFlags new_access = to_buf ? VK_ACCESS_TRANSFER_READ_BIT :
2982  VK_ACCESS_TRANSFER_WRITE_BIT;
2983 
2984  sem_wait_dst[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2985 
2986  /* If the layout matches and we have read access skip the barrier */
2987  if ((frame->layout[i] == new_layout) && (frame->access[i] & new_access))
2988  continue;
2989 
2990  img_bar[bar_num].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2991  img_bar[bar_num].srcAccessMask = 0x0;
2992  img_bar[bar_num].dstAccessMask = new_access;
2993  img_bar[bar_num].oldLayout = frame->layout[i];
2994  img_bar[bar_num].newLayout = new_layout;
2995  img_bar[bar_num].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2996  img_bar[bar_num].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2997  img_bar[bar_num].image = frame->img[i];
2998  img_bar[bar_num].subresourceRange.levelCount = 1;
2999  img_bar[bar_num].subresourceRange.layerCount = 1;
3000  img_bar[bar_num].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3001 
3002  frame->layout[i] = img_bar[bar_num].newLayout;
3003  frame->access[i] = img_bar[bar_num].dstAccessMask;
3004 
3005  bar_num++;
3006  }
3007 
3008  if (bar_num)
3009  vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3010  VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
3011  0, NULL, 0, NULL, bar_num, img_bar);
3012 
3013  /* Schedule a copy for each plane */
3014  for (int i = 0; i < planes; i++) {
3015  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3016  VkBufferImageCopy buf_reg = {
3017  .bufferOffset = buf_offsets[i],
3018  .bufferRowLength = buf_stride[i] / desc->comp[i].step,
3019  .imageSubresource.layerCount = 1,
3020  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3021  .imageOffset = { 0, 0, 0, },
3022  };
3023 
3024  int p_w, p_h;
3025  get_plane_wh(&p_w, &p_h, pix_fmt, w, h, i);
3026 
3027  buf_reg.bufferImageHeight = p_h;
3028  buf_reg.imageExtent = (VkExtent3D){ p_w, p_h, 1, };
3029 
3030  if (to_buf)
3031  vkCmdCopyImageToBuffer(cmd_buf, frame->img[i], frame->layout[i],
3032  vkbuf->buf, 1, &buf_reg);
3033  else
3034  vkCmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[i],
3035  frame->layout[i], 1, &buf_reg);
3036  }
3037 
3038  /* When uploading, do this asynchronously if the source is refcounted by
3039  * keeping the buffers as a submission dependency.
3040  * The hwcontext is guaranteed to not be freed until all frames are freed
3041  * in the frames_unint function.
3042  * When downloading to buffer, do this synchronously and wait for the
3043  * queue submission to finish executing */
3044  if (!to_buf) {
3045  int ref;
3046  for (ref = 0; ref < AV_NUM_DATA_POINTERS; ref++) {
3047  if (!f->buf[ref])
3048  break;
3049  if ((err = add_buf_dep_exec_ctx(hwfc, ectx, &f->buf[ref], 1)))
3050  return err;
3051  }
3052  if (ref && (err = add_buf_dep_exec_ctx(hwfc, ectx, bufs, planes)))
3053  return err;
3054  return submit_exec_ctx(hwfc, ectx, &s_info, !ref);
3055  } else {
3056  return submit_exec_ctx(hwfc, ectx, &s_info, 1);
3057  }
3058 }
3059 
3060 static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf,
3061  const AVFrame *swf, int from)
3062 {
3063  int err = 0;
3064  VkResult ret;
3065  AVVkFrame *f = (AVVkFrame *)vkf->data[0];
3066  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
3067  AVVulkanDeviceContext *hwctx = dev_ctx->hwctx;
3069 
3070  AVFrame tmp;
3071  AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 };
3072  size_t buf_offsets[AV_NUM_DATA_POINTERS] = { 0 };
3073 
3074  int p_w, p_h;
3075  const int planes = av_pix_fmt_count_planes(swf->format);
3076 
3077  int host_mapped[AV_NUM_DATA_POINTERS] = { 0 };
3078  const int map_host = !!(p->extensions & EXT_EXTERNAL_HOST_MEMORY);
3079 
3080  VK_LOAD_PFN(hwctx->inst, vkGetMemoryHostPointerPropertiesEXT);
3081 
3082  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
3083  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
3084  return AVERROR(EINVAL);
3085  }
3086 
3087  if (swf->width > hwfc->width || swf->height > hwfc->height)
3088  return AVERROR(EINVAL);
3089 
3090  /* For linear, host visiable images */
3091  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
3092  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
3093  AVFrame *map = av_frame_alloc();
3094  if (!map)
3095  return AVERROR(ENOMEM);
3096  map->format = swf->format;
3097 
3098  err = vulkan_map_frame_to_mem(hwfc, map, vkf, AV_HWFRAME_MAP_WRITE);
3099  if (err)
3100  return err;
3101 
3102  err = av_frame_copy((AVFrame *)(from ? swf : map), from ? map : swf);
3103  av_frame_free(&map);
3104  return err;
3105  }
3106 
3107  /* Create buffers */
3108  for (int i = 0; i < planes; i++) {
3109  size_t req_size;
3110 
3111  VkExternalMemoryBufferCreateInfo create_desc = {
3112  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
3113  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3114  };
3115 
3116  VkImportMemoryHostPointerInfoEXT import_desc = {
3117  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3118  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3119  };
3120 
3121  VkMemoryHostPointerPropertiesEXT p_props = {
3122  .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
3123  };
3124 
3125  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3126 
3127  tmp.linesize[i] = FFABS(swf->linesize[i]);
3128 
3129  /* Do not map images with a negative stride */
3130  if (map_host && swf->linesize[i] > 0) {
3131  size_t offs;
3132  offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment;
3133  import_desc.pHostPointer = swf->data[i] - offs;
3134 
3135  /* We have to compensate for the few extra bytes of padding we
3136  * completely ignore at the start */
3137  req_size = FFALIGN(offs + tmp.linesize[i] * p_h,
3138  p->hprops.minImportedHostPointerAlignment);
3139 
3140  ret = pfn_vkGetMemoryHostPointerPropertiesEXT(hwctx->act_dev,
3141  import_desc.handleType,
3142  import_desc.pHostPointer,
3143  &p_props);
3144 
3145  if (ret == VK_SUCCESS) {
3146  host_mapped[i] = 1;
3147  buf_offsets[i] = offs;
3148  }
3149  }
3150 
3151  if (!host_mapped[i])
3152  req_size = get_req_buffer_size(p, &tmp.linesize[i], p_h);
3153 
3154  err = create_buf(dev_ctx, &bufs[i],
3155  from ? VK_BUFFER_USAGE_TRANSFER_DST_BIT :
3156  VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
3157  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
3158  req_size, p_props.memoryTypeBits, host_mapped[i],
3159  host_mapped[i] ? &create_desc : NULL,
3160  host_mapped[i] ? &import_desc : NULL);
3161  if (err)
3162  goto end;
3163  }
3164 
3165  if (!from) {
3166  /* Map, copy image to buffer, unmap */
3167  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3168  goto end;
3169 
3170  for (int i = 0; i < planes; i++) {
3171  if (host_mapped[i])
3172  continue;
3173 
3174  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3175 
3176  av_image_copy_plane(tmp.data[i], tmp.linesize[i],
3177  (const uint8_t *)swf->data[i], swf->linesize[i],
3178  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3179  p_h);
3180  }
3181 
3182  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3183  goto end;
3184  }
3185 
3186  /* Copy buffers into/from image */
3187  err = transfer_image_buf(hwfc, vkf, bufs, buf_offsets, tmp.linesize,
3188  swf->width, swf->height, swf->format, from);
3189 
3190  if (from) {
3191  /* Map, copy image to buffer, unmap */
3192  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3193  goto end;
3194 
3195  for (int i = 0; i < planes; i++) {
3196  if (host_mapped[i])
3197  continue;
3198 
3199  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3200 
3201  av_image_copy_plane(swf->data[i], swf->linesize[i],
3202  (const uint8_t *)tmp.data[i], tmp.linesize[i],
3203  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3204  p_h);
3205  }
3206 
3207  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3208  goto end;
3209  }
3210 
3211 end:
3212  for (int i = 0; i < planes; i++)
3213  av_buffer_unref(&bufs[i]);
3214 
3215  return err;
3216 }
3217 
3219  const AVFrame *src)
3220 {
3222 
3223  switch (src->format) {
3224 #if CONFIG_CUDA
3225  case AV_PIX_FMT_CUDA:
3226  if ((p->extensions & EXT_EXTERNAL_FD_MEMORY) &&
3227  (p->extensions & EXT_EXTERNAL_FD_SEM))
3228  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
3229 #endif
3230  default:
3231  if (src->hw_frames_ctx)
3232  return AVERROR(ENOSYS);
3233  else
3234  return vulkan_transfer_data(hwfc, dst, src, 0);
3235  }
3236 }
3237 
3238 #if CONFIG_CUDA
3239 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
3240  const AVFrame *src)
3241 {
3242  int err;
3243  VkResult ret;
3244  CUcontext dummy;
3245  AVVkFrame *dst_f;
3246  AVVkFrameInternal *dst_int;
3247  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3249 
3251  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3252  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3253  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3254  CudaFunctions *cu = cu_internal->cuda_dl;
3255  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
3256  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
3257 
3258  ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
3259  if (ret < 0)
3260  return AVERROR_EXTERNAL;
3261 
3262  dst_f = (AVVkFrame *)src->data[0];
3263 
3264  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
3265  if (err < 0) {
3266  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3267  return err;
3268  }
3269 
3270  dst_int = dst_f->internal;
3271 
3272  ret = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
3273  planes, cuda_dev->stream));
3274  if (ret < 0) {
3275  err = AVERROR_EXTERNAL;
3276  goto fail;
3277  }
3278 
3279  for (int i = 0; i < planes; i++) {
3280  CUDA_MEMCPY2D cpy = {
3281  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
3282  .dstDevice = (CUdeviceptr)dst->data[i],
3283  .dstPitch = dst->linesize[i],
3284  .dstY = 0,
3285 
3286  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
3287  .srcArray = dst_int->cu_array[i],
3288  };
3289 
3290  int w, h;
3291  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3292 
3293  cpy.WidthInBytes = w * desc->comp[i].step;
3294  cpy.Height = h;
3295 
3296  ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
3297  if (ret < 0) {
3298  err = AVERROR_EXTERNAL;
3299  goto fail;
3300  }
3301  }
3302 
3303  ret = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
3304  planes, cuda_dev->stream));
3305  if (ret < 0) {
3306  err = AVERROR_EXTERNAL;
3307  goto fail;
3308  }
3309 
3310  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3311 
3312  av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n");
3313 
3314  return 0;
3315 
3316 fail:
3317  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3318  vulkan_free_internal(dst_int);
3319  dst_f->internal = NULL;
3320  av_buffer_unref(&dst->buf[0]);
3321  return err;
3322 }
3323 #endif
3324 
3326  const AVFrame *src)
3327 {
3329 
3330  switch (dst->format) {
3331 #if CONFIG_CUDA
3332  case AV_PIX_FMT_CUDA:
3333  if ((p->extensions & EXT_EXTERNAL_FD_MEMORY) &&
3334  (p->extensions & EXT_EXTERNAL_FD_SEM))
3335  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
3336 #endif
3337  default:
3338  if (dst->hw_frames_ctx)
3339  return AVERROR(ENOSYS);
3340  else
3341  return vulkan_transfer_data(hwfc, src, dst, 1);
3342  }
3343 }
3344 
3346  AVHWFramesContext *src_fc, int flags)
3347 {
3348  return vulkan_frames_init(dst_fc);
3349 }
3350 
3352 {
3353  return av_mallocz(sizeof(AVVkFrame));
3354 }
3355 
3358  .name = "Vulkan",
3359 
3360  .device_hwctx_size = sizeof(AVVulkanDeviceContext),
3361  .device_priv_size = sizeof(VulkanDevicePriv),
3362  .frames_hwctx_size = sizeof(AVVulkanFramesContext),
3363  .frames_priv_size = sizeof(VulkanFramesPriv),
3364 
3365  .device_init = &vulkan_device_init,
3366  .device_create = &vulkan_device_create,
3367  .device_derive = &vulkan_device_derive,
3368 
3369  .frames_get_constraints = &vulkan_frames_get_constraints,
3370  .frames_init = vulkan_frames_init,
3371  .frames_get_buffer = vulkan_get_buffer,
3372  .frames_uninit = vulkan_frames_uninit,
3373 
3374  .transfer_get_formats = vulkan_transfer_get_formats,
3375  .transfer_data_to = vulkan_transfer_data_to,
3376  .transfer_data_from = vulkan_transfer_data_from,
3377 
3378  .map_to = vulkan_map_to,
3379  .map_from = vulkan_map_from,
3380  .frames_derive_to = &vulkan_frames_derive_to,
3381 
3382  .pix_fmts = (const enum AVPixelFormat []) {
3385  },
3386 };
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:534
#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
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.
#define FF_ARRAY_ELEMS(a)
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.
static const struct @322 planes[]
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
#define f(width, name)
Definition: cbs_vp9.c:255
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:255
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
static const int weights[]
Definition: hevc_pel.c:32
#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
The mapping must be writeable.
Definition: hwcontext.h:528
#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:133
#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:105
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:39
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
The mapping must be readable.
Definition: hwcontext.h:524
#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
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
#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
static const struct @310 vk_pixfmt_map[]
#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
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)
#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:561
#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:373
#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:27