FFmpeg  4.4.6
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 {
140  enum AVPixelFormat pixfmt;
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]);
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 
1397  vulkan_free_internal(f->internal);
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 {
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 
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;
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 */
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,
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:
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();
2287  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
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 
2297  tmp->format = AV_PIX_FMT_DRM_PRIME;
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 
2457  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
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 
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 
2686  tmp->format = AV_PIX_FMT_DRM_PRIME;
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);
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 
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 };
static void flush(AVCodecContext *avctx)
static const char *const format[]
Definition: af_aiir.c:456
static cqueue * cqueue_create(int size, int max_size)
#define av_unused
Definition: attributes.h:131
uint8_t
#define flags(name, subs,...)
Definition: cbs_av1.c:572
#define f(width, name)
Definition: cbs_vp9.c:255
uint64_t layout
#define fail()
Definition: checkasm.h:133
#define FFMIN(a, b)
Definition: common.h:105
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
#define NULL
Definition: coverity.c:32
#define CHECK_CU(x)
Definition: cuviddec.c:108
static enum AVPixelFormat pix_fmt
static AVFrame * frame
static float sub(float src0, float src1)
int8_t exp
Definition: eval.c:72
const char * usage
Definition: floatimg_cmp.c:60
#define AV_NUM_DATA_POINTERS
Definition: frame.h:319
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
AVBufferRef * av_buffer_create(uint8_t *data, buffer_size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:379
AVBufferPool * av_buffer_pool_init2(buffer_size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, buffer_size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:245
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
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:799
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
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
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
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
void * av_mallocz_array(size_t nmemb, size_t size)
Allocate a memory block for an array with av_mallocz().
Definition: mem.c:190
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
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
#define LIBAVUTIL_VERSION_MINOR
Definition: version.h:82
#define LIBAVUTIL_VERSION_MAJOR
Definition: version.h:81
#define LIBAVUTIL_VERSION_MICRO
Definition: version.h:83
int index
Definition: gxfenc.c:89
static const int weights[]
Definition: hevc_pel.c:32
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 av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:789
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
AVHWFrameTransferDirection
Definition: hwcontext.h:415
@ AV_HWDEVICE_TYPE_VULKAN
Definition: hwcontext.h:39
@ AV_HWDEVICE_TYPE_CUDA
Definition: hwcontext.h:30
@ AV_HWDEVICE_TYPE_DRM
Definition: hwcontext.h:36
@ AV_HWDEVICE_TYPE_VAAPI
Definition: hwcontext.h:31
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition: hwcontext.h:524
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition: hwcontext.h:528
@ AV_HWFRAME_MAP_OVERWRITE
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:534
FFmpeg internal API for CUDA.
API-specific header for AV_HWDEVICE_TYPE_DRM.
cl_device_type type
API-specific header for AV_HWDEVICE_TYPE_VAAPI.
const VDPAUPixFmtMap * map
static int submit_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, VkSubmitInfo *s_info, int synchronous)
static int wait_start_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
#define CASE(VAL)
static int vulkan_frames_init(AVHWFramesContext *hwfc)
#define SEARCH_FLAGS(expr, out)
static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req, VkMemoryPropertyFlagBits req_flags, const void *alloc_extension, VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, const AVFrame *swf, int from)
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static void free_buf(void *opaque, uint8_t *data)
static int vulkan_map_frame_to_mem(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
#define CHECK_QUEUE(type, n)
static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, void *alloc_pnext, size_t alloc_pnext_stride)
static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
static void try_export_flags(AVHWFramesContext *hwfc, VkExternalMemoryHandleTypeFlags *comp_handle_types, VkExternalMemoryHandleTypeFlagBits *iexp, VkExternalMemoryHandleTypeFlagBits exp)
static int unmap_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, int nb_buffers, int flush)
static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
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)
static void unref_exec_ctx_deps(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
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)
static int find_device(AVHWDeviceContext *ctx, VulkanDeviceSelection *select)
#define ADD_VAL_TO_LIST(list, count, val)
static void vulkan_frame_free(void *opaque, uint8_t *data)
static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VulkanDeviceSelection *dev_select, AVDictionary *opts, int flags)
static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, const char *const **dst, uint32_t *num, int debug)
static size_t get_req_buffer_size(VulkanDevicePriv *p, int *stride, int height)
static int search_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
static int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
static int vulkan_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
static int vulkan_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, AVDictionary *opts, int flags)
static int vulkan_device_init(AVHWDeviceContext *ctx)
static int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags)
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues)
AVVkFrame * av_vk_frame_alloc(void)
Allocates a single AVVkFrame and initializes everything as 0.
static int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[], int nb_buffers, int invalidate)
static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *data, void *priv)
const VkFormat vkfmts[4]
static void get_plane_wh(int *w, int *h, enum AVPixelFormat format, int frame_w, int frame_h, int plane)
static const struct @310 vk_pixfmt_map[]
static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, AVVkFrame *frame, enum PrepMode pmode)
static AVBufferRef * vulkan_pool_alloc(void *opaque, buffer_size_t size)
static const char * vk_ret2str(VkResult res)
enum AVPixelFormat pixfmt
static const char * vk_dev_type(enum VkPhysicalDeviceType type)
static void vulkan_device_free(AVHWDeviceContext *ctx)
#define GET_QUEUE_COUNT(hwctx, graph, comp, tx)
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.
#define ADD_QUEUE(fidx, graph, comp, tx)
#define VK_LOAD_PFN(inst, name)
#define COPY_FEATURE(DST, NAME)
static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
static int pixfmt_is_supported(AVVulkanDeviceContext *hwctx, enum AVPixelFormat p, int linear)
const HWContextType ff_hwcontext_type_vulkan
static int add_buf_dep_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, AVBufferRef *const *deps, int nb_deps)
static const VulkanOptExtension optional_instance_exts[]
static void vulkan_free_internal(AVVkFrameInternal *internal)
VulkanExtensions
@ EXT_HOST_QUERY_RESET
@ EXT_PUSH_DESCRIPTORS
@ EXT_EXTERNAL_HOST_MEMORY
@ EXT_EXTERNAL_FD_MEMORY
@ EXT_DRM_MODIFIER_FLAGS
@ EXT_EXTERNAL_DMABUF_MEMORY
@ EXT_NO_FLAG
@ EXT_EXTERNAL_FD_SEM
static void vulkan_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
static const VulkanOptExtension optional_device_exts[]
static int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame, VkImageTiling tiling, VkImageUsageFlagBits usage, void *create_pnext)
@ PREP_MODE_WRITE
@ PREP_MODE_RO_SHADER
@ PREP_MODE_EXTERNAL_EXPORT
static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
#define DEFAULT_USAGE_FLAGS
static void free_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
API-specific header for AV_HWDEVICE_TYPE_VULKAN.
misc image utilities
int i
Definition: input.c:407
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:121
const char * from
Definition: jacosubdec.c:65
int buffer_size_t
Definition: internal.h:306
const char * desc
Definition: libsvtav1.c:79
uint8_t w
Definition: llviddspenc.c:39
static const struct @322 planes[]
int stride
Definition: mace.c:144
#define FFALIGN(x, a)
Definition: macros.h:48
#define htype
int dummy
Definition: motion.c:64
const char data[16]
Definition: mxf.c:142
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2613
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
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2573
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:148
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:144
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:410
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:428
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:406
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:399
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:421
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:438
#define AV_PIX_FMT_YUVA420P16
Definition: pixfmt.h:441
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:403
#define AV_PIX_FMT_YUVA420P10
Definition: pixfmt.h:436
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:404
#define AV_PIX_FMT_P010
Definition: pixfmt.h:448
#define AV_PIX_FMT_P016
Definition: pixfmt.h:449
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:400
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:389
#define AV_PIX_FMT_BGR32
Definition: pixfmt.h:374
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:385
#define AV_PIX_FMT_YUVA422P10
Definition: pixfmt.h:437
#define AV_PIX_FMT_X2RGB10
Definition: pixfmt.h:452
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:431
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
@ AV_PIX_FMT_NV12
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
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:356
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
@ AV_PIX_FMT_NV42
as above, but U and V bytes are swapped
Definition: pixfmt.h:349
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
Definition: pixfmt.h:90
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
@ AV_PIX_FMT_NB
number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of...
Definition: pixfmt.h:363
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:101
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition: pixfmt.h:235
@ AV_PIX_FMT_NV24
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
@ AV_PIX_FMT_DRM_PRIME
DRM-managed buffers exposed through PRIME buffer sharing.
Definition: pixfmt.h:328
@ AV_PIX_FMT_NV16
interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:201
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:177
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:215
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:176
@ AV_PIX_FMT_VAAPI
Definition: pixfmt.h:122
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
#define AV_PIX_FMT_YUVA422P12
Definition: pixfmt.h:439
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:391
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:386
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:411
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:383
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:443
#define AV_PIX_FMT_YUVA422P16
Definition: pixfmt.h:442
#define AV_PIX_FMT_YUVA444P12
Definition: pixfmt.h:440
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:429
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:412
#define AV_PIX_FMT_0BGR32
Definition: pixfmt.h:377
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:402
#define fp
Definition: regdef.h:44
formats
Definition: signature.h:48
#define FF_ARRAY_ELEMS(a)
A reference to a data buffer.
Definition: buffer.h:84
uint8_t * data
The data buffer.
Definition: buffer.h:92
This struct is allocated as AVHWDeviceContext.hwctx.
AVCUDADeviceContextInternal * internal
int fd
File descriptor of DRM device.
DRM frame descriptor.
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
int nb_layers
Number of layers in the frame.
int nb_objects
Number of DRM objects making up this frame.
AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]
Array of layers in the frame.
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
int nb_planes
Number of planes in the layer.
uint32_t format
Format of the layer (DRM_FORMAT_*).
int fd
DRM PRIME fd for the object.
Definition: hwcontext_drm.h:52
size_t size
Total size of the object.
Definition: hwcontext_drm.h:58
uint64_t format_modifier
Format modifier applied to the object (DRM_FORMAT_MOD_*).
Definition: hwcontext_drm.h:65
ptrdiff_t pitch
Pitch (linesize) of this plane.
Definition: hwcontext_drm.h:87
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor.
Definition: hwcontext_drm.h:79
ptrdiff_t offset
Offset within that object of this plane.
Definition: hwcontext_drm.h:83
char * value
Definition: dict.h:83
AVFormatInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1699
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:332
int width
Definition: frame.h:376
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition: frame.h:657
int height
Definition: frame.h:376
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:509
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:349
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:391
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
AVHWDeviceInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:71
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:79
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:453
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:478
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
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
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:471
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:162
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
AVHWFramesInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:134
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:149
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:190
AVBufferPool * pool_internal
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
VAAPI connection details.
VADisplay display
The VADisplay handle, to be filled by the user.
size_t size[AV_NUM_DATA_POINTERS]
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization semaphores.
struct AVVkFrameInternal * internal
Internal data.
VkDeviceMemory mem[AV_NUM_DATA_POINTERS]
Memory backing the images.
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
VkPhysicalDevice phys_dev
Physical device.
int queue_family_tx_index
Queue family index to use for transfer operations, and the amount of queues enabled.
int queue_family_index
Queue family index for graphics.
const char *const * enabled_dev_extensions
Enabled device extensions.
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
VkDevice act_dev
Active device.
int queue_family_comp_index
Queue family index for compute ops, and the amount of queues enabled.
const char *const * enabled_inst_extensions
Enabled instance extensions.
VkInstance inst
Vulkan instance.
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation.
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
void * create_pnext
Extension data for image creation.
VkImageTiling tiling
Controls the tiling of allocated frames.
void * alloc_pnext[AV_NUM_DATA_POINTERS]
Extension data for memory allocation.
VkImageUsageFlagBits usage
Defines extra usage of output frames.
enum AVHWDeviceType type
void * priv
Hardware-specific private data associated with the mapping.
VkMemoryPropertyFlagBits flags
VkDeviceMemory mem
VkPhysicalDeviceMemoryProperties mprops
VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
VkPhysicalDeviceProperties2 props
VkDebugUtilsMessengerEXT debug_ctx
uint8_t uuid[VK_UUID_SIZE]
VkCommandPool pool
VkCommandBuffer * bufs
VulkanQueueCtx * queues
VulkanExecCtx download_ctx
VulkanExecCtx conv_ctx
VulkanExecCtx upload_ctx
AVVkFrame * frame
AVBufferRef ** buf_deps
#define av_free(p)
#define av_malloc_array(a, b)
#define av_freep(p)
#define av_log(a,...)
static uint8_t tmp[11]
Definition: aes_ctr.c:27
#define src
Definition: vp8dsp.c:255
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
AVFormatContext * ctx
Definition: movenc.c:48
AVDictionary * opts
Definition: movenc.c:50
#define height
int size
if(ret< 0)
Definition: vf_mcdeint.c:282
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:747