FFmpeg
hwcontext_vulkan.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #define VK_NO_PROTOTYPES
20 #define VK_ENABLE_BETA_EXTENSIONS
21 
22 #ifdef _WIN32
23 #include <windows.h> /* Included to prevent conflicts with CreateSemaphore */
24 #include <versionhelpers.h>
25 #include "compat/w32dlfcn.h"
26 #else
27 #include <dlfcn.h>
28 #endif
29 
30 #include <unistd.h>
31 
32 #include "config.h"
33 #include "pixdesc.h"
34 #include "avstring.h"
35 #include "imgutils.h"
36 #include "hwcontext.h"
37 #include "avassert.h"
38 #include "hwcontext_internal.h"
39 #include "hwcontext_vulkan.h"
40 
41 #include "vulkan.h"
42 #include "vulkan_loader.h"
43 
44 #if CONFIG_LIBDRM
45 #include <xf86drm.h>
46 #include <drm_fourcc.h>
47 #include "hwcontext_drm.h"
48 #if CONFIG_VAAPI
49 #include <va/va_drmcommon.h>
50 #include "hwcontext_vaapi.h"
51 #endif
52 #endif
53 
54 #if CONFIG_CUDA
56 #include "cuda_check.h"
57 #define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x)
58 #endif
59 
60 typedef struct VulkanQueueCtx {
61  VkFence fence;
62  VkQueue queue;
64 
65  /* Buffer dependencies */
70 
71 typedef struct VulkanExecCtx {
72  VkCommandPool pool;
73  VkCommandBuffer *bufs;
75  int nb_queues;
78 
79 typedef struct VulkanDevicePriv {
80  /* Vulkan library and loader functions */
81  void *libvulkan;
83 
84  /* Properties */
85  VkPhysicalDeviceProperties2 props;
86  VkPhysicalDeviceMemoryProperties mprops;
87  VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops;
88 
89  /* Features */
90  VkPhysicalDeviceVulkan11Features device_features_1_1;
91  VkPhysicalDeviceVulkan12Features device_features_1_2;
92 
93  /* Queues */
94  uint32_t qfs[5];
95  int num_qfs;
96 
97  /* Debug callback */
98  VkDebugUtilsMessengerEXT debug_ctx;
99 
100  /* Extensions */
102 
103  /* Settings */
105 
106  /* Option to allocate all image planes in a single allocation */
108 
109  /* Nvidia */
111 
112  /* Intel */
115 
116 typedef struct VulkanFramesPriv {
117  /* Image conversions */
119 
120  /* Image transfers */
123 
124  /* Modifier info list to free at uninit */
125  VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
127 
128 typedef struct AVVkFrameInternal {
129 #if CONFIG_CUDA
130  /* Importing external memory into cuda is really expensive so we keep the
131  * memory imported all the time */
132  AVBufferRef *cuda_fc_ref; /* Need to keep it around for uninit */
133  CUexternalMemory ext_mem[AV_NUM_DATA_POINTERS];
134  CUmipmappedArray cu_mma[AV_NUM_DATA_POINTERS];
135  CUarray cu_array[AV_NUM_DATA_POINTERS];
136  CUexternalSemaphore cu_sem[AV_NUM_DATA_POINTERS];
137 #ifdef _WIN32
138  HANDLE ext_mem_handle[AV_NUM_DATA_POINTERS];
139  HANDLE ext_sem_handle[AV_NUM_DATA_POINTERS];
140 #endif
141 #endif
143 
144 #define ADD_VAL_TO_LIST(list, count, val) \
145  do { \
146  list = av_realloc_array(list, sizeof(*list), ++count); \
147  if (!list) { \
148  err = AVERROR(ENOMEM); \
149  goto fail; \
150  } \
151  list[count - 1] = av_strdup(val); \
152  if (!list[count - 1]) { \
153  err = AVERROR(ENOMEM); \
154  goto fail; \
155  } \
156  } while(0)
157 
158 #define RELEASE_PROPS(props, count) \
159  if (props) { \
160  for (int i = 0; i < count; i++) \
161  av_free((void *)((props)[i])); \
162  av_free((void *)props); \
163  }
164 
165 static const struct {
167  const VkFormat vkfmts[4];
168 } vk_pixfmt_map[] = {
169  { AV_PIX_FMT_GRAY8, { VK_FORMAT_R8_UNORM } },
170  { AV_PIX_FMT_GRAY16, { VK_FORMAT_R16_UNORM } },
171  { AV_PIX_FMT_GRAYF32, { VK_FORMAT_R32_SFLOAT } },
172 
173  { AV_PIX_FMT_NV12, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
174  { AV_PIX_FMT_NV21, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
175  { AV_PIX_FMT_P010, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
176  { AV_PIX_FMT_P012, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
177  { AV_PIX_FMT_P016, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM } },
178 
179  { AV_PIX_FMT_NV16, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
180 
181  { AV_PIX_FMT_NV24, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
182  { AV_PIX_FMT_NV42, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM } },
183 
184  { AV_PIX_FMT_YUV420P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
185  { AV_PIX_FMT_YUV420P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
186  { AV_PIX_FMT_YUV420P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
187  { AV_PIX_FMT_YUV420P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
188 
189  { AV_PIX_FMT_YUV422P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
190  { AV_PIX_FMT_YUV422P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
191  { AV_PIX_FMT_YUV422P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
192  { AV_PIX_FMT_YUV422P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
193 
194  { AV_PIX_FMT_YUV444P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
195  { AV_PIX_FMT_YUV444P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
196  { AV_PIX_FMT_YUV444P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
197  { AV_PIX_FMT_YUV444P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
198 
199  { AV_PIX_FMT_YUVA420P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
200  { AV_PIX_FMT_YUVA420P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
201  /* There is no AV_PIX_FMT_YUVA420P12 */
202  { AV_PIX_FMT_YUVA420P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
203 
204  { AV_PIX_FMT_YUVA422P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
205  { AV_PIX_FMT_YUVA422P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
206  { AV_PIX_FMT_YUVA422P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
207  { AV_PIX_FMT_YUVA422P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
208 
209  { AV_PIX_FMT_YUVA444P, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
210  { AV_PIX_FMT_YUVA444P10, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
211  { AV_PIX_FMT_YUVA444P12, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
212  { AV_PIX_FMT_YUVA444P16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
213 
214  { AV_PIX_FMT_VUYX, { VK_FORMAT_R8G8B8A8_UNORM } },
215  { AV_PIX_FMT_XV36, { VK_FORMAT_R16G16B16A16_UNORM } },
216 
217  { AV_PIX_FMT_BGRA, { VK_FORMAT_B8G8R8A8_UNORM } },
218  { AV_PIX_FMT_RGBA, { VK_FORMAT_R8G8B8A8_UNORM } },
219  { AV_PIX_FMT_RGB24, { VK_FORMAT_R8G8B8_UNORM } },
220  { AV_PIX_FMT_BGR24, { VK_FORMAT_B8G8R8_UNORM } },
221  { AV_PIX_FMT_RGB48, { VK_FORMAT_R16G16B16_UNORM } },
222  { AV_PIX_FMT_RGBA64, { VK_FORMAT_R16G16B16A16_UNORM } },
223  { AV_PIX_FMT_RGBA64, { VK_FORMAT_R16G16B16A16_UNORM } },
224  { AV_PIX_FMT_RGB565, { VK_FORMAT_R5G6B5_UNORM_PACK16 } },
225  { AV_PIX_FMT_BGR565, { VK_FORMAT_B5G6R5_UNORM_PACK16 } },
226  { AV_PIX_FMT_BGR0, { VK_FORMAT_B8G8R8A8_UNORM } },
227  { AV_PIX_FMT_RGB0, { VK_FORMAT_R8G8B8A8_UNORM } },
228 
229  /* Lower priority as there's an endianess-dependent overlap between these
230  * and rgba/bgr0, and PACK32 formats are more limited */
231  { AV_PIX_FMT_BGR32, { VK_FORMAT_A8B8G8R8_UNORM_PACK32 } },
232  { AV_PIX_FMT_0BGR32, { VK_FORMAT_A8B8G8R8_UNORM_PACK32 } },
233 
234  { AV_PIX_FMT_X2RGB10, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 } },
235 
236  { AV_PIX_FMT_GBRAP, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } },
237  { AV_PIX_FMT_GBRAP16, { VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_UNORM } },
238  { AV_PIX_FMT_GBRPF32, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
239  { AV_PIX_FMT_GBRAPF32, { VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT } },
240 };
241 
243 {
244  for (enum AVPixelFormat i = 0; i < FF_ARRAY_ELEMS(vk_pixfmt_map); i++)
245  if (vk_pixfmt_map[i].pixfmt == p)
246  return vk_pixfmt_map[i].vkfmts;
247  return NULL;
248 }
249 
250 static const void *vk_find_struct(const void *chain, VkStructureType stype)
251 {
252  const VkBaseInStructure *in = chain;
253  while (in) {
254  if (in->sType == stype)
255  return in;
256 
257  in = in->pNext;
258  }
259 
260  return NULL;
261 }
262 
263 static void vk_link_struct(void *chain, void *in)
264 {
265  VkBaseOutStructure *out = chain;
266  if (!in)
267  return;
268 
269  while (out->pNext)
270  out = out->pNext;
271 
272  out->pNext = in;
273 }
274 
276  int linear)
277 {
278  AVVulkanDeviceContext *hwctx = dev_ctx->hwctx;
279  VulkanDevicePriv *priv = dev_ctx->internal->priv;
280  FFVulkanFunctions *vk = &priv->vkfn;
281  const VkFormat *fmt = av_vkfmt_from_pixfmt(p);
283 
284  if (!fmt)
285  return 0;
286 
287  for (int i = 0; i < planes; i++) {
288  VkFormatFeatureFlags flags;
289  VkFormatProperties2 prop = {
290  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
291  };
292  vk->GetPhysicalDeviceFormatProperties2(hwctx->phys_dev, fmt[i], &prop);
293  flags = linear ? prop.formatProperties.linearTilingFeatures :
294  prop.formatProperties.optimalTilingFeatures;
296  return 0;
297  }
298 
299  return 1;
300 }
301 
303 {
304  AVVulkanDeviceContext *hwctx = ctx->hwctx;
305  VulkanDevicePriv *p = ctx->internal->priv;
306 
307  static const char *lib_names[] = {
308 #if defined(_WIN32)
309  "vulkan-1.dll",
310 #elif defined(__APPLE__)
311  "libvulkan.dylib",
312  "libvulkan.1.dylib",
313  "libMoltenVK.dylib",
314 #else
315  "libvulkan.so.1",
316  "libvulkan.so",
317 #endif
318  };
319 
320  for (int i = 0; i < FF_ARRAY_ELEMS(lib_names); i++) {
321  p->libvulkan = dlopen(lib_names[i], RTLD_NOW | RTLD_LOCAL);
322  if (p->libvulkan)
323  break;
324  }
325 
326  if (!p->libvulkan) {
327  av_log(ctx, AV_LOG_ERROR, "Unable to open the libvulkan library!\n");
328  return AVERROR_UNKNOWN;
329  }
330 
331  hwctx->get_proc_addr = (PFN_vkGetInstanceProcAddr)dlsym(p->libvulkan, "vkGetInstanceProcAddr");
332 
333  return 0;
334 }
335 
336 typedef struct VulkanOptExtension {
337  const char *name;
340 
342  /* For future use */
343 };
344 
346  /* Misc or required by other extensions */
347  { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
348  { VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
349  { VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
350 
351  /* Imports/exports */
352  { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_MEMORY },
353  { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_DMABUF_MEMORY },
354  { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS },
355  { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_SEM },
356  { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_HOST_MEMORY },
357 #ifdef _WIN32
358  { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY },
359  { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM },
360 #endif
361 
362  /* Video encoding/decoding */
363  { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
364  { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
365  { VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
366  { VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
367  { VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
368  { VK_EXT_VIDEO_DECODE_H265_EXTENSION_NAME, FF_VK_EXT_NO_FLAG },
369 };
370 
371 /* Converts return values to strings */
372 static const char *vk_ret2str(VkResult res)
373 {
374 #define CASE(VAL) case VAL: return #VAL
375  switch (res) {
376  CASE(VK_SUCCESS);
377  CASE(VK_NOT_READY);
378  CASE(VK_TIMEOUT);
379  CASE(VK_EVENT_SET);
380  CASE(VK_EVENT_RESET);
381  CASE(VK_INCOMPLETE);
382  CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
383  CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
384  CASE(VK_ERROR_INITIALIZATION_FAILED);
385  CASE(VK_ERROR_DEVICE_LOST);
386  CASE(VK_ERROR_MEMORY_MAP_FAILED);
387  CASE(VK_ERROR_LAYER_NOT_PRESENT);
388  CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
389  CASE(VK_ERROR_FEATURE_NOT_PRESENT);
390  CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
391  CASE(VK_ERROR_TOO_MANY_OBJECTS);
392  CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
393  CASE(VK_ERROR_FRAGMENTED_POOL);
394  CASE(VK_ERROR_SURFACE_LOST_KHR);
395  CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
396  CASE(VK_SUBOPTIMAL_KHR);
397  CASE(VK_ERROR_OUT_OF_DATE_KHR);
398  CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
399  CASE(VK_ERROR_VALIDATION_FAILED_EXT);
400  CASE(VK_ERROR_INVALID_SHADER_NV);
401  CASE(VK_ERROR_OUT_OF_POOL_MEMORY);
402  CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE);
403  CASE(VK_ERROR_NOT_PERMITTED_EXT);
404  CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
405  CASE(VK_ERROR_INVALID_DEVICE_ADDRESS_EXT);
406  CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
407  default: return "Unknown error";
408  }
409 #undef CASE
410 }
411 
412 static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
413  VkDebugUtilsMessageTypeFlagsEXT messageType,
414  const VkDebugUtilsMessengerCallbackDataEXT *data,
415  void *priv)
416 {
417  int l;
418  AVHWDeviceContext *ctx = priv;
419 
420  switch (severity) {
421  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: l = AV_LOG_VERBOSE; break;
422  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: l = AV_LOG_INFO; break;
423  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: l = AV_LOG_WARNING; break;
424  case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: l = AV_LOG_ERROR; break;
425  default: l = AV_LOG_DEBUG; break;
426  }
427 
428  av_log(ctx, l, "%s\n", data->pMessage);
429  for (int i = 0; i < data->cmdBufLabelCount; i++)
430  av_log(ctx, l, "\t%i: %s\n", i, data->pCmdBufLabels[i].pLabelName);
431 
432  return 0;
433 }
434 
436  const char * const **dst, uint32_t *num, int debug)
437 {
438  const char *tstr;
439  const char **extension_names = NULL;
440  VulkanDevicePriv *p = ctx->internal->priv;
441  FFVulkanFunctions *vk = &p->vkfn;
442  AVVulkanDeviceContext *hwctx = ctx->hwctx;
443  int err = 0, found, extensions_found = 0;
444 
445  const char *mod;
446  int optional_exts_num;
447  uint32_t sup_ext_count;
448  char *user_exts_str = NULL;
449  AVDictionaryEntry *user_exts;
450  VkExtensionProperties *sup_ext;
451  const VulkanOptExtension *optional_exts;
452 
453  if (!dev) {
454  mod = "instance";
455  optional_exts = optional_instance_exts;
456  optional_exts_num = FF_ARRAY_ELEMS(optional_instance_exts);
457  user_exts = av_dict_get(opts, "instance_extensions", NULL, 0);
458  if (user_exts) {
459  user_exts_str = av_strdup(user_exts->value);
460  if (!user_exts_str) {
461  err = AVERROR(ENOMEM);
462  goto fail;
463  }
464  }
465  vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, NULL);
466  sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
467  if (!sup_ext)
468  return AVERROR(ENOMEM);
469  vk->EnumerateInstanceExtensionProperties(NULL, &sup_ext_count, sup_ext);
470  } else {
471  mod = "device";
472  optional_exts = optional_device_exts;
473  optional_exts_num = FF_ARRAY_ELEMS(optional_device_exts);
474  user_exts = av_dict_get(opts, "device_extensions", NULL, 0);
475  if (user_exts) {
476  user_exts_str = av_strdup(user_exts->value);
477  if (!user_exts_str) {
478  err = AVERROR(ENOMEM);
479  goto fail;
480  }
481  }
482  vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
483  &sup_ext_count, NULL);
484  sup_ext = av_malloc_array(sup_ext_count, sizeof(VkExtensionProperties));
485  if (!sup_ext)
486  return AVERROR(ENOMEM);
487  vk->EnumerateDeviceExtensionProperties(hwctx->phys_dev, NULL,
488  &sup_ext_count, sup_ext);
489  }
490 
491  for (int i = 0; i < optional_exts_num; i++) {
492  tstr = optional_exts[i].name;
493  found = 0;
494  for (int j = 0; j < sup_ext_count; j++) {
495  if (!strcmp(tstr, sup_ext[j].extensionName)) {
496  found = 1;
497  break;
498  }
499  }
500  if (!found)
501  continue;
502 
503  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr);
504  p->extensions |= optional_exts[i].flag;
505  ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
506  }
507 
508  if (debug && !dev) {
509  tstr = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
510  found = 0;
511  for (int j = 0; j < sup_ext_count; j++) {
512  if (!strcmp(tstr, sup_ext[j].extensionName)) {
513  found = 1;
514  break;
515  }
516  }
517  if (found) {
518  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension %s\n", mod, tstr);
519  ADD_VAL_TO_LIST(extension_names, extensions_found, tstr);
521  } else {
522  av_log(ctx, AV_LOG_ERROR, "Debug extension \"%s\" not found!\n",
523  tstr);
524  err = AVERROR(EINVAL);
525  goto fail;
526  }
527  }
528 
529  if (user_exts_str) {
530  char *save, *token = av_strtok(user_exts_str, "+", &save);
531  while (token) {
532  found = 0;
533  for (int j = 0; j < sup_ext_count; j++) {
534  if (!strcmp(token, sup_ext[j].extensionName)) {
535  found = 1;
536  break;
537  }
538  }
539  if (found) {
540  av_log(ctx, AV_LOG_VERBOSE, "Using %s extension \"%s\"\n", mod, token);
541  ADD_VAL_TO_LIST(extension_names, extensions_found, token);
542  } else {
543  av_log(ctx, AV_LOG_WARNING, "%s extension \"%s\" not found, excluding.\n",
544  mod, token);
545  }
546  token = av_strtok(NULL, "+", &save);
547  }
548  }
549 
550  *dst = extension_names;
551  *num = extensions_found;
552 
553  av_free(user_exts_str);
554  av_free(sup_ext);
555  return 0;
556 
557 fail:
558  RELEASE_PROPS(extension_names, extensions_found);
559  av_free(user_exts_str);
560  av_free(sup_ext);
561  return err;
562 }
563 
565  const char * const **dst, uint32_t *num,
566  int *debug_mode)
567 {
568  static const char default_layer[] = { "VK_LAYER_KHRONOS_validation" };
569 
570  int found = 0, err = 0;
571  VulkanDevicePriv *priv = ctx->internal->priv;
572  FFVulkanFunctions *vk = &priv->vkfn;
573 
574  uint32_t sup_layer_count;
575  VkLayerProperties *sup_layers;
576 
577  AVDictionaryEntry *user_layers;
578  char *user_layers_str = NULL;
579  char *save, *token;
580 
581  const char **enabled_layers = NULL;
582  uint32_t enabled_layers_count = 0;
583 
584  AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
585  int debug = debug_opt && strtol(debug_opt->value, NULL, 10);
586 
587  /* If `debug=0`, enable no layers at all. */
588  if (debug_opt && !debug)
589  return 0;
590 
591  vk->EnumerateInstanceLayerProperties(&sup_layer_count, NULL);
592  sup_layers = av_malloc_array(sup_layer_count, sizeof(VkLayerProperties));
593  if (!sup_layers)
594  return AVERROR(ENOMEM);
595  vk->EnumerateInstanceLayerProperties(&sup_layer_count, sup_layers);
596 
597  av_log(ctx, AV_LOG_VERBOSE, "Supported validation layers:\n");
598  for (int i = 0; i < sup_layer_count; i++)
599  av_log(ctx, AV_LOG_VERBOSE, "\t%s\n", sup_layers[i].layerName);
600 
601  /* If `debug=1` is specified, enable the standard validation layer extension */
602  if (debug) {
603  *debug_mode = debug;
604  for (int i = 0; i < sup_layer_count; i++) {
605  if (!strcmp(default_layer, sup_layers[i].layerName)) {
606  found = 1;
607  av_log(ctx, AV_LOG_VERBOSE, "Default validation layer %s is enabled\n",
608  default_layer);
609  ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, default_layer);
610  break;
611  }
612  }
613  }
614 
615  user_layers = av_dict_get(opts, "validation_layers", NULL, 0);
616  if (!user_layers)
617  goto end;
618 
619  user_layers_str = av_strdup(user_layers->value);
620  if (!user_layers_str) {
621  err = AVERROR(ENOMEM);
622  goto fail;
623  }
624 
625  token = av_strtok(user_layers_str, "+", &save);
626  while (token) {
627  found = 0;
628  if (!strcmp(default_layer, token)) {
629  if (debug) {
630  /* if the `debug=1`, default_layer is enabled, skip here */
631  token = av_strtok(NULL, "+", &save);
632  continue;
633  } else {
634  /* if the `debug=0`, enable debug mode to load its callback properly */
635  *debug_mode = debug;
636  }
637  }
638  for (int j = 0; j < sup_layer_count; j++) {
639  if (!strcmp(token, sup_layers[j].layerName)) {
640  found = 1;
641  break;
642  }
643  }
644  if (found) {
645  av_log(ctx, AV_LOG_VERBOSE, "Requested Validation Layer: %s\n", token);
646  ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token);
647  } else {
649  "Validation Layer \"%s\" not support.\n", token);
650  err = AVERROR(EINVAL);
651  goto fail;
652  }
653  token = av_strtok(NULL, "+", &save);
654  }
655 
656  av_free(user_layers_str);
657 
658 end:
659  av_free(sup_layers);
660 
661  *dst = enabled_layers;
662  *num = enabled_layers_count;
663 
664  return 0;
665 
666 fail:
667  RELEASE_PROPS(enabled_layers, enabled_layers_count);
668  av_free(sup_layers);
669  av_free(user_layers_str);
670  return err;
671 }
672 
673 /* Creates a VkInstance */
675 {
676  int err = 0, debug_mode = 0;
677  VkResult ret;
678  VulkanDevicePriv *p = ctx->internal->priv;
679  FFVulkanFunctions *vk = &p->vkfn;
680  AVVulkanDeviceContext *hwctx = ctx->hwctx;
681  VkApplicationInfo application_info = {
682  .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
683  .pEngineName = "libavutil",
684  .apiVersion = VK_API_VERSION_1_2,
685  .engineVersion = VK_MAKE_VERSION(LIBAVUTIL_VERSION_MAJOR,
688  };
689  VkInstanceCreateInfo inst_props = {
690  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
691  .pApplicationInfo = &application_info,
692  };
693 
694  if (!hwctx->get_proc_addr) {
695  err = load_libvulkan(ctx);
696  if (err < 0)
697  return err;
698  }
699 
700  err = ff_vk_load_functions(ctx, vk, p->extensions, 0, 0);
701  if (err < 0) {
702  av_log(ctx, AV_LOG_ERROR, "Unable to load instance enumeration functions!\n");
703  return err;
704  }
705 
706  err = check_validation_layers(ctx, opts, &inst_props.ppEnabledLayerNames,
707  &inst_props.enabledLayerCount, &debug_mode);
708  if (err)
709  goto fail;
710 
711  /* Check for present/missing extensions */
712  err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames,
713  &inst_props.enabledExtensionCount, debug_mode);
714  hwctx->enabled_inst_extensions = inst_props.ppEnabledExtensionNames;
715  hwctx->nb_enabled_inst_extensions = inst_props.enabledExtensionCount;
716  if (err < 0)
717  goto fail;
718 
719  /* Try to create the instance */
720  ret = vk->CreateInstance(&inst_props, hwctx->alloc, &hwctx->inst);
721 
722  /* Check for errors */
723  if (ret != VK_SUCCESS) {
724  av_log(ctx, AV_LOG_ERROR, "Instance creation failure: %s\n",
725  vk_ret2str(ret));
726  err = AVERROR_EXTERNAL;
727  goto fail;
728  }
729 
730  err = ff_vk_load_functions(ctx, vk, p->extensions, 1, 0);
731  if (err < 0) {
732  av_log(ctx, AV_LOG_ERROR, "Unable to load instance functions!\n");
733  goto fail;
734  }
735 
736  if (debug_mode) {
737  VkDebugUtilsMessengerCreateInfoEXT dbg = {
738  .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
739  .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
740  VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
741  VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
742  VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
743  .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
744  VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
745  VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
746  .pfnUserCallback = vk_dbg_callback,
747  .pUserData = ctx,
748  };
749 
750  vk->CreateDebugUtilsMessengerEXT(hwctx->inst, &dbg,
751  hwctx->alloc, &p->debug_ctx);
752  }
753 
754  err = 0;
755 
756 fail:
757  RELEASE_PROPS(inst_props.ppEnabledLayerNames, inst_props.enabledLayerCount);
758  return err;
759 }
760 
761 typedef struct VulkanDeviceSelection {
762  uint8_t uuid[VK_UUID_SIZE]; /* Will use this first unless !has_uuid */
763  int has_uuid;
764  const char *name; /* Will use this second unless NULL */
765  uint32_t pci_device; /* Will use this third unless 0x0 */
766  uint32_t vendor_id; /* Last resort to find something deterministic */
767  int index; /* Finally fall back to index */
769 
770 static const char *vk_dev_type(enum VkPhysicalDeviceType type)
771 {
772  switch (type) {
773  case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "integrated";
774  case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "discrete";
775  case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "virtual";
776  case VK_PHYSICAL_DEVICE_TYPE_CPU: return "software";
777  default: return "unknown";
778  }
779 }
780 
781 /* Finds a device */
783 {
784  int err = 0, choice = -1;
785  uint32_t num;
786  VkResult ret;
787  VulkanDevicePriv *p = ctx->internal->priv;
788  FFVulkanFunctions *vk = &p->vkfn;
789  VkPhysicalDevice *devices = NULL;
790  VkPhysicalDeviceIDProperties *idp = NULL;
791  VkPhysicalDeviceProperties2 *prop = NULL;
792  AVVulkanDeviceContext *hwctx = ctx->hwctx;
793 
794  ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, NULL);
795  if (ret != VK_SUCCESS || !num) {
796  av_log(ctx, AV_LOG_ERROR, "No devices found: %s!\n", vk_ret2str(ret));
797  return AVERROR(ENODEV);
798  }
799 
800  devices = av_malloc_array(num, sizeof(VkPhysicalDevice));
801  if (!devices)
802  return AVERROR(ENOMEM);
803 
804  ret = vk->EnumeratePhysicalDevices(hwctx->inst, &num, devices);
805  if (ret != VK_SUCCESS) {
806  av_log(ctx, AV_LOG_ERROR, "Failed enumerating devices: %s\n",
807  vk_ret2str(ret));
808  err = AVERROR(ENODEV);
809  goto end;
810  }
811 
812  prop = av_calloc(num, sizeof(*prop));
813  if (!prop) {
814  err = AVERROR(ENOMEM);
815  goto end;
816  }
817 
818  idp = av_calloc(num, sizeof(*idp));
819  if (!idp) {
820  err = AVERROR(ENOMEM);
821  goto end;
822  }
823 
824  av_log(ctx, AV_LOG_VERBOSE, "GPU listing:\n");
825  for (int i = 0; i < num; i++) {
826  idp[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
827  prop[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
828  prop[i].pNext = &idp[i];
829 
830  vk->GetPhysicalDeviceProperties2(devices[i], &prop[i]);
831  av_log(ctx, AV_LOG_VERBOSE, " %d: %s (%s) (0x%x)\n", i,
832  prop[i].properties.deviceName,
833  vk_dev_type(prop[i].properties.deviceType),
834  prop[i].properties.deviceID);
835  }
836 
837  if (select->has_uuid) {
838  for (int i = 0; i < num; i++) {
839  if (!strncmp(idp[i].deviceUUID, select->uuid, VK_UUID_SIZE)) {
840  choice = i;
841  goto end;
842  }
843  }
844  av_log(ctx, AV_LOG_ERROR, "Unable to find device by given UUID!\n");
845  err = AVERROR(ENODEV);
846  goto end;
847  } else if (select->name) {
848  av_log(ctx, AV_LOG_VERBOSE, "Requested device: %s\n", select->name);
849  for (int i = 0; i < num; i++) {
850  if (strstr(prop[i].properties.deviceName, select->name)) {
851  choice = i;
852  goto end;
853  }
854  }
855  av_log(ctx, AV_LOG_ERROR, "Unable to find device \"%s\"!\n",
856  select->name);
857  err = AVERROR(ENODEV);
858  goto end;
859  } else if (select->pci_device) {
860  av_log(ctx, AV_LOG_VERBOSE, "Requested device: 0x%x\n", select->pci_device);
861  for (int i = 0; i < num; i++) {
862  if (select->pci_device == prop[i].properties.deviceID) {
863  choice = i;
864  goto end;
865  }
866  }
867  av_log(ctx, AV_LOG_ERROR, "Unable to find device with PCI ID 0x%x!\n",
868  select->pci_device);
869  err = AVERROR(EINVAL);
870  goto end;
871  } else if (select->vendor_id) {
872  av_log(ctx, AV_LOG_VERBOSE, "Requested vendor: 0x%x\n", select->vendor_id);
873  for (int i = 0; i < num; i++) {
874  if (select->vendor_id == prop[i].properties.vendorID) {
875  choice = i;
876  goto end;
877  }
878  }
879  av_log(ctx, AV_LOG_ERROR, "Unable to find device with Vendor ID 0x%x!\n",
880  select->vendor_id);
881  err = AVERROR(ENODEV);
882  goto end;
883  } else {
884  if (select->index < num) {
885  choice = select->index;
886  goto end;
887  }
888  av_log(ctx, AV_LOG_ERROR, "Unable to find device with index %i!\n",
889  select->index);
890  err = AVERROR(ENODEV);
891  goto end;
892  }
893 
894 end:
895  if (choice > -1) {
896  av_log(ctx, AV_LOG_VERBOSE, "Device %d selected: %s (%s) (0x%x)\n",
897  choice, prop[choice].properties.deviceName,
898  vk_dev_type(prop[choice].properties.deviceType),
899  prop[choice].properties.deviceID);
900  hwctx->phys_dev = devices[choice];
901  }
902 
903  av_free(devices);
904  av_free(prop);
905  av_free(idp);
906 
907  return err;
908 }
909 
910 /* Picks the least used qf with the fewest unneeded flags, or -1 if none found */
911 static inline int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf,
912  VkQueueFlagBits flags)
913 {
914  int index = -1;
915  uint32_t min_score = UINT32_MAX;
916 
917  for (int i = 0; i < num_qf; i++) {
918  const VkQueueFlagBits qflags = qf[i].queueFlags;
919  if (qflags & flags) {
920  uint32_t score = av_popcount(qflags) + qf[i].timestampValidBits;
921  if (score < min_score) {
922  index = i;
923  min_score = score;
924  }
925  }
926  }
927 
928  if (index > -1)
929  qf[index].timestampValidBits++;
930 
931  return index;
932 }
933 
934 static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
935 {
936  uint32_t num;
937  float *weights;
938  VkQueueFamilyProperties *qf = NULL;
939  VulkanDevicePriv *p = ctx->internal->priv;
940  FFVulkanFunctions *vk = &p->vkfn;
941  AVVulkanDeviceContext *hwctx = ctx->hwctx;
942  int graph_index, comp_index, tx_index, enc_index, dec_index;
943 
944  /* First get the number of queue families */
945  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, NULL);
946  if (!num) {
947  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
948  return AVERROR_EXTERNAL;
949  }
950 
951  /* Then allocate memory */
952  qf = av_malloc_array(num, sizeof(VkQueueFamilyProperties));
953  if (!qf)
954  return AVERROR(ENOMEM);
955 
956  /* Finally retrieve the queue families */
957  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, qf);
958 
959  av_log(ctx, AV_LOG_VERBOSE, "Queue families:\n");
960  for (int i = 0; i < num; i++) {
961  av_log(ctx, AV_LOG_VERBOSE, " %i:%s%s%s%s%s%s%s (queues: %i)\n", i,
962  ((qf[i].queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? " graphics" : "",
963  ((qf[i].queueFlags) & VK_QUEUE_COMPUTE_BIT) ? " compute" : "",
964  ((qf[i].queueFlags) & VK_QUEUE_TRANSFER_BIT) ? " transfer" : "",
965  ((qf[i].queueFlags) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) ? " encode" : "",
966  ((qf[i].queueFlags) & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ? " decode" : "",
967  ((qf[i].queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? " sparse" : "",
968  ((qf[i].queueFlags) & VK_QUEUE_PROTECTED_BIT) ? " protected" : "",
969  qf[i].queueCount);
970 
971  /* We use this field to keep a score of how many times we've used that
972  * queue family in order to make better choices. */
973  qf[i].timestampValidBits = 0;
974  }
975 
976  /* Pick each queue family to use */
977  graph_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT);
978  comp_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT);
979  tx_index = pick_queue_family(qf, num, VK_QUEUE_TRANSFER_BIT);
980  enc_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_ENCODE_BIT_KHR);
981  dec_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_DECODE_BIT_KHR);
982 
983  /* Signalling the transfer capabilities on a queue family is optional */
984  if (tx_index < 0) {
985  tx_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT);
986  if (tx_index < 0)
987  tx_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT);
988  }
989 
990  hwctx->queue_family_index = -1;
991  hwctx->queue_family_comp_index = -1;
992  hwctx->queue_family_tx_index = -1;
993  hwctx->queue_family_encode_index = -1;
994  hwctx->queue_family_decode_index = -1;
995 
996 #define SETUP_QUEUE(qf_idx) \
997  if (qf_idx > -1) { \
998  int fidx = qf_idx; \
999  int qc = qf[fidx].queueCount; \
1000  VkDeviceQueueCreateInfo *pc; \
1001  \
1002  if (fidx == graph_index) { \
1003  hwctx->queue_family_index = fidx; \
1004  hwctx->nb_graphics_queues = qc; \
1005  graph_index = -1; \
1006  } \
1007  if (fidx == comp_index) { \
1008  hwctx->queue_family_comp_index = fidx; \
1009  hwctx->nb_comp_queues = qc; \
1010  comp_index = -1; \
1011  } \
1012  if (fidx == tx_index) { \
1013  hwctx->queue_family_tx_index = fidx; \
1014  hwctx->nb_tx_queues = qc; \
1015  tx_index = -1; \
1016  } \
1017  if (fidx == enc_index) { \
1018  hwctx->queue_family_encode_index = fidx; \
1019  hwctx->nb_encode_queues = qc; \
1020  enc_index = -1; \
1021  } \
1022  if (fidx == dec_index) { \
1023  hwctx->queue_family_decode_index = fidx; \
1024  hwctx->nb_decode_queues = qc; \
1025  dec_index = -1; \
1026  } \
1027  \
1028  pc = av_realloc((void *)cd->pQueueCreateInfos, \
1029  sizeof(*pc) * (cd->queueCreateInfoCount + 1)); \
1030  if (!pc) { \
1031  av_free(qf); \
1032  return AVERROR(ENOMEM); \
1033  } \
1034  cd->pQueueCreateInfos = pc; \
1035  pc = &pc[cd->queueCreateInfoCount]; \
1036  \
1037  weights = av_malloc(qc * sizeof(float)); \
1038  if (!weights) { \
1039  av_free(qf); \
1040  return AVERROR(ENOMEM); \
1041  } \
1042  \
1043  memset(pc, 0, sizeof(*pc)); \
1044  pc->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; \
1045  pc->queueFamilyIndex = fidx; \
1046  pc->queueCount = qc; \
1047  pc->pQueuePriorities = weights; \
1048  \
1049  for (int i = 0; i < qc; i++) \
1050  weights[i] = 1.0f / qc; \
1051  \
1052  cd->queueCreateInfoCount++; \
1053  }
1054 
1055  SETUP_QUEUE(graph_index)
1056  SETUP_QUEUE(comp_index)
1057  SETUP_QUEUE(tx_index)
1058  SETUP_QUEUE(enc_index)
1059  SETUP_QUEUE(dec_index)
1060 
1061 #undef SETUP_QUEUE
1062 
1063  av_free(qf);
1064 
1065  return 0;
1066 }
1067 
1069  int queue_family_index, int num_queues)
1070 {
1071  VkResult ret;
1072  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1074  FFVulkanFunctions *vk = &p->vkfn;
1075 
1076  VkCommandPoolCreateInfo cqueue_create = {
1077  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1078  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1079  .queueFamilyIndex = queue_family_index,
1080  };
1081  VkCommandBufferAllocateInfo cbuf_create = {
1082  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1083  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1084  .commandBufferCount = num_queues,
1085  };
1086 
1087  cmd->nb_queues = num_queues;
1088 
1089  /* Create command pool */
1090  ret = vk->CreateCommandPool(hwctx->act_dev, &cqueue_create,
1091  hwctx->alloc, &cmd->pool);
1092  if (ret != VK_SUCCESS) {
1093  av_log(hwfc, AV_LOG_ERROR, "Command pool creation failure: %s\n",
1094  vk_ret2str(ret));
1095  return AVERROR_EXTERNAL;
1096  }
1097 
1098  cmd->bufs = av_mallocz(num_queues * sizeof(*cmd->bufs));
1099  if (!cmd->bufs)
1100  return AVERROR(ENOMEM);
1101 
1102  cbuf_create.commandPool = cmd->pool;
1103 
1104  /* Allocate command buffer */
1105  ret = vk->AllocateCommandBuffers(hwctx->act_dev, &cbuf_create, cmd->bufs);
1106  if (ret != VK_SUCCESS) {
1107  av_log(hwfc, AV_LOG_ERROR, "Command buffer alloc failure: %s\n",
1108  vk_ret2str(ret));
1109  av_freep(&cmd->bufs);
1110  return AVERROR_EXTERNAL;
1111  }
1112 
1113  cmd->queues = av_mallocz(num_queues * sizeof(*cmd->queues));
1114  if (!cmd->queues)
1115  return AVERROR(ENOMEM);
1116 
1117  for (int i = 0; i < num_queues; i++) {
1118  VulkanQueueCtx *q = &cmd->queues[i];
1119  vk->GetDeviceQueue(hwctx->act_dev, queue_family_index, i, &q->queue);
1120  q->was_synchronous = 1;
1121  }
1122 
1123  return 0;
1124 }
1125 
1127 {
1128  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1130  FFVulkanFunctions *vk = &p->vkfn;
1131 
1132  if (cmd->queues) {
1133  for (int i = 0; i < cmd->nb_queues; i++) {
1134  VulkanQueueCtx *q = &cmd->queues[i];
1135 
1136  /* Make sure all queues have finished executing */
1137  if (q->fence && !q->was_synchronous) {
1138  vk->WaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
1139  vk->ResetFences(hwctx->act_dev, 1, &q->fence);
1140  }
1141 
1142  /* Free the fence */
1143  if (q->fence)
1144  vk->DestroyFence(hwctx->act_dev, q->fence, hwctx->alloc);
1145 
1146  /* Free buffer dependencies */
1147  for (int j = 0; j < q->nb_buf_deps; j++)
1148  av_buffer_unref(&q->buf_deps[j]);
1149  av_free(q->buf_deps);
1150  }
1151  }
1152 
1153  if (cmd->bufs)
1154  vk->FreeCommandBuffers(hwctx->act_dev, cmd->pool, cmd->nb_queues, cmd->bufs);
1155  if (cmd->pool)
1156  vk->DestroyCommandPool(hwctx->act_dev, cmd->pool, hwctx->alloc);
1157 
1158  av_freep(&cmd->queues);
1159  av_freep(&cmd->bufs);
1160  cmd->pool = NULL;
1161 }
1162 
1163 static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
1164 {
1165  return cmd->bufs[cmd->cur_queue_idx];
1166 }
1167 
1169 {
1170  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
1171 
1172  for (int j = 0; j < q->nb_buf_deps; j++)
1173  av_buffer_unref(&q->buf_deps[j]);
1174  q->nb_buf_deps = 0;
1175 }
1176 
1178 {
1179  VkResult ret;
1180  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1181  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
1183  FFVulkanFunctions *vk = &p->vkfn;
1184 
1185  VkCommandBufferBeginInfo cmd_start = {
1186  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1187  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1188  };
1189 
1190  /* Create the fence and don't wait for it initially */
1191  if (!q->fence) {
1192  VkFenceCreateInfo fence_spawn = {
1193  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1194  };
1195  ret = vk->CreateFence(hwctx->act_dev, &fence_spawn, hwctx->alloc,
1196  &q->fence);
1197  if (ret != VK_SUCCESS) {
1198  av_log(hwfc, AV_LOG_ERROR, "Failed to queue frame fence: %s\n",
1199  vk_ret2str(ret));
1200  return AVERROR_EXTERNAL;
1201  }
1202  } else if (!q->was_synchronous) {
1203  vk->WaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
1204  vk->ResetFences(hwctx->act_dev, 1, &q->fence);
1205  }
1206 
1207  /* Discard queue dependencies */
1208  unref_exec_ctx_deps(hwfc, cmd);
1209 
1210  ret = vk->BeginCommandBuffer(cmd->bufs[cmd->cur_queue_idx], &cmd_start);
1211  if (ret != VK_SUCCESS) {
1212  av_log(hwfc, AV_LOG_ERROR, "Unable to init command buffer: %s\n",
1213  vk_ret2str(ret));
1214  return AVERROR_EXTERNAL;
1215  }
1216 
1217  return 0;
1218 }
1219 
1221  AVBufferRef * const *deps, int nb_deps)
1222 {
1223  AVBufferRef **dst;
1224  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
1225 
1226  if (!deps || !nb_deps)
1227  return 0;
1228 
1230  (q->nb_buf_deps + nb_deps) * sizeof(*dst));
1231  if (!dst)
1232  goto err;
1233 
1234  q->buf_deps = dst;
1235 
1236  for (int i = 0; i < nb_deps; i++) {
1237  q->buf_deps[q->nb_buf_deps] = av_buffer_ref(deps[i]);
1238  if (!q->buf_deps[q->nb_buf_deps])
1239  goto err;
1240  q->nb_buf_deps++;
1241  }
1242 
1243  return 0;
1244 
1245 err:
1246  unref_exec_ctx_deps(hwfc, cmd);
1247  return AVERROR(ENOMEM);
1248 }
1249 
1251  VkSubmitInfo *s_info, AVVkFrame *f, int synchronous)
1252 {
1253  VkResult ret;
1254  VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx];
1256  FFVulkanFunctions *vk = &p->vkfn;
1257 
1258  ret = vk->EndCommandBuffer(cmd->bufs[cmd->cur_queue_idx]);
1259  if (ret != VK_SUCCESS) {
1260  av_log(hwfc, AV_LOG_ERROR, "Unable to finish command buffer: %s\n",
1261  vk_ret2str(ret));
1262  unref_exec_ctx_deps(hwfc, cmd);
1263  return AVERROR_EXTERNAL;
1264  }
1265 
1266  s_info->pCommandBuffers = &cmd->bufs[cmd->cur_queue_idx];
1267  s_info->commandBufferCount = 1;
1268 
1269  ret = vk->QueueSubmit(q->queue, 1, s_info, q->fence);
1270  if (ret != VK_SUCCESS) {
1271  av_log(hwfc, AV_LOG_ERROR, "Queue submission failure: %s\n",
1272  vk_ret2str(ret));
1273  unref_exec_ctx_deps(hwfc, cmd);
1274  return AVERROR_EXTERNAL;
1275  }
1276 
1277  if (f)
1278  for (int i = 0; i < s_info->signalSemaphoreCount; i++)
1279  f->sem_value[i]++;
1280 
1281  q->was_synchronous = synchronous;
1282 
1283  if (synchronous) {
1284  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1285  vk->WaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX);
1286  vk->ResetFences(hwctx->act_dev, 1, &q->fence);
1287  unref_exec_ctx_deps(hwfc, cmd);
1288  } else { /* Rotate queues */
1289  cmd->cur_queue_idx = (cmd->cur_queue_idx + 1) % cmd->nb_queues;
1290  }
1291 
1292  return 0;
1293 }
1294 
1296 {
1297  VulkanDevicePriv *p = ctx->internal->priv;
1298  FFVulkanFunctions *vk = &p->vkfn;
1299  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1300 
1301  if (hwctx->act_dev)
1302  vk->DestroyDevice(hwctx->act_dev, hwctx->alloc);
1303 
1304  if (p->debug_ctx)
1305  vk->DestroyDebugUtilsMessengerEXT(hwctx->inst, p->debug_ctx,
1306  hwctx->alloc);
1307 
1308  if (hwctx->inst)
1309  vk->DestroyInstance(hwctx->inst, hwctx->alloc);
1310 
1311  if (p->libvulkan)
1312  dlclose(p->libvulkan);
1313 
1316 }
1317 
1319  VulkanDeviceSelection *dev_select,
1320  AVDictionary *opts, int flags)
1321 {
1322  int err = 0;
1323  VkResult ret;
1324  AVDictionaryEntry *opt_d;
1325  VulkanDevicePriv *p = ctx->internal->priv;
1326  FFVulkanFunctions *vk = &p->vkfn;
1327  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1328 
1329  /*
1330  * VkPhysicalDeviceVulkan12Features has a timelineSemaphore field, but
1331  * MoltenVK doesn't implement VkPhysicalDeviceVulkan12Features yet, so we
1332  * use VkPhysicalDeviceTimelineSemaphoreFeatures directly.
1333  */
1334  VkPhysicalDeviceTimelineSemaphoreFeatures timeline_features = {
1335  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
1336  };
1337  VkPhysicalDeviceVulkan12Features dev_features_1_2 = {
1338  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
1339  .pNext = &timeline_features,
1340  };
1341  VkPhysicalDeviceVulkan11Features dev_features_1_1 = {
1342  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
1343  .pNext = &dev_features_1_2,
1344  };
1345  VkPhysicalDeviceFeatures2 dev_features = {
1346  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1347  .pNext = &dev_features_1_1,
1348  };
1349 
1350  VkDeviceCreateInfo dev_info = {
1351  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1352  .pNext = &hwctx->device_features,
1353  };
1354 
1355  hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
1356  hwctx->device_features.pNext = &p->device_features_1_1;
1357  p->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
1359  p->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
1360  ctx->free = vulkan_device_free;
1361 
1362  /* Create an instance if not given one */
1363  if ((err = create_instance(ctx, opts)))
1364  goto end;
1365 
1366  /* Find a device (if not given one) */
1367  if ((err = find_device(ctx, dev_select)))
1368  goto end;
1369 
1370  vk->GetPhysicalDeviceFeatures2(hwctx->phys_dev, &dev_features);
1371 
1372  /* Try to keep in sync with libplacebo */
1373 #define COPY_FEATURE(DST, NAME) (DST).features.NAME = dev_features.features.NAME;
1374  COPY_FEATURE(hwctx->device_features, shaderImageGatherExtended)
1375  COPY_FEATURE(hwctx->device_features, shaderStorageImageReadWithoutFormat)
1376  COPY_FEATURE(hwctx->device_features, shaderStorageImageWriteWithoutFormat)
1377  COPY_FEATURE(hwctx->device_features, fragmentStoresAndAtomics)
1378  COPY_FEATURE(hwctx->device_features, vertexPipelineStoresAndAtomics)
1379  COPY_FEATURE(hwctx->device_features, shaderInt64)
1380 #undef COPY_FEATURE
1381 
1382  /* We require timeline semaphores */
1383  if (!timeline_features.timelineSemaphore) {
1384  av_log(ctx, AV_LOG_ERROR, "Device does not support timeline semaphores!\n");
1385  err = AVERROR(ENOSYS);
1386  goto end;
1387  }
1388  p->device_features_1_2.timelineSemaphore = 1;
1389 
1390  /* Setup queue family */
1391  if ((err = setup_queue_families(ctx, &dev_info)))
1392  goto end;
1393 
1394  if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames,
1395  &dev_info.enabledExtensionCount, 0))) {
1396  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1397  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1398  av_free((void *)dev_info.pQueueCreateInfos);
1399  goto end;
1400  }
1401 
1402  ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc,
1403  &hwctx->act_dev);
1404 
1405  for (int i = 0; i < dev_info.queueCreateInfoCount; i++)
1406  av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities);
1407  av_free((void *)dev_info.pQueueCreateInfos);
1408 
1409  if (ret != VK_SUCCESS) {
1410  av_log(ctx, AV_LOG_ERROR, "Device creation failure: %s\n",
1411  vk_ret2str(ret));
1412  for (int i = 0; i < dev_info.enabledExtensionCount; i++)
1413  av_free((void *)dev_info.ppEnabledExtensionNames[i]);
1414  av_free((void *)dev_info.ppEnabledExtensionNames);
1415  err = AVERROR_EXTERNAL;
1416  goto end;
1417  }
1418 
1419  /* Tiled images setting, use them by default */
1420  opt_d = av_dict_get(opts, "linear_images", NULL, 0);
1421  if (opt_d)
1422  p->use_linear_images = strtol(opt_d->value, NULL, 10);
1423 
1424  opt_d = av_dict_get(opts, "contiguous_planes", NULL, 0);
1425  if (opt_d)
1426  p->contiguous_planes = strtol(opt_d->value, NULL, 10);
1427  else
1428  p->contiguous_planes = -1;
1429 
1430  hwctx->enabled_dev_extensions = dev_info.ppEnabledExtensionNames;
1431  hwctx->nb_enabled_dev_extensions = dev_info.enabledExtensionCount;
1432 
1433 end:
1434  return err;
1435 }
1436 
1438 {
1439  int err;
1440  uint32_t queue_num;
1441  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1442  VulkanDevicePriv *p = ctx->internal->priv;
1443  FFVulkanFunctions *vk = &p->vkfn;
1444  int graph_index, comp_index, tx_index, enc_index, dec_index;
1445 
1446  /* Set device extension flags */
1447  for (int i = 0; i < hwctx->nb_enabled_dev_extensions; i++) {
1448  for (int j = 0; j < FF_ARRAY_ELEMS(optional_device_exts); j++) {
1449  if (!strcmp(hwctx->enabled_dev_extensions[i],
1450  optional_device_exts[j].name)) {
1452  break;
1453  }
1454  }
1455  }
1456 
1457  err = ff_vk_load_functions(ctx, vk, p->extensions, 1, 1);
1458  if (err < 0) {
1459  av_log(ctx, AV_LOG_ERROR, "Unable to load functions!\n");
1460  return err;
1461  }
1462 
1463  p->props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1464  p->props.pNext = &p->hprops;
1465  p->hprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
1466 
1467  vk->GetPhysicalDeviceProperties2(hwctx->phys_dev, &p->props);
1468  av_log(ctx, AV_LOG_VERBOSE, "Using device: %s\n",
1469  p->props.properties.deviceName);
1470  av_log(ctx, AV_LOG_VERBOSE, "Alignments:\n");
1471  av_log(ctx, AV_LOG_VERBOSE, " optimalBufferCopyRowPitchAlignment: %"PRIu64"\n",
1472  p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
1473  av_log(ctx, AV_LOG_VERBOSE, " minMemoryMapAlignment: %"SIZE_SPECIFIER"\n",
1474  p->props.properties.limits.minMemoryMapAlignment);
1476  av_log(ctx, AV_LOG_VERBOSE, " minImportedHostPointerAlignment: %"PRIu64"\n",
1477  p->hprops.minImportedHostPointerAlignment);
1478 
1479  p->dev_is_nvidia = (p->props.properties.vendorID == 0x10de);
1480  p->dev_is_intel = (p->props.properties.vendorID == 0x8086);
1481 
1482  vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &queue_num, NULL);
1483  if (!queue_num) {
1484  av_log(ctx, AV_LOG_ERROR, "Failed to get queues!\n");
1485  return AVERROR_EXTERNAL;
1486  }
1487 
1488  graph_index = hwctx->queue_family_index;
1489  comp_index = hwctx->queue_family_comp_index;
1490  tx_index = hwctx->queue_family_tx_index;
1491  enc_index = hwctx->queue_family_encode_index;
1492  dec_index = hwctx->queue_family_decode_index;
1493 
1494 #define CHECK_QUEUE(type, required, fidx, ctx_qf, qc) \
1495  do { \
1496  if (ctx_qf < 0 && required) { \
1497  av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \
1498  " in the context!\n", type); \
1499  return AVERROR(EINVAL); \
1500  } else if (fidx < 0 || ctx_qf < 0) { \
1501  break; \
1502  } else if (ctx_qf >= queue_num) { \
1503  av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \
1504  type, ctx_qf, queue_num); \
1505  return AVERROR(EINVAL); \
1506  } \
1507  \
1508  av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \
1509  " for%s%s%s%s%s\n", \
1510  ctx_qf, qc, \
1511  ctx_qf == graph_index ? " graphics" : "", \
1512  ctx_qf == comp_index ? " compute" : "", \
1513  ctx_qf == tx_index ? " transfers" : "", \
1514  ctx_qf == enc_index ? " encode" : "", \
1515  ctx_qf == dec_index ? " decode" : ""); \
1516  graph_index = (ctx_qf == graph_index) ? -1 : graph_index; \
1517  comp_index = (ctx_qf == comp_index) ? -1 : comp_index; \
1518  tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \
1519  enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \
1520  dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \
1521  p->qfs[p->num_qfs++] = ctx_qf; \
1522  } while (0)
1523 
1524  CHECK_QUEUE("graphics", 0, graph_index, hwctx->queue_family_index, hwctx->nb_graphics_queues);
1525  CHECK_QUEUE("upload", 1, tx_index, hwctx->queue_family_tx_index, hwctx->nb_tx_queues);
1526  CHECK_QUEUE("compute", 1, comp_index, hwctx->queue_family_comp_index, hwctx->nb_comp_queues);
1527  CHECK_QUEUE("encode", 0, enc_index, hwctx->queue_family_encode_index, hwctx->nb_encode_queues);
1528  CHECK_QUEUE("decode", 0, dec_index, hwctx->queue_family_decode_index, hwctx->nb_decode_queues);
1529 
1530 #undef CHECK_QUEUE
1531 
1532  /* Get device capabilities */
1533  vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops);
1534 
1535  return 0;
1536 }
1537 
1538 static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device,
1539  AVDictionary *opts, int flags)
1540 {
1541  VulkanDeviceSelection dev_select = { 0 };
1542  if (device && device[0]) {
1543  char *end = NULL;
1544  dev_select.index = strtol(device, &end, 10);
1545  if (end == device) {
1546  dev_select.index = 0;
1547  dev_select.name = device;
1548  }
1549  }
1550 
1551  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1552 }
1553 
1555  AVHWDeviceContext *src_ctx,
1556  AVDictionary *opts, int flags)
1557 {
1558  av_unused VulkanDeviceSelection dev_select = { 0 };
1559 
1560  /* If there's only one device on the system, then even if its not covered
1561  * by the following checks (e.g. non-PCIe ARM GPU), having an empty
1562  * dev_select will mean it'll get picked. */
1563  switch(src_ctx->type) {
1564 #if CONFIG_LIBDRM
1565 #if CONFIG_VAAPI
1566  case AV_HWDEVICE_TYPE_VAAPI: {
1567  AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
1568 
1569  const char *vendor = vaQueryVendorString(src_hwctx->display);
1570  if (!vendor) {
1571  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from VAAPI!\n");
1572  return AVERROR_EXTERNAL;
1573  }
1574 
1575  if (strstr(vendor, "Intel"))
1576  dev_select.vendor_id = 0x8086;
1577  if (strstr(vendor, "AMD"))
1578  dev_select.vendor_id = 0x1002;
1579 
1580  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1581  }
1582 #endif
1583  case AV_HWDEVICE_TYPE_DRM: {
1584  AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1585 
1586  drmDevice *drm_dev_info;
1587  int err = drmGetDevice(src_hwctx->fd, &drm_dev_info);
1588  if (err) {
1589  av_log(ctx, AV_LOG_ERROR, "Unable to get device info from DRM fd!\n");
1590  return AVERROR_EXTERNAL;
1591  }
1592 
1593  if (drm_dev_info->bustype == DRM_BUS_PCI)
1594  dev_select.pci_device = drm_dev_info->deviceinfo.pci->device_id;
1595 
1596  drmFreeDevice(&drm_dev_info);
1597 
1598  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1599  }
1600 #endif
1601 #if CONFIG_CUDA
1602  case AV_HWDEVICE_TYPE_CUDA: {
1603  AVHWDeviceContext *cuda_cu = src_ctx;
1604  AVCUDADeviceContext *src_hwctx = src_ctx->hwctx;
1605  AVCUDADeviceContextInternal *cu_internal = src_hwctx->internal;
1606  CudaFunctions *cu = cu_internal->cuda_dl;
1607 
1608  int ret = CHECK_CU(cu->cuDeviceGetUuid((CUuuid *)&dev_select.uuid,
1609  cu_internal->cuda_device));
1610  if (ret < 0) {
1611  av_log(ctx, AV_LOG_ERROR, "Unable to get UUID from CUDA!\n");
1612  return AVERROR_EXTERNAL;
1613  }
1614 
1615  dev_select.has_uuid = 1;
1616 
1617  return vulkan_device_create_internal(ctx, &dev_select, opts, flags);
1618  }
1619 #endif
1620  default:
1621  return AVERROR(ENOSYS);
1622  }
1623 }
1624 
1626  const void *hwconfig,
1627  AVHWFramesConstraints *constraints)
1628 {
1629  int count = 0;
1630  VulkanDevicePriv *p = ctx->internal->priv;
1631 
1632  for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++)
1633  count += pixfmt_is_supported(ctx, i, p->use_linear_images);
1634 
1635 #if CONFIG_CUDA
1636  if (p->dev_is_nvidia)
1637  count++;
1638 #endif
1639 
1640  constraints->valid_sw_formats = av_malloc_array(count + 1,
1641  sizeof(enum AVPixelFormat));
1642  if (!constraints->valid_sw_formats)
1643  return AVERROR(ENOMEM);
1644 
1645  count = 0;
1646  for (enum AVPixelFormat i = 0; i < AV_PIX_FMT_NB; i++)
1648  constraints->valid_sw_formats[count++] = i;
1649 
1650 #if CONFIG_CUDA
1651  if (p->dev_is_nvidia)
1652  constraints->valid_sw_formats[count++] = AV_PIX_FMT_CUDA;
1653 #endif
1654  constraints->valid_sw_formats[count++] = AV_PIX_FMT_NONE;
1655 
1656  constraints->min_width = 0;
1657  constraints->min_height = 0;
1658  constraints->max_width = p->props.properties.limits.maxImageDimension2D;
1659  constraints->max_height = p->props.properties.limits.maxImageDimension2D;
1660 
1661  constraints->valid_hw_formats = av_malloc_array(2, sizeof(enum AVPixelFormat));
1662  if (!constraints->valid_hw_formats)
1663  return AVERROR(ENOMEM);
1664 
1665  constraints->valid_hw_formats[0] = AV_PIX_FMT_VULKAN;
1666  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1667 
1668  return 0;
1669 }
1670 
1671 static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
1672  VkMemoryPropertyFlagBits req_flags, const void *alloc_extension,
1673  VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
1674 {
1675  VkResult ret;
1676  int index = -1;
1677  VulkanDevicePriv *p = ctx->internal->priv;
1678  FFVulkanFunctions *vk = &p->vkfn;
1679  AVVulkanDeviceContext *dev_hwctx = ctx->hwctx;
1680  VkMemoryAllocateInfo alloc_info = {
1681  .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1682  .pNext = alloc_extension,
1683  .allocationSize = req->size,
1684  };
1685 
1686  /* The vulkan spec requires memory types to be sorted in the "optimal"
1687  * order, so the first matching type we find will be the best/fastest one */
1688  for (int i = 0; i < p->mprops.memoryTypeCount; i++) {
1689  const VkMemoryType *type = &p->mprops.memoryTypes[i];
1690 
1691  /* The memory type must be supported by the requirements (bitfield) */
1692  if (!(req->memoryTypeBits & (1 << i)))
1693  continue;
1694 
1695  /* The memory type flags must include our properties */
1696  if ((type->propertyFlags & req_flags) != req_flags)
1697  continue;
1698 
1699  /* The memory type must be large enough */
1700  if (req->size > p->mprops.memoryHeaps[type->heapIndex].size)
1701  continue;
1702 
1703  /* Found a suitable memory type */
1704  index = i;
1705  break;
1706  }
1707 
1708  if (index < 0) {
1709  av_log(ctx, AV_LOG_ERROR, "No memory type found for flags 0x%x\n",
1710  req_flags);
1711  return AVERROR(EINVAL);
1712  }
1713 
1714  alloc_info.memoryTypeIndex = index;
1715 
1716  ret = vk->AllocateMemory(dev_hwctx->act_dev, &alloc_info,
1717  dev_hwctx->alloc, mem);
1718  if (ret != VK_SUCCESS) {
1719  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory: %s\n",
1720  vk_ret2str(ret));
1721  return AVERROR(ENOMEM);
1722  }
1723 
1724  *mem_flags |= p->mprops.memoryTypes[index].propertyFlags;
1725 
1726  return 0;
1727 }
1728 
1730 {
1731  AVVkFrameInternal *internal = f->internal;
1732 
1733  if (!internal)
1734  return;
1735 
1736 #if CONFIG_CUDA
1737  if (internal->cuda_fc_ref) {
1738  AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
1739  int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
1740  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
1741  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
1742  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
1743  CudaFunctions *cu = cu_internal->cuda_dl;
1744 
1745  for (int i = 0; i < planes; i++) {
1746  if (internal->cu_sem[i])
1747  CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
1748  if (internal->cu_mma[i])
1749  CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
1750  if (internal->ext_mem[i])
1751  CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
1752 #ifdef _WIN32
1753  if (internal->ext_sem_handle[i])
1754  CloseHandle(internal->ext_sem_handle[i]);
1755  if (internal->ext_mem_handle[i])
1756  CloseHandle(internal->ext_mem_handle[i]);
1757 #endif
1758  }
1759 
1760  av_buffer_unref(&internal->cuda_fc_ref);
1761  }
1762 #endif
1763 
1764  av_freep(&f->internal);
1765 }
1766 
1767 static void vulkan_frame_free(void *opaque, uint8_t *data)
1768 {
1769  AVVkFrame *f = (AVVkFrame *)data;
1770  AVHWFramesContext *hwfc = opaque;
1771  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1773  FFVulkanFunctions *vk = &p->vkfn;
1775 
1776  /* We could use vkWaitSemaphores, but the validation layer seems to have
1777  * issues tracking command buffer execution state on uninit. */
1778  vk->DeviceWaitIdle(hwctx->act_dev);
1779 
1781 
1782  for (int i = 0; i < planes; i++) {
1783  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
1784  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
1785  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
1786  }
1787 
1788  av_free(f);
1789 }
1790 
1792  void *alloc_pnext, size_t alloc_pnext_stride)
1793 {
1794  int err;
1795  VkResult ret;
1796  AVHWDeviceContext *ctx = hwfc->device_ctx;
1797  VulkanDevicePriv *p = ctx->internal->priv;
1798  FFVulkanFunctions *vk = &p->vkfn;
1799  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
1800  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1801  VkBindImageMemoryInfo bind_info[AV_NUM_DATA_POINTERS] = { { 0 } };
1802 
1803  VkMemoryRequirements cont_memory_requirements = { 0 };
1804  int cont_mem_size_list[AV_NUM_DATA_POINTERS] = { 0 };
1805  int cont_mem_size = 0;
1806 
1807  AVVulkanDeviceContext *hwctx = ctx->hwctx;
1808 
1809  for (int i = 0; i < planes; i++) {
1810  int use_ded_mem;
1811  VkImageMemoryRequirementsInfo2 req_desc = {
1812  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
1813  .image = f->img[i],
1814  };
1815  VkMemoryDedicatedAllocateInfo ded_alloc = {
1816  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1817  .pNext = (void *)(((uint8_t *)alloc_pnext) + i*alloc_pnext_stride),
1818  };
1819  VkMemoryDedicatedRequirements ded_req = {
1820  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
1821  };
1822  VkMemoryRequirements2 req = {
1823  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
1824  .pNext = &ded_req,
1825  };
1826 
1827  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
1828 
1829  if (f->tiling == VK_IMAGE_TILING_LINEAR)
1830  req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
1831  p->props.properties.limits.minMemoryMapAlignment);
1832 
1833  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) {
1834  if (ded_req.requiresDedicatedAllocation) {
1835  av_log(hwfc, AV_LOG_ERROR, "Cannot allocate all planes in a single allocation, "
1836  "device requires dedicated image allocation!\n");
1837  return AVERROR(EINVAL);
1838  } else if (!i) {
1839  cont_memory_requirements = req.memoryRequirements;
1840  } else if (cont_memory_requirements.memoryTypeBits !=
1841  req.memoryRequirements.memoryTypeBits) {
1842  av_log(hwfc, AV_LOG_ERROR, "The memory requirements differ between plane 0 "
1843  "and %i, cannot allocate in a single region!\n",
1844  i);
1845  return AVERROR(EINVAL);
1846  }
1847 
1848  cont_mem_size_list[i] = FFALIGN(req.memoryRequirements.size,
1849  req.memoryRequirements.alignment);
1850  cont_mem_size += cont_mem_size_list[i];
1851  continue;
1852  }
1853 
1854  /* In case the implementation prefers/requires dedicated allocation */
1855  use_ded_mem = ded_req.prefersDedicatedAllocation |
1856  ded_req.requiresDedicatedAllocation;
1857  if (use_ded_mem)
1858  ded_alloc.image = f->img[i];
1859 
1860  /* Allocate memory */
1861  if ((err = alloc_mem(ctx, &req.memoryRequirements,
1862  f->tiling == VK_IMAGE_TILING_LINEAR ?
1863  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1864  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1865  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
1866  &f->flags, &f->mem[i])))
1867  return err;
1868 
1869  f->size[i] = req.memoryRequirements.size;
1870  bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1871  bind_info[i].image = f->img[i];
1872  bind_info[i].memory = f->mem[i];
1873  }
1874 
1875  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) {
1876  cont_memory_requirements.size = cont_mem_size;
1877 
1878  /* Allocate memory */
1879  if ((err = alloc_mem(ctx, &cont_memory_requirements,
1880  f->tiling == VK_IMAGE_TILING_LINEAR ?
1881  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
1882  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1883  (void *)(((uint8_t *)alloc_pnext)),
1884  &f->flags, &f->mem[0])))
1885  return err;
1886 
1887  f->size[0] = cont_memory_requirements.size;
1888 
1889  for (int i = 0, offset = 0; i < planes; i++) {
1890  bind_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1891  bind_info[i].image = f->img[i];
1892  bind_info[i].memory = f->mem[0];
1893  bind_info[i].memoryOffset = offset;
1894 
1895  f->offset[i] = bind_info[i].memoryOffset;
1896  offset += cont_mem_size_list[i];
1897  }
1898  }
1899 
1900  /* Bind the allocated memory to the images */
1901  ret = vk->BindImageMemory2(hwctx->act_dev, planes, bind_info);
1902  if (ret != VK_SUCCESS) {
1903  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
1904  vk_ret2str(ret));
1905  return AVERROR_EXTERNAL;
1906  }
1907 
1908  return 0;
1909 }
1910 
1911 enum PrepMode {
1915 };
1916 
1918  AVVkFrame *frame, enum PrepMode pmode)
1919 {
1920  int err;
1921  uint32_t src_qf, dst_qf;
1922  VkImageLayout new_layout;
1923  VkAccessFlags new_access;
1924  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
1926  FFVulkanFunctions *vk = &p->vkfn;
1927  uint64_t sem_sig_val[AV_NUM_DATA_POINTERS];
1928 
1929  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
1930 
1931  VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = {
1932  .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
1933  .pSignalSemaphoreValues = sem_sig_val,
1934  .signalSemaphoreValueCount = planes,
1935  };
1936 
1937  VkSubmitInfo s_info = {
1938  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1939  .pNext = &s_timeline_sem_info,
1940  .pSignalSemaphores = frame->sem,
1941  .signalSemaphoreCount = planes,
1942  };
1943 
1944  VkPipelineStageFlagBits wait_st[AV_NUM_DATA_POINTERS];
1945  for (int i = 0; i < planes; i++) {
1946  wait_st[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1947  sem_sig_val[i] = frame->sem_value[i] + 1;
1948  }
1949 
1950  switch (pmode) {
1951  case PREP_MODE_WRITE:
1952  new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1953  new_access = VK_ACCESS_TRANSFER_WRITE_BIT;
1954  src_qf = VK_QUEUE_FAMILY_IGNORED;
1955  dst_qf = VK_QUEUE_FAMILY_IGNORED;
1956  break;
1958  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1959  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1960  src_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
1961  dst_qf = VK_QUEUE_FAMILY_IGNORED;
1962  s_timeline_sem_info.pWaitSemaphoreValues = frame->sem_value;
1963  s_timeline_sem_info.waitSemaphoreValueCount = planes;
1964  s_info.pWaitSemaphores = frame->sem;
1965  s_info.pWaitDstStageMask = wait_st;
1966  s_info.waitSemaphoreCount = planes;
1967  break;
1969  new_layout = VK_IMAGE_LAYOUT_GENERAL;
1970  new_access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
1971  src_qf = VK_QUEUE_FAMILY_IGNORED;
1972  dst_qf = VK_QUEUE_FAMILY_EXTERNAL_KHR;
1973  s_timeline_sem_info.pWaitSemaphoreValues = frame->sem_value;
1974  s_timeline_sem_info.waitSemaphoreValueCount = planes;
1975  s_info.pWaitSemaphores = frame->sem;
1976  s_info.pWaitDstStageMask = wait_st;
1977  s_info.waitSemaphoreCount = planes;
1978  break;
1979  }
1980 
1981  if ((err = wait_start_exec_ctx(hwfc, ectx)))
1982  return err;
1983 
1984  /* Change the image layout to something more optimal for writes.
1985  * This also signals the newly created semaphore, making it usable
1986  * for synchronization */
1987  for (int i = 0; i < planes; i++) {
1988  img_bar[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1989  img_bar[i].srcAccessMask = 0x0;
1990  img_bar[i].dstAccessMask = new_access;
1991  img_bar[i].oldLayout = frame->layout[i];
1992  img_bar[i].newLayout = new_layout;
1993  img_bar[i].srcQueueFamilyIndex = src_qf;
1994  img_bar[i].dstQueueFamilyIndex = dst_qf;
1995  img_bar[i].image = frame->img[i];
1996  img_bar[i].subresourceRange.levelCount = 1;
1997  img_bar[i].subresourceRange.layerCount = 1;
1998  img_bar[i].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1999 
2000  frame->layout[i] = img_bar[i].newLayout;
2001  frame->access[i] = img_bar[i].dstAccessMask;
2002  }
2003 
2004  vk->CmdPipelineBarrier(get_buf_exec_ctx(hwfc, ectx),
2005  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2006  VK_PIPELINE_STAGE_TRANSFER_BIT,
2007  0, 0, NULL, 0, NULL, planes, img_bar);
2008 
2009  return submit_exec_ctx(hwfc, ectx, &s_info, frame, 0);
2010 }
2011 
2012 static inline void get_plane_wh(int *w, int *h, enum AVPixelFormat format,
2013  int frame_w, int frame_h, int plane)
2014 {
2016 
2017  /* Currently always true unless gray + alpha support is added */
2018  if (!plane || (plane == 3) || desc->flags & AV_PIX_FMT_FLAG_RGB ||
2019  !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
2020  *w = frame_w;
2021  *h = frame_h;
2022  return;
2023  }
2024 
2025  *w = AV_CEIL_RSHIFT(frame_w, desc->log2_chroma_w);
2026  *h = AV_CEIL_RSHIFT(frame_h, desc->log2_chroma_h);
2027 }
2028 
2030  VkImageTiling tiling, VkImageUsageFlagBits usage,
2031  void *create_pnext)
2032 {
2033  int err;
2034  VkResult ret;
2035  AVHWDeviceContext *ctx = hwfc->device_ctx;
2036  VulkanDevicePriv *p = ctx->internal->priv;
2037  FFVulkanFunctions *vk = &p->vkfn;
2038  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2039  enum AVPixelFormat format = hwfc->sw_format;
2040  const VkFormat *img_fmts = av_vkfmt_from_pixfmt(format);
2041  const int planes = av_pix_fmt_count_planes(format);
2042 
2043  VkExportSemaphoreCreateInfo ext_sem_info = {
2044  .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
2045 #ifdef _WIN32
2046  .handleTypes = IsWindows8OrGreater()
2047  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
2048  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
2049 #else
2050  .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
2051 #endif
2052  };
2053 
2054  VkSemaphoreTypeCreateInfo sem_type_info = {
2055  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2056 #ifdef _WIN32
2057  .pNext = p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM ? &ext_sem_info : NULL,
2058 #else
2059  .pNext = p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM ? &ext_sem_info : NULL,
2060 #endif
2061  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2062  .initialValue = 0,
2063  };
2064 
2065  VkSemaphoreCreateInfo sem_spawn = {
2066  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2067  .pNext = &sem_type_info,
2068  };
2069 
2071  if (!f) {
2072  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2073  return AVERROR(ENOMEM);
2074  }
2075 
2076  /* Create the images */
2077  for (int i = 0; i < planes; i++) {
2078  VkImageCreateInfo create_info = {
2079  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2080  .pNext = create_pnext,
2081  .imageType = VK_IMAGE_TYPE_2D,
2082  .format = img_fmts[i],
2083  .extent.depth = 1,
2084  .mipLevels = 1,
2085  .arrayLayers = 1,
2086  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2087  .tiling = tiling,
2088  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2089  .usage = usage,
2090  .samples = VK_SAMPLE_COUNT_1_BIT,
2091  .pQueueFamilyIndices = p->qfs,
2092  .queueFamilyIndexCount = p->num_qfs,
2093  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2094  VK_SHARING_MODE_EXCLUSIVE,
2095  };
2096 
2097  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2098  format, hwfc->width, hwfc->height, i);
2099 
2100  ret = vk->CreateImage(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  /* Create semaphore */
2110  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2111  hwctx->alloc, &f->sem[i]);
2112  if (ret != VK_SUCCESS) {
2113  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2114  vk_ret2str(ret));
2115  return AVERROR_EXTERNAL;
2116  }
2117 
2118  f->layout[i] = create_info.initialLayout;
2119  f->access[i] = 0x0;
2120  f->sem_value[i] = 0;
2121  }
2122 
2123  f->flags = 0x0;
2124  f->tiling = tiling;
2125 
2126  *frame = f;
2127  return 0;
2128 
2129 fail:
2130  vulkan_frame_free(hwfc, (uint8_t *)f);
2131  return err;
2132 }
2133 
2134 /* Checks if an export flag is enabled, and if it is ORs it with *iexp */
2136  VkExternalMemoryHandleTypeFlags *comp_handle_types,
2137  VkExternalMemoryHandleTypeFlagBits *iexp,
2138  VkExternalMemoryHandleTypeFlagBits exp)
2139 {
2140  VkResult ret;
2141  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2142  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
2144  FFVulkanFunctions *vk = &p->vkfn;
2145 
2146  const VkImageDrmFormatModifierListCreateInfoEXT *drm_mod_info =
2148  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2149  int has_mods = hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && drm_mod_info;
2150  int nb_mods;
2151 
2152  VkExternalImageFormatProperties eprops = {
2153  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2154  };
2155  VkImageFormatProperties2 props = {
2156  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2157  .pNext = &eprops,
2158  };
2159  VkPhysicalDeviceImageDrmFormatModifierInfoEXT phy_dev_mod_info = {
2160  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2161  .pNext = NULL,
2162  .pQueueFamilyIndices = p->qfs,
2163  .queueFamilyIndexCount = p->num_qfs,
2164  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2165  VK_SHARING_MODE_EXCLUSIVE,
2166  };
2167  VkPhysicalDeviceExternalImageFormatInfo enext = {
2168  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2169  .handleType = exp,
2170  .pNext = has_mods ? &phy_dev_mod_info : NULL,
2171  };
2172  VkPhysicalDeviceImageFormatInfo2 pinfo = {
2173  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2174  .pNext = !exp ? NULL : &enext,
2175  .format = av_vkfmt_from_pixfmt(hwfc->sw_format)[0],
2176  .type = VK_IMAGE_TYPE_2D,
2177  .tiling = hwctx->tiling,
2178  .usage = hwctx->usage,
2179  .flags = VK_IMAGE_CREATE_ALIAS_BIT,
2180  };
2181 
2182  nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
2183  for (int i = 0; i < nb_mods; i++) {
2184  if (has_mods)
2185  phy_dev_mod_info.drmFormatModifier = drm_mod_info->pDrmFormatModifiers[i];
2186 
2187  ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
2188  &pinfo, &props);
2189 
2190  if (ret == VK_SUCCESS) {
2191  *iexp |= exp;
2192  *comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
2193  }
2194  }
2195 }
2196 
2197 static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size)
2198 {
2199  int err;
2200  AVVkFrame *f;
2201  AVBufferRef *avbuf = NULL;
2202  AVHWFramesContext *hwfc = opaque;
2203  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2205  VulkanFramesPriv *fp = hwfc->internal->priv;
2206  VkExportMemoryAllocateInfo eminfo[AV_NUM_DATA_POINTERS];
2207  VkExternalMemoryHandleTypeFlags e = 0x0;
2208 
2209  VkExternalMemoryImageCreateInfo eiinfo = {
2210  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2211  .pNext = hwctx->create_pnext,
2212  };
2213 
2214 #ifdef _WIN32
2215  if (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY)
2216  try_export_flags(hwfc, &eiinfo.handleTypes, &e, IsWindows8OrGreater()
2217  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
2218  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
2219 #else
2221  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2222  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
2223 
2225  try_export_flags(hwfc, &eiinfo.handleTypes, &e,
2226  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2227 #endif
2228 
2229  for (int i = 0; i < av_pix_fmt_count_planes(hwfc->sw_format); i++) {
2230  eminfo[i].sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
2231  eminfo[i].pNext = hwctx->alloc_pnext[i];
2232  eminfo[i].handleTypes = e;
2233  }
2234 
2235  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
2236  eiinfo.handleTypes ? &eiinfo : NULL);
2237  if (err)
2238  return NULL;
2239 
2240  err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
2241  if (err)
2242  goto fail;
2243 
2244  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_WRITE);
2245  if (err)
2246  goto fail;
2247 
2248  avbuf = av_buffer_create((uint8_t *)f, sizeof(AVVkFrame),
2249  vulkan_frame_free, hwfc, 0);
2250  if (!avbuf)
2251  goto fail;
2252 
2253  return avbuf;
2254 
2255 fail:
2256  vulkan_frame_free(hwfc, (uint8_t *)f);
2257  return NULL;
2258 }
2259 
2261 {
2262  VulkanFramesPriv *fp = hwfc->internal->priv;
2263 
2264  if (fp->modifier_info) {
2265  if (fp->modifier_info->pDrmFormatModifiers)
2266  av_freep(&fp->modifier_info->pDrmFormatModifiers);
2267  av_freep(&fp->modifier_info);
2268  }
2269 
2270  free_exec_ctx(hwfc, &fp->conv_ctx);
2271  free_exec_ctx(hwfc, &fp->upload_ctx);
2272  free_exec_ctx(hwfc, &fp->download_ctx);
2273 }
2274 
2276 {
2277  int err;
2278  AVVkFrame *f;
2279  AVVulkanFramesContext *hwctx = hwfc->hwctx;
2280  VulkanFramesPriv *fp = hwfc->internal->priv;
2281  AVVulkanDeviceContext *dev_hwctx = hwfc->device_ctx->hwctx;
2283  const VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
2284  const int has_modifiers = !!(p->extensions & FF_VK_EXT_DRM_MODIFIER_FLAGS);
2285 
2286  /* Default tiling flags */
2287  hwctx->tiling = hwctx->tiling ? hwctx->tiling :
2288  has_modifiers ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
2289  p->use_linear_images ? VK_IMAGE_TILING_LINEAR :
2290  VK_IMAGE_TILING_OPTIMAL;
2291 
2292  if (!hwctx->usage)
2294 
2295  if (!(hwctx->flags & AV_VK_FRAME_FLAG_NONE)) {
2296  if (p->contiguous_planes == 1 ||
2297  ((p->contiguous_planes == -1) && p->dev_is_intel))
2299  }
2300 
2301  modifier_info = vk_find_struct(hwctx->create_pnext,
2302  VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
2303 
2304  /* Get the supported modifiers if the user has not given any. */
2305  if (has_modifiers && !modifier_info) {
2306  const VkFormat *fmt = av_vkfmt_from_pixfmt(hwfc->sw_format);
2307  VkImageDrmFormatModifierListCreateInfoEXT *modifier_info;
2308  FFVulkanFunctions *vk = &p->vkfn;
2309  VkDrmFormatModifierPropertiesEXT *mod_props;
2310  uint64_t *modifiers;
2311  int modifier_count = 0;
2312 
2313  VkDrmFormatModifierPropertiesListEXT mod_props_list = {
2314  .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
2315  .pNext = NULL,
2316  .drmFormatModifierCount = 0,
2317  .pDrmFormatModifierProperties = NULL,
2318  };
2319  VkFormatProperties2 prop = {
2320  .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
2321  .pNext = &mod_props_list,
2322  };
2323 
2324  /* Get all supported modifiers */
2325  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
2326 
2327  if (!mod_props_list.drmFormatModifierCount) {
2328  av_log(hwfc, AV_LOG_ERROR, "There are no supported modifiers for the given sw_format\n");
2329  return AVERROR(EINVAL);
2330  }
2331 
2332  /* Createa structure to hold the modifier list info */
2333  modifier_info = av_mallocz(sizeof(*modifier_info));
2334  if (!modifier_info)
2335  return AVERROR(ENOMEM);
2336 
2337  modifier_info->pNext = NULL;
2338  modifier_info->sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;
2339 
2340  /* Add structure to the image creation pNext chain */
2341  if (!hwctx->create_pnext)
2342  hwctx->create_pnext = modifier_info;
2343  else
2344  vk_link_struct(hwctx->create_pnext, (void *)modifier_info);
2345 
2346  /* Backup the allocated struct to be freed later */
2347  fp->modifier_info = modifier_info;
2348 
2349  /* Allocate list of modifiers */
2350  modifiers = av_mallocz(mod_props_list.drmFormatModifierCount *
2351  sizeof(*modifiers));
2352  if (!modifiers)
2353  return AVERROR(ENOMEM);
2354 
2355  modifier_info->pDrmFormatModifiers = modifiers;
2356 
2357  /* Allocate a temporary list to hold all modifiers supported */
2358  mod_props = av_mallocz(mod_props_list.drmFormatModifierCount *
2359  sizeof(*mod_props));
2360  if (!mod_props)
2361  return AVERROR(ENOMEM);
2362 
2363  mod_props_list.pDrmFormatModifierProperties = mod_props;
2364 
2365  /* Finally get all modifiers from the device */
2366  vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt[0], &prop);
2367 
2368  /* Reject any modifiers that don't match our requirements */
2369  for (int i = 0; i < mod_props_list.drmFormatModifierCount; i++) {
2370  if (!(mod_props[i].drmFormatModifierTilingFeatures & hwctx->usage))
2371  continue;
2372 
2373  modifiers[modifier_count++] = mod_props[i].drmFormatModifier;
2374  }
2375 
2376  if (!modifier_count) {
2377  av_log(hwfc, AV_LOG_ERROR, "None of the given modifiers supports"
2378  " the usage flags!\n");
2379  av_freep(&mod_props);
2380  return AVERROR(EINVAL);
2381  }
2382 
2383  modifier_info->drmFormatModifierCount = modifier_count;
2384  av_freep(&mod_props);
2385  }
2386 
2387  err = create_exec_ctx(hwfc, &fp->conv_ctx,
2388  dev_hwctx->queue_family_comp_index,
2389  dev_hwctx->nb_comp_queues);
2390  if (err)
2391  return err;
2392 
2393  err = create_exec_ctx(hwfc, &fp->upload_ctx,
2394  dev_hwctx->queue_family_tx_index,
2395  dev_hwctx->nb_tx_queues);
2396  if (err)
2397  return err;
2398 
2399  err = create_exec_ctx(hwfc, &fp->download_ctx,
2400  dev_hwctx->queue_family_tx_index, 1);
2401  if (err)
2402  return err;
2403 
2404  /* Test to see if allocation will fail */
2405  err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage,
2406  hwctx->create_pnext);
2407  if (err)
2408  return err;
2409 
2410  vulkan_frame_free(hwfc, (uint8_t *)f);
2411 
2412  /* If user did not specify a pool, hwfc->pool will be set to the internal one
2413  * in hwcontext.c just after this gets called */
2414  if (!hwfc->pool) {
2416  hwfc, vulkan_pool_alloc,
2417  NULL);
2418  if (!hwfc->internal->pool_internal)
2419  return AVERROR(ENOMEM);
2420  }
2421 
2422  return 0;
2423 }
2424 
2426 {
2427  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
2428  if (!frame->buf[0])
2429  return AVERROR(ENOMEM);
2430 
2431  frame->data[0] = frame->buf[0]->data;
2432  frame->format = AV_PIX_FMT_VULKAN;
2433  frame->width = hwfc->width;
2434  frame->height = hwfc->height;
2435 
2436  return 0;
2437 }
2438 
2440  enum AVHWFrameTransferDirection dir,
2441  enum AVPixelFormat **formats)
2442 {
2443  enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
2444  if (!fmts)
2445  return AVERROR(ENOMEM);
2446 
2447  fmts[0] = hwfc->sw_format;
2448  fmts[1] = AV_PIX_FMT_NONE;
2449 
2450  *formats = fmts;
2451  return 0;
2452 }
2453 
2454 typedef struct VulkanMapping {
2456  int flags;
2457 } VulkanMapping;
2458 
2460 {
2461  VulkanMapping *map = hwmap->priv;
2462  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2463  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2465  FFVulkanFunctions *vk = &p->vkfn;
2466 
2467  /* Check if buffer needs flushing */
2468  if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
2469  !(map->frame->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
2470  VkResult ret;
2471  VkMappedMemoryRange flush_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
2472 
2473  for (int i = 0; i < planes; i++) {
2474  flush_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
2475  flush_ranges[i].memory = map->frame->mem[i];
2476  flush_ranges[i].size = VK_WHOLE_SIZE;
2477  }
2478 
2479  ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, planes,
2480  flush_ranges);
2481  if (ret != VK_SUCCESS) {
2482  av_log(hwfc, AV_LOG_ERROR, "Failed to flush memory: %s\n",
2483  vk_ret2str(ret));
2484  }
2485  }
2486 
2487  for (int i = 0; i < planes; i++)
2488  vk->UnmapMemory(hwctx->act_dev, map->frame->mem[i]);
2489 
2490  av_free(map);
2491 }
2492 
2494  const AVFrame *src, int flags)
2495 {
2496  VkResult ret;
2497  int err, mapped_mem_count = 0, mem_planes = 0;
2498  AVVkFrame *f = (AVVkFrame *)src->data[0];
2499  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2500  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
2501  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2503  FFVulkanFunctions *vk = &p->vkfn;
2504 
2506  if (!map)
2507  return AVERROR(EINVAL);
2508 
2509  if (src->format != AV_PIX_FMT_VULKAN) {
2510  av_log(hwfc, AV_LOG_ERROR, "Cannot map from pixel format %s!\n",
2511  av_get_pix_fmt_name(src->format));
2512  err = AVERROR(EINVAL);
2513  goto fail;
2514  }
2515 
2516  if (!(f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ||
2517  !(f->tiling == VK_IMAGE_TILING_LINEAR)) {
2518  av_log(hwfc, AV_LOG_ERROR, "Unable to map frame, not host visible "
2519  "and linear!\n");
2520  err = AVERROR(EINVAL);
2521  goto fail;
2522  }
2523 
2524  dst->width = src->width;
2525  dst->height = src->height;
2526 
2527  mem_planes = hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY ? 1 : planes;
2528  for (int i = 0; i < mem_planes; i++) {
2529  ret = vk->MapMemory(hwctx->act_dev, f->mem[i], 0,
2530  VK_WHOLE_SIZE, 0, (void **)&dst->data[i]);
2531  if (ret != VK_SUCCESS) {
2532  av_log(hwfc, AV_LOG_ERROR, "Failed to map image memory: %s\n",
2533  vk_ret2str(ret));
2534  err = AVERROR_EXTERNAL;
2535  goto fail;
2536  }
2537  mapped_mem_count++;
2538  }
2539 
2540  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY) {
2541  for (int i = 0; i < planes; i++)
2542  dst->data[i] = dst->data[0] + f->offset[i];
2543  }
2544 
2545  /* Check if the memory contents matter */
2547  !(f->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
2548  VkMappedMemoryRange map_mem_ranges[AV_NUM_DATA_POINTERS] = { { 0 } };
2549  for (int i = 0; i < planes; i++) {
2550  map_mem_ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
2551  map_mem_ranges[i].size = VK_WHOLE_SIZE;
2552  map_mem_ranges[i].memory = f->mem[i];
2553  }
2554 
2555  ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, planes,
2556  map_mem_ranges);
2557  if (ret != VK_SUCCESS) {
2558  av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate memory: %s\n",
2559  vk_ret2str(ret));
2560  err = AVERROR_EXTERNAL;
2561  goto fail;
2562  }
2563  }
2564 
2565  for (int i = 0; i < planes; i++) {
2566  VkImageSubresource sub = {
2567  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2568  };
2569  VkSubresourceLayout layout;
2570  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
2571  dst->linesize[i] = layout.rowPitch;
2572  }
2573 
2574  map->frame = f;
2575  map->flags = flags;
2576 
2577  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
2579  if (err < 0)
2580  goto fail;
2581 
2582  return 0;
2583 
2584 fail:
2585  for (int i = 0; i < mapped_mem_count; i++)
2586  vk->UnmapMemory(hwctx->act_dev, f->mem[i]);
2587 
2588  av_free(map);
2589  return err;
2590 }
2591 
2592 #if CONFIG_LIBDRM
2593 static void vulkan_unmap_from_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
2594 {
2595  AVVkFrame *f = hwmap->priv;
2596  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
2597  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
2599  FFVulkanFunctions *vk = &p->vkfn;
2600 
2601  VkSemaphoreWaitInfo wait_info = {
2602  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
2603  .flags = 0x0,
2604  .pSemaphores = f->sem,
2605  .pValues = f->sem_value,
2606  .semaphoreCount = planes,
2607  };
2608 
2609  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
2610 
2612 
2613  for (int i = 0; i < planes; i++) {
2614  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2615  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2616  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2617  }
2618 
2619  av_free(f);
2620 }
2621 
2622 static const struct {
2623  uint32_t drm_fourcc;
2624  VkFormat vk_format;
2625 } vulkan_drm_format_map[] = {
2626  { DRM_FORMAT_R8, VK_FORMAT_R8_UNORM },
2627  { DRM_FORMAT_R16, VK_FORMAT_R16_UNORM },
2628  { DRM_FORMAT_GR88, VK_FORMAT_R8G8_UNORM },
2629  { DRM_FORMAT_RG88, VK_FORMAT_R8G8_UNORM },
2630  { DRM_FORMAT_GR1616, VK_FORMAT_R16G16_UNORM },
2631  { DRM_FORMAT_RG1616, VK_FORMAT_R16G16_UNORM },
2632  { DRM_FORMAT_ARGB8888, VK_FORMAT_B8G8R8A8_UNORM },
2633  { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM },
2634  { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM },
2635  { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM },
2636 
2637  // All these DRM_FORMATs were added in the same libdrm commit.
2638 #ifdef DRM_FORMAT_XYUV8888
2639  { DRM_FORMAT_XYUV8888, VK_FORMAT_R8G8B8A8_UNORM },
2640  { DRM_FORMAT_XVYU12_16161616, VK_FORMAT_R16G16B16A16_UNORM} ,
2641  // As we had to map XV36 to a 16bit Vulkan format, reverse mapping will
2642  // end up yielding Y416 as the DRM format, so we need to recognise it.
2643  { DRM_FORMAT_Y416, VK_FORMAT_R16G16B16A16_UNORM },
2644 #endif
2645 };
2646 
2647 static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc)
2648 {
2649  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
2650  if (vulkan_drm_format_map[i].drm_fourcc == drm_fourcc)
2651  return vulkan_drm_format_map[i].vk_format;
2652  return VK_FORMAT_UNDEFINED;
2653 }
2654 
2655 static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame,
2656  const AVFrame *src)
2657 {
2658  int err = 0;
2659  VkResult ret;
2660  AVVkFrame *f;
2661  int bind_counts = 0;
2662  AVHWDeviceContext *ctx = hwfc->device_ctx;
2663  AVVulkanDeviceContext *hwctx = ctx->hwctx;
2664  VulkanDevicePriv *p = ctx->internal->priv;
2665  FFVulkanFunctions *vk = &p->vkfn;
2666  VulkanFramesPriv *fp = hwfc->internal->priv;
2667  const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0];
2668  VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES];
2669  VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES];
2670 
2671  for (int i = 0; i < desc->nb_layers; i++) {
2672  if (drm_to_vulkan_fmt(desc->layers[i].format) == VK_FORMAT_UNDEFINED) {
2673  av_log(ctx, AV_LOG_ERROR, "Unsupported DMABUF layer format %#08x!\n",
2674  desc->layers[i].format);
2675  return AVERROR(EINVAL);
2676  }
2677  }
2678 
2679  if (!(f = av_vk_frame_alloc())) {
2680  av_log(ctx, AV_LOG_ERROR, "Unable to allocate memory for AVVkFrame!\n");
2681  err = AVERROR(ENOMEM);
2682  goto fail;
2683  }
2684 
2685  f->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
2686 
2687  for (int i = 0; i < desc->nb_layers; i++) {
2688  const int planes = desc->layers[i].nb_planes;
2689 
2690  /* Semaphore */
2691  VkSemaphoreTypeCreateInfo sem_type_info = {
2692  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
2693  .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
2694  .initialValue = 0,
2695  };
2696  VkSemaphoreCreateInfo sem_spawn = {
2697  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2698  .pNext = &sem_type_info,
2699  };
2700 
2701  /* Image creation */
2702  VkSubresourceLayout ext_img_layouts[AV_DRM_MAX_PLANES];
2703  VkImageDrmFormatModifierExplicitCreateInfoEXT ext_img_mod_spec = {
2704  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
2705  .drmFormatModifier = desc->objects[0].format_modifier,
2706  .drmFormatModifierPlaneCount = planes,
2707  .pPlaneLayouts = (const VkSubresourceLayout *)&ext_img_layouts,
2708  };
2709  VkExternalMemoryImageCreateInfo ext_img_spec = {
2710  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2711  .pNext = &ext_img_mod_spec,
2712  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2713  };
2714  VkImageCreateInfo create_info = {
2715  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2716  .pNext = &ext_img_spec,
2717  .imageType = VK_IMAGE_TYPE_2D,
2718  .format = drm_to_vulkan_fmt(desc->layers[i].format),
2719  .extent.depth = 1,
2720  .mipLevels = 1,
2721  .arrayLayers = 1,
2722  .flags = 0x0, /* ALIAS flag is implicit for imported images */
2723  .tiling = f->tiling,
2724  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */
2725  .usage = VK_IMAGE_USAGE_SAMPLED_BIT |
2726  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
2727  .samples = VK_SAMPLE_COUNT_1_BIT,
2728  .pQueueFamilyIndices = p->qfs,
2729  .queueFamilyIndexCount = p->num_qfs,
2730  .sharingMode = p->num_qfs > 1 ? VK_SHARING_MODE_CONCURRENT :
2731  VK_SHARING_MODE_EXCLUSIVE,
2732  };
2733 
2734  /* Image format verification */
2735  VkExternalImageFormatProperties ext_props = {
2736  .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR,
2737  };
2738  VkImageFormatProperties2 props_ret = {
2739  .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
2740  .pNext = &ext_props,
2741  };
2742  VkPhysicalDeviceImageDrmFormatModifierInfoEXT props_drm_mod = {
2743  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
2744  .drmFormatModifier = ext_img_mod_spec.drmFormatModifier,
2745  .pQueueFamilyIndices = create_info.pQueueFamilyIndices,
2746  .queueFamilyIndexCount = create_info.queueFamilyIndexCount,
2747  .sharingMode = create_info.sharingMode,
2748  };
2749  VkPhysicalDeviceExternalImageFormatInfo props_ext = {
2750  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
2751  .pNext = &props_drm_mod,
2752  .handleType = ext_img_spec.handleTypes,
2753  };
2754  VkPhysicalDeviceImageFormatInfo2 fmt_props = {
2755  .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
2756  .pNext = &props_ext,
2757  .format = create_info.format,
2758  .type = create_info.imageType,
2759  .tiling = create_info.tiling,
2760  .usage = create_info.usage,
2761  .flags = create_info.flags,
2762  };
2763 
2764  /* Check if importing is possible for this combination of parameters */
2765  ret = vk->GetPhysicalDeviceImageFormatProperties2(hwctx->phys_dev,
2766  &fmt_props, &props_ret);
2767  if (ret != VK_SUCCESS) {
2768  av_log(ctx, AV_LOG_ERROR, "Cannot map DRM frame to Vulkan: %s\n",
2769  vk_ret2str(ret));
2770  err = AVERROR_EXTERNAL;
2771  goto fail;
2772  }
2773 
2774  /* Set the image width/height */
2775  get_plane_wh(&create_info.extent.width, &create_info.extent.height,
2776  hwfc->sw_format, src->width, src->height, i);
2777 
2778  /* Set the subresource layout based on the layer properties */
2779  for (int j = 0; j < planes; j++) {
2780  ext_img_layouts[j].offset = desc->layers[i].planes[j].offset;
2781  ext_img_layouts[j].rowPitch = desc->layers[i].planes[j].pitch;
2782  ext_img_layouts[j].size = 0; /* The specs say so for all 3 */
2783  ext_img_layouts[j].arrayPitch = 0;
2784  ext_img_layouts[j].depthPitch = 0;
2785  }
2786 
2787  /* Create image */
2788  ret = vk->CreateImage(hwctx->act_dev, &create_info,
2789  hwctx->alloc, &f->img[i]);
2790  if (ret != VK_SUCCESS) {
2791  av_log(ctx, AV_LOG_ERROR, "Image creation failure: %s\n",
2792  vk_ret2str(ret));
2793  err = AVERROR(EINVAL);
2794  goto fail;
2795  }
2796 
2797  ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn,
2798  hwctx->alloc, &f->sem[i]);
2799  if (ret != VK_SUCCESS) {
2800  av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n",
2801  vk_ret2str(ret));
2802  return AVERROR_EXTERNAL;
2803  }
2804 
2805  /* We'd import a semaphore onto the one we created using
2806  * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI
2807  * offer us anything we could import and sync with, so instead
2808  * just signal the semaphore we created. */
2809 
2810  f->layout[i] = create_info.initialLayout;
2811  f->access[i] = 0x0;
2812  f->sem_value[i] = 0;
2813  }
2814 
2815  for (int i = 0; i < desc->nb_objects; i++) {
2816  /* Memory requirements */
2817  VkImageMemoryRequirementsInfo2 req_desc = {
2818  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2819  .image = f->img[i],
2820  };
2821  VkMemoryDedicatedRequirements ded_req = {
2822  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
2823  };
2824  VkMemoryRequirements2 req2 = {
2825  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
2826  .pNext = &ded_req,
2827  };
2828 
2829  /* Allocation/importing */
2830  VkMemoryFdPropertiesKHR fdmp = {
2831  .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
2832  };
2833  VkImportMemoryFdInfoKHR idesc = {
2834  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2835  .fd = dup(desc->objects[i].fd),
2836  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2837  };
2838  VkMemoryDedicatedAllocateInfo ded_alloc = {
2839  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2840  .pNext = &idesc,
2841  .image = req_desc.image,
2842  };
2843 
2844  /* Get object properties */
2845  ret = vk->GetMemoryFdPropertiesKHR(hwctx->act_dev,
2846  VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
2847  idesc.fd, &fdmp);
2848  if (ret != VK_SUCCESS) {
2849  av_log(hwfc, AV_LOG_ERROR, "Failed to get FD properties: %s\n",
2850  vk_ret2str(ret));
2851  err = AVERROR_EXTERNAL;
2852  close(idesc.fd);
2853  goto fail;
2854  }
2855 
2856  vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req2);
2857 
2858  /* Only a single bit must be set, not a range, and it must match */
2859  req2.memoryRequirements.memoryTypeBits = fdmp.memoryTypeBits;
2860 
2861  err = alloc_mem(ctx, &req2.memoryRequirements,
2862  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
2863  (ded_req.prefersDedicatedAllocation ||
2864  ded_req.requiresDedicatedAllocation) ?
2865  &ded_alloc : ded_alloc.pNext,
2866  &f->flags, &f->mem[i]);
2867  if (err) {
2868  close(idesc.fd);
2869  return err;
2870  }
2871 
2872  f->size[i] = req2.memoryRequirements.size;
2873  }
2874 
2875  for (int i = 0; i < desc->nb_layers; i++) {
2876  const int planes = desc->layers[i].nb_planes;
2877  for (int j = 0; j < planes; j++) {
2878  VkImageAspectFlagBits aspect = j == 0 ? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT :
2879  j == 1 ? VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT :
2880  VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
2881 
2882  plane_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
2883  plane_info[bind_counts].pNext = NULL;
2884  plane_info[bind_counts].planeAspect = aspect;
2885 
2886  bind_info[bind_counts].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
2887  bind_info[bind_counts].pNext = planes > 1 ? &plane_info[bind_counts] : NULL;
2888  bind_info[bind_counts].image = f->img[i];
2889  bind_info[bind_counts].memory = f->mem[desc->layers[i].planes[j].object_index];
2890 
2891  /* Offset is already signalled via pPlaneLayouts above */
2892  bind_info[bind_counts].memoryOffset = 0;
2893 
2894  bind_counts++;
2895  }
2896  }
2897 
2898  /* Bind the allocated memory to the images */
2899  ret = vk->BindImageMemory2(hwctx->act_dev, bind_counts, bind_info);
2900  if (ret != VK_SUCCESS) {
2901  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory: %s\n",
2902  vk_ret2str(ret));
2903  err = AVERROR_EXTERNAL;
2904  goto fail;
2905  }
2906 
2907  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_IMPORT);
2908  if (err)
2909  goto fail;
2910 
2911  *frame = f;
2912 
2913  return 0;
2914 
2915 fail:
2916  for (int i = 0; i < desc->nb_layers; i++) {
2917  vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
2918  vk->DestroySemaphore(hwctx->act_dev, f->sem[i], hwctx->alloc);
2919  }
2920  for (int i = 0; i < desc->nb_objects; i++)
2921  vk->FreeMemory(hwctx->act_dev, f->mem[i], hwctx->alloc);
2922 
2923  av_free(f);
2924 
2925  return err;
2926 }
2927 
2928 static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst,
2929  const AVFrame *src, int flags)
2930 {
2931  int err = 0;
2932  AVVkFrame *f;
2933 
2934  if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src)))
2935  return err;
2936 
2937  /* The unmapping function will free this */
2938  dst->data[0] = (uint8_t *)f;
2939  dst->width = src->width;
2940  dst->height = src->height;
2941 
2942  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2943  &vulkan_unmap_from_drm, f);
2944  if (err < 0)
2945  goto fail;
2946 
2947  av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n");
2948 
2949  return 0;
2950 
2951 fail:
2952  vulkan_frame_free(hwfc->device_ctx->hwctx, (uint8_t *)f);
2953  dst->data[0] = NULL;
2954  return err;
2955 }
2956 
2957 #if CONFIG_VAAPI
2958 static int vulkan_map_from_vaapi(AVHWFramesContext *dst_fc,
2959  AVFrame *dst, const AVFrame *src,
2960  int flags)
2961 {
2962  int err;
2963  AVFrame *tmp = av_frame_alloc();
2964  AVHWFramesContext *vaapi_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
2965  AVVAAPIDeviceContext *vaapi_ctx = vaapi_fc->device_ctx->hwctx;
2966  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)src->data[3];
2967 
2968  if (!tmp)
2969  return AVERROR(ENOMEM);
2970 
2971  /* We have to sync since like the previous comment said, no semaphores */
2972  vaSyncSurface(vaapi_ctx->display, surface_id);
2973 
2974  tmp->format = AV_PIX_FMT_DRM_PRIME;
2975 
2976  err = av_hwframe_map(tmp, src, flags);
2977  if (err < 0)
2978  goto fail;
2979 
2980  err = vulkan_map_from_drm(dst_fc, dst, tmp, flags);
2981  if (err < 0)
2982  goto fail;
2983 
2984  err = ff_hwframe_map_replace(dst, src);
2985 
2986 fail:
2987  av_frame_free(&tmp);
2988  return err;
2989 }
2990 #endif
2991 #endif
2992 
2993 #if CONFIG_CUDA
2994 static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
2995  AVBufferRef *cuda_hwfc,
2996  const AVFrame *frame)
2997 {
2998  int err;
2999  VkResult ret;
3000  AVVkFrame *dst_f;
3001  AVVkFrameInternal *dst_int;
3002  AVHWDeviceContext *ctx = hwfc->device_ctx;
3003  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3004  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3006  VulkanDevicePriv *p = ctx->internal->priv;
3007  FFVulkanFunctions *vk = &p->vkfn;
3008 
3009  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)cuda_hwfc->data;
3010  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3011  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3012  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3013  CudaFunctions *cu = cu_internal->cuda_dl;
3014  CUarray_format cufmt = desc->comp[0].depth > 8 ? CU_AD_FORMAT_UNSIGNED_INT16 :
3015  CU_AD_FORMAT_UNSIGNED_INT8;
3016 
3017  dst_f = (AVVkFrame *)frame->data[0];
3018 
3019  dst_int = dst_f->internal;
3020  if (!dst_int || !dst_int->cuda_fc_ref) {
3021  if (!dst_f->internal)
3022  dst_f->internal = dst_int = av_mallocz(sizeof(*dst_f->internal));
3023 
3024  if (!dst_int)
3025  return AVERROR(ENOMEM);
3026 
3027  dst_int->cuda_fc_ref = av_buffer_ref(cuda_hwfc);
3028  if (!dst_int->cuda_fc_ref) {
3029  av_freep(&dst_f->internal);
3030  return AVERROR(ENOMEM);
3031  }
3032 
3033  for (int i = 0; i < planes; i++) {
3034  CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
3035  .offset = 0,
3036  .arrayDesc = {
3037  .Depth = 0,
3038  .Format = cufmt,
3039  .NumChannels = 1 + ((planes == 2) && i),
3040  .Flags = 0,
3041  },
3042  .numLevels = 1,
3043  };
3044  int p_w, p_h;
3045 
3046 #ifdef _WIN32
3047  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3048  .type = IsWindows8OrGreater()
3049  ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32
3050  : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT,
3051  .size = dst_f->size[i],
3052  };
3053  VkMemoryGetWin32HandleInfoKHR export_info = {
3054  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
3055  .memory = dst_f->mem[i],
3056  .handleType = IsWindows8OrGreater()
3057  ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
3058  : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3059  };
3060  VkSemaphoreGetWin32HandleInfoKHR sem_export = {
3061  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR,
3062  .semaphore = dst_f->sem[i],
3063  .handleType = IsWindows8OrGreater()
3064  ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
3065  : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
3066  };
3067  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3068  .type = 10 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 */,
3069  };
3070 
3071  ret = vk->GetMemoryWin32HandleKHR(hwctx->act_dev, &export_info,
3072  &ext_desc.handle.win32.handle);
3073  if (ret != VK_SUCCESS) {
3074  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a Win32 Handle: %s!\n",
3075  vk_ret2str(ret));
3076  err = AVERROR_EXTERNAL;
3077  goto fail;
3078  }
3079  dst_int->ext_mem_handle[i] = ext_desc.handle.win32.handle;
3080 #else
3081  CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
3082  .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
3083  .size = dst_f->size[i],
3084  };
3085  VkMemoryGetFdInfoKHR export_info = {
3086  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3087  .memory = dst_f->mem[i],
3088  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
3089  };
3090  VkSemaphoreGetFdInfoKHR sem_export = {
3091  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
3092  .semaphore = dst_f->sem[i],
3093  .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
3094  };
3095  CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC ext_sem_desc = {
3096  .type = 9 /* TODO: CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD */,
3097  };
3098 
3099  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3100  &ext_desc.handle.fd);
3101  if (ret != VK_SUCCESS) {
3102  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD: %s!\n",
3103  vk_ret2str(ret));
3104  err = AVERROR_EXTERNAL;
3105  goto fail;
3106  }
3107 #endif
3108 
3109  ret = CHECK_CU(cu->cuImportExternalMemory(&dst_int->ext_mem[i], &ext_desc));
3110  if (ret < 0) {
3111 #ifndef _WIN32
3112  close(ext_desc.handle.fd);
3113 #endif
3114  err = AVERROR_EXTERNAL;
3115  goto fail;
3116  }
3117 
3118  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3119  tex_desc.arrayDesc.Width = p_w;
3120  tex_desc.arrayDesc.Height = p_h;
3121 
3122  ret = CHECK_CU(cu->cuExternalMemoryGetMappedMipmappedArray(&dst_int->cu_mma[i],
3123  dst_int->ext_mem[i],
3124  &tex_desc));
3125  if (ret < 0) {
3126  err = AVERROR_EXTERNAL;
3127  goto fail;
3128  }
3129 
3130  ret = CHECK_CU(cu->cuMipmappedArrayGetLevel(&dst_int->cu_array[i],
3131  dst_int->cu_mma[i], 0));
3132  if (ret < 0) {
3133  err = AVERROR_EXTERNAL;
3134  goto fail;
3135  }
3136 
3137 #ifdef _WIN32
3138  ret = vk->GetSemaphoreWin32HandleKHR(hwctx->act_dev, &sem_export,
3139  &ext_sem_desc.handle.win32.handle);
3140 #else
3141  ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &sem_export,
3142  &ext_sem_desc.handle.fd);
3143 #endif
3144  if (ret != VK_SUCCESS) {
3145  av_log(ctx, AV_LOG_ERROR, "Failed to export semaphore: %s\n",
3146  vk_ret2str(ret));
3147  err = AVERROR_EXTERNAL;
3148  goto fail;
3149  }
3150 #ifdef _WIN32
3151  dst_int->ext_sem_handle[i] = ext_sem_desc.handle.win32.handle;
3152 #endif
3153 
3154  ret = CHECK_CU(cu->cuImportExternalSemaphore(&dst_int->cu_sem[i],
3155  &ext_sem_desc));
3156  if (ret < 0) {
3157 #ifndef _WIN32
3158  close(ext_sem_desc.handle.fd);
3159 #endif
3160  err = AVERROR_EXTERNAL;
3161  goto fail;
3162  }
3163  }
3164  }
3165 
3166  return 0;
3167 
3168 fail:
3169  vulkan_free_internal(dst_f);
3170  return err;
3171 }
3172 
3173 static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
3174  AVFrame *dst, const AVFrame *src)
3175 {
3176  int err;
3177  CUcontext dummy;
3178  AVVkFrame *dst_f;
3179  AVVkFrameInternal *dst_int;
3180  VulkanFramesPriv *fp = hwfc->internal->priv;
3181  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3183 
3184  AVHWFramesContext *cuda_fc = (AVHWFramesContext*)src->hw_frames_ctx->data;
3185  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
3186  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
3187  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
3188  CudaFunctions *cu = cu_internal->cuda_dl;
3189  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
3190  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
3191 
3192  dst_f = (AVVkFrame *)dst->data[0];
3193 
3194  err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_EXPORT);
3195  if (err < 0)
3196  return err;
3197 
3198  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
3199  if (err < 0)
3200  return err;
3201 
3202  err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
3203  if (err < 0) {
3204  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3205  return err;
3206  }
3207 
3208  dst_int = dst_f->internal;
3209 
3210  for (int i = 0; i < planes; i++) {
3211  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
3212  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
3213  }
3214 
3215  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
3216  planes, cuda_dev->stream));
3217  if (err < 0)
3218  goto fail;
3219 
3220  for (int i = 0; i < planes; i++) {
3221  CUDA_MEMCPY2D cpy = {
3222  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
3223  .srcDevice = (CUdeviceptr)src->data[i],
3224  .srcPitch = src->linesize[i],
3225  .srcY = 0,
3226 
3227  .dstMemoryType = CU_MEMORYTYPE_ARRAY,
3228  .dstArray = dst_int->cu_array[i],
3229  };
3230 
3231  int p_w, p_h;
3232  get_plane_wh(&p_w, &p_h, hwfc->sw_format, hwfc->width, hwfc->height, i);
3233 
3234  cpy.WidthInBytes = p_w * desc->comp[i].step;
3235  cpy.Height = p_h;
3236 
3237  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
3238  if (err < 0)
3239  goto fail;
3240  }
3241 
3242  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
3243  planes, cuda_dev->stream));
3244  if (err < 0)
3245  goto fail;
3246 
3247  for (int i = 0; i < planes; i++)
3248  dst_f->sem_value[i]++;
3249 
3250  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3251 
3252  av_log(hwfc, AV_LOG_VERBOSE, "Transfered CUDA image to Vulkan!\n");
3253 
3254  return err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_IMPORT);
3255 
3256 fail:
3257  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
3258  vulkan_free_internal(dst_f);
3259  dst_f->internal = NULL;
3260  av_buffer_unref(&dst->buf[0]);
3261  return err;
3262 }
3263 #endif
3264 
3265 static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
3266  const AVFrame *src, int flags)
3267 {
3269 
3270  switch (src->format) {
3271 #if CONFIG_LIBDRM
3272 #if CONFIG_VAAPI
3273  case AV_PIX_FMT_VAAPI:
3275  return vulkan_map_from_vaapi(hwfc, dst, src, flags);
3276  else
3277  return AVERROR(ENOSYS);
3278 #endif
3279  case AV_PIX_FMT_DRM_PRIME:
3281  return vulkan_map_from_drm(hwfc, dst, src, flags);
3282  else
3283  return AVERROR(ENOSYS);
3284 #endif
3285  default:
3286  return AVERROR(ENOSYS);
3287  }
3288 }
3289 
3290 #if CONFIG_LIBDRM
3291 typedef struct VulkanDRMMapping {
3292  AVDRMFrameDescriptor drm_desc;
3293  AVVkFrame *source;
3294 } VulkanDRMMapping;
3295 
3296 static void vulkan_unmap_to_drm(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
3297 {
3298  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
3299 
3300  for (int i = 0; i < drm_desc->nb_objects; i++)
3301  close(drm_desc->objects[i].fd);
3302 
3303  av_free(drm_desc);
3304 }
3305 
3306 static inline uint32_t vulkan_fmt_to_drm(VkFormat vkfmt)
3307 {
3308  for (int i = 0; i < FF_ARRAY_ELEMS(vulkan_drm_format_map); i++)
3309  if (vulkan_drm_format_map[i].vk_format == vkfmt)
3310  return vulkan_drm_format_map[i].drm_fourcc;
3311  return DRM_FORMAT_INVALID;
3312 }
3313 
3314 static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
3315  const AVFrame *src, int flags)
3316 {
3317  int err = 0;
3318  VkResult ret;
3319  AVVkFrame *f = (AVVkFrame *)src->data[0];
3321  FFVulkanFunctions *vk = &p->vkfn;
3322  VulkanFramesPriv *fp = hwfc->internal->priv;
3323  AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx;
3324  AVVulkanFramesContext *hwfctx = hwfc->hwctx;
3325  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
3326  VkImageDrmFormatModifierPropertiesEXT drm_mod = {
3327  .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
3328  };
3329  VkSemaphoreWaitInfo wait_info = {
3330  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
3331  .flags = 0x0,
3332  .semaphoreCount = planes,
3333  };
3334 
3335  AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
3336  if (!drm_desc)
3337  return AVERROR(ENOMEM);
3338 
3339  err = prepare_frame(hwfc, &fp->conv_ctx, f, PREP_MODE_EXTERNAL_EXPORT);
3340  if (err < 0)
3341  goto end;
3342 
3343  /* Wait for the operation to finish so we can cleanly export it. */
3344  wait_info.pSemaphores = f->sem;
3345  wait_info.pValues = f->sem_value;
3346 
3347  vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
3348 
3349  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
3350  if (err < 0)
3351  goto end;
3352 
3353  ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
3354  &drm_mod);
3355  if (ret != VK_SUCCESS) {
3356  av_log(hwfc, AV_LOG_ERROR, "Failed to retrieve DRM format modifier!\n");
3357  err = AVERROR_EXTERNAL;
3358  goto end;
3359  }
3360 
3361  for (int i = 0; (i < planes) && (f->mem[i]); i++) {
3362  VkMemoryGetFdInfoKHR export_info = {
3363  .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
3364  .memory = f->mem[i],
3365  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
3366  };
3367 
3368  ret = vk->GetMemoryFdKHR(hwctx->act_dev, &export_info,
3369  &drm_desc->objects[i].fd);
3370  if (ret != VK_SUCCESS) {
3371  av_log(hwfc, AV_LOG_ERROR, "Unable to export the image as a FD!\n");
3372  err = AVERROR_EXTERNAL;
3373  goto end;
3374  }
3375 
3376  drm_desc->nb_objects++;
3377  drm_desc->objects[i].size = f->size[i];
3378  drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
3379  }
3380 
3381  drm_desc->nb_layers = planes;
3382  for (int i = 0; i < drm_desc->nb_layers; i++) {
3383  VkSubresourceLayout layout;
3384  VkImageSubresource sub = {
3385  .aspectMask = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
3386  };
3387  VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
3388 
3389  drm_desc->layers[i].format = vulkan_fmt_to_drm(plane_vkfmt);
3390  drm_desc->layers[i].nb_planes = 1;
3391 
3392  if (drm_desc->layers[i].format == DRM_FORMAT_INVALID) {
3393  av_log(hwfc, AV_LOG_ERROR, "Cannot map to DRM layer, unsupported!\n");
3394  err = AVERROR_PATCHWELCOME;
3395  goto end;
3396  }
3397 
3398  drm_desc->layers[i].planes[0].object_index = FFMIN(i, drm_desc->nb_objects - 1);
3399 
3400  if (f->tiling == VK_IMAGE_TILING_OPTIMAL)
3401  continue;
3402 
3403  vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
3404  drm_desc->layers[i].planes[0].offset = layout.offset;
3405  drm_desc->layers[i].planes[0].pitch = layout.rowPitch;
3406 
3407  if (hwfctx->flags & AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY)
3408  drm_desc->layers[i].planes[0].offset += f->offset[i];
3409  }
3410 
3411  dst->width = src->width;
3412  dst->height = src->height;
3413  dst->data[0] = (uint8_t *)drm_desc;
3414 
3415  av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
3416 
3417  return 0;
3418 
3419 end:
3420  av_free(drm_desc);
3421  return err;
3422 }
3423 
3424 #if CONFIG_VAAPI
3425 static int vulkan_map_to_vaapi(AVHWFramesContext *hwfc, AVFrame *dst,
3426  const AVFrame *src, int flags)
3427 {
3428  int err;
3429  AVFrame *tmp = av_frame_alloc();
3430  if (!tmp)
3431  return AVERROR(ENOMEM);
3432 
3433  tmp->format = AV_PIX_FMT_DRM_PRIME;
3434 
3435  err = vulkan_map_to_drm(hwfc, tmp, src, flags);
3436  if (err < 0)
3437  goto fail;
3438 
3439  err = av_hwframe_map(dst, tmp, flags);
3440  if (err < 0)
3441  goto fail;
3442 
3443  err = ff_hwframe_map_replace(dst, src);
3444 
3445 fail:
3446  av_frame_free(&tmp);
3447  return err;
3448 }
3449 #endif
3450 #endif
3451 
3453  const AVFrame *src, int flags)
3454 {
3456 
3457  switch (dst->format) {
3458 #if CONFIG_LIBDRM
3459  case AV_PIX_FMT_DRM_PRIME:
3461  return vulkan_map_to_drm(hwfc, dst, src, flags);
3462  else
3463  return AVERROR(ENOSYS);
3464 #if CONFIG_VAAPI
3465  case AV_PIX_FMT_VAAPI:
3467  return vulkan_map_to_vaapi(hwfc, dst, src, flags);
3468  else
3469  return AVERROR(ENOSYS);
3470 #endif
3471 #endif
3472  default:
3473  return vulkan_map_frame_to_mem(hwfc, dst, src, flags);
3474  }
3475 }
3476 
3477 typedef struct ImageBuffer {
3478  VkBuffer buf;
3479  VkDeviceMemory mem;
3480  VkMemoryPropertyFlagBits flags;
3482 } ImageBuffer;
3483 
3484 static void free_buf(void *opaque, uint8_t *data)
3485 {
3486  AVHWDeviceContext *ctx = opaque;
3487  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3488  VulkanDevicePriv *p = ctx->internal->priv;
3489  FFVulkanFunctions *vk = &p->vkfn;
3490  ImageBuffer *vkbuf = (ImageBuffer *)data;
3491 
3492  if (vkbuf->buf)
3493  vk->DestroyBuffer(hwctx->act_dev, vkbuf->buf, hwctx->alloc);
3494  if (vkbuf->mem)
3495  vk->FreeMemory(hwctx->act_dev, vkbuf->mem, hwctx->alloc);
3496 
3497  av_free(data);
3498 }
3499 
3501 {
3502  size_t size;
3503  *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment);
3504  size = height*(*stride);
3505  size = FFALIGN(size, p->props.properties.limits.minMemoryMapAlignment);
3506  return size;
3507 }
3508 
3510  VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags,
3511  size_t size, uint32_t req_memory_bits, int host_mapped,
3512  void *create_pnext, void *alloc_pnext)
3513 {
3514  int err;
3515  VkResult ret;
3516  int use_ded_mem;
3517  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3518  VulkanDevicePriv *p = ctx->internal->priv;
3519  FFVulkanFunctions *vk = &p->vkfn;
3520 
3521  VkBufferCreateInfo buf_spawn = {
3522  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
3523  .pNext = create_pnext,
3524  .usage = usage,
3525  .size = size,
3526  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
3527  };
3528 
3529  VkBufferMemoryRequirementsInfo2 req_desc = {
3530  .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
3531  };
3532  VkMemoryDedicatedAllocateInfo ded_alloc = {
3533  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
3534  .pNext = alloc_pnext,
3535  };
3536  VkMemoryDedicatedRequirements ded_req = {
3537  .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
3538  };
3539  VkMemoryRequirements2 req = {
3540  .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
3541  .pNext = &ded_req,
3542  };
3543 
3544  ImageBuffer *vkbuf = av_mallocz(sizeof(*vkbuf));
3545  if (!vkbuf)
3546  return AVERROR(ENOMEM);
3547 
3548  vkbuf->mapped_mem = host_mapped;
3549 
3550  ret = vk->CreateBuffer(hwctx->act_dev, &buf_spawn, NULL, &vkbuf->buf);
3551  if (ret != VK_SUCCESS) {
3552  av_log(ctx, AV_LOG_ERROR, "Failed to create buffer: %s\n",
3553  vk_ret2str(ret));
3554  err = AVERROR_EXTERNAL;
3555  goto fail;
3556  }
3557 
3558  req_desc.buffer = vkbuf->buf;
3559 
3560  vk->GetBufferMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
3561 
3562  /* In case the implementation prefers/requires dedicated allocation */
3563  use_ded_mem = ded_req.prefersDedicatedAllocation |
3564  ded_req.requiresDedicatedAllocation;
3565  if (use_ded_mem)
3566  ded_alloc.buffer = vkbuf->buf;
3567 
3568  /* Additional requirements imposed on us */
3569  if (req_memory_bits)
3570  req.memoryRequirements.memoryTypeBits &= req_memory_bits;
3571 
3572  err = alloc_mem(ctx, &req.memoryRequirements, flags,
3573  use_ded_mem ? &ded_alloc : (void *)ded_alloc.pNext,
3574  &vkbuf->flags, &vkbuf->mem);
3575  if (err)
3576  goto fail;
3577 
3578  ret = vk->BindBufferMemory(hwctx->act_dev, vkbuf->buf, vkbuf->mem, 0);
3579  if (ret != VK_SUCCESS) {
3580  av_log(ctx, AV_LOG_ERROR, "Failed to bind memory to buffer: %s\n",
3581  vk_ret2str(ret));
3582  err = AVERROR_EXTERNAL;
3583  goto fail;
3584  }
3585 
3586  *buf = av_buffer_create((uint8_t *)vkbuf, sizeof(*vkbuf), free_buf, ctx, 0);
3587  if (!(*buf)) {
3588  err = AVERROR(ENOMEM);
3589  goto fail;
3590  }
3591 
3592  return 0;
3593 
3594 fail:
3595  free_buf(ctx, (uint8_t *)vkbuf);
3596  return err;
3597 }
3598 
3599 /* Skips mapping of host mapped buffers but still invalidates them */
3600 static int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[],
3601  int nb_buffers, int invalidate)
3602 {
3603  VkResult ret;
3604  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3605  VulkanDevicePriv *p = ctx->internal->priv;
3606  FFVulkanFunctions *vk = &p->vkfn;
3607  VkMappedMemoryRange invalidate_ctx[AV_NUM_DATA_POINTERS];
3608  int invalidate_count = 0;
3609 
3610  for (int i = 0; i < nb_buffers; i++) {
3611  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3612  if (vkbuf->mapped_mem)
3613  continue;
3614 
3615  ret = vk->MapMemory(hwctx->act_dev, vkbuf->mem, 0,
3616  VK_WHOLE_SIZE, 0, (void **)&mem[i]);
3617  if (ret != VK_SUCCESS) {
3618  av_log(ctx, AV_LOG_ERROR, "Failed to map buffer memory: %s\n",
3619  vk_ret2str(ret));
3620  return AVERROR_EXTERNAL;
3621  }
3622  }
3623 
3624  if (!invalidate)
3625  return 0;
3626 
3627  for (int i = 0; i < nb_buffers; i++) {
3628  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3629  const VkMappedMemoryRange ival_buf = {
3630  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3631  .memory = vkbuf->mem,
3632  .size = VK_WHOLE_SIZE,
3633  };
3634 
3635  /* For host imported memory Vulkan says to use platform-defined
3636  * sync methods, but doesn't really say not to call flush or invalidate
3637  * on original host pointers. It does explicitly allow to do that on
3638  * host-mapped pointers which are then mapped again using vkMapMemory,
3639  * but known implementations return the original pointers when mapped
3640  * again. */
3641  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
3642  continue;
3643 
3644  invalidate_ctx[invalidate_count++] = ival_buf;
3645  }
3646 
3647  if (invalidate_count) {
3648  ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, invalidate_count,
3649  invalidate_ctx);
3650  if (ret != VK_SUCCESS)
3651  av_log(ctx, AV_LOG_WARNING, "Failed to invalidate memory: %s\n",
3652  vk_ret2str(ret));
3653  }
3654 
3655  return 0;
3656 }
3657 
3659  int nb_buffers, int flush)
3660 {
3661  int err = 0;
3662  VkResult ret;
3663  AVVulkanDeviceContext *hwctx = ctx->hwctx;
3664  VulkanDevicePriv *p = ctx->internal->priv;
3665  FFVulkanFunctions *vk = &p->vkfn;
3666  VkMappedMemoryRange flush_ctx[AV_NUM_DATA_POINTERS];
3667  int flush_count = 0;
3668 
3669  if (flush) {
3670  for (int i = 0; i < nb_buffers; i++) {
3671  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3672  const VkMappedMemoryRange flush_buf = {
3673  .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3674  .memory = vkbuf->mem,
3675  .size = VK_WHOLE_SIZE,
3676  };
3677 
3678  if (vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
3679  continue;
3680 
3681  flush_ctx[flush_count++] = flush_buf;
3682  }
3683  }
3684 
3685  if (flush_count) {
3686  ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, flush_count, flush_ctx);
3687  if (ret != VK_SUCCESS) {
3688  av_log(ctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
3689  vk_ret2str(ret));
3690  err = AVERROR_EXTERNAL; /* We still want to try to unmap them */
3691  }
3692  }
3693 
3694  for (int i = 0; i < nb_buffers; i++) {
3695  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3696  if (vkbuf->mapped_mem)
3697  continue;
3698 
3699  vk->UnmapMemory(hwctx->act_dev, vkbuf->mem);
3700  }
3701 
3702  return err;
3703 }
3704 
3706  AVBufferRef **bufs, size_t *buf_offsets,
3707  const int *buf_stride, int w,
3708  int h, enum AVPixelFormat pix_fmt, int to_buf)
3709 {
3710  int err;
3711  AVVkFrame *frame = (AVVkFrame *)f->data[0];
3712  VulkanFramesPriv *fp = hwfc->internal->priv;
3714  FFVulkanFunctions *vk = &p->vkfn;
3715 
3716  int bar_num = 0;
3717  VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS];
3718 
3719  const int planes = av_pix_fmt_count_planes(pix_fmt);
3721 
3722  VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 };
3723  VulkanExecCtx *ectx = to_buf ? &fp->download_ctx : &fp->upload_ctx;
3724  VkCommandBuffer cmd_buf = get_buf_exec_ctx(hwfc, ectx);
3725 
3726  uint64_t sem_signal_values[AV_NUM_DATA_POINTERS];
3727 
3728  VkTimelineSemaphoreSubmitInfo s_timeline_sem_info = {
3729  .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
3730  .pWaitSemaphoreValues = frame->sem_value,
3731  .pSignalSemaphoreValues = sem_signal_values,
3732  .waitSemaphoreValueCount = planes,
3733  .signalSemaphoreValueCount = planes,
3734  };
3735 
3736  VkSubmitInfo s_info = {
3737  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3738  .pNext = &s_timeline_sem_info,
3739  .pSignalSemaphores = frame->sem,
3740  .pWaitSemaphores = frame->sem,
3741  .pWaitDstStageMask = sem_wait_dst,
3742  .signalSemaphoreCount = planes,
3743  .waitSemaphoreCount = planes,
3744  };
3745 
3746  for (int i = 0; i < planes; i++)
3747  sem_signal_values[i] = frame->sem_value[i] + 1;
3748 
3749  if ((err = wait_start_exec_ctx(hwfc, ectx)))
3750  return err;
3751 
3752  /* Change the image layout to something more optimal for transfers */
3753  for (int i = 0; i < planes; i++) {
3754  VkImageLayout new_layout = to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL :
3755  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3756  VkAccessFlags new_access = to_buf ? VK_ACCESS_TRANSFER_READ_BIT :
3757  VK_ACCESS_TRANSFER_WRITE_BIT;
3758 
3759  sem_wait_dst[i] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3760 
3761  /* If the layout matches and we have read access skip the barrier */
3762  if ((frame->layout[i] == new_layout) && (frame->access[i] & new_access))
3763  continue;
3764 
3765  img_bar[bar_num].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3766  img_bar[bar_num].srcAccessMask = 0x0;
3767  img_bar[bar_num].dstAccessMask = new_access;
3768  img_bar[bar_num].oldLayout = frame->layout[i];
3769  img_bar[bar_num].newLayout = new_layout;
3770  img_bar[bar_num].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3771  img_bar[bar_num].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3772  img_bar[bar_num].image = frame->img[i];
3773  img_bar[bar_num].subresourceRange.levelCount = 1;
3774  img_bar[bar_num].subresourceRange.layerCount = 1;
3775  img_bar[bar_num].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3776 
3777  frame->layout[i] = img_bar[bar_num].newLayout;
3778  frame->access[i] = img_bar[bar_num].dstAccessMask;
3779 
3780  bar_num++;
3781  }
3782 
3783  if (bar_num)
3784  vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3785  VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
3786  0, NULL, 0, NULL, bar_num, img_bar);
3787 
3788  /* Schedule a copy for each plane */
3789  for (int i = 0; i < planes; i++) {
3790  ImageBuffer *vkbuf = (ImageBuffer *)bufs[i]->data;
3791  VkBufferImageCopy buf_reg = {
3792  .bufferOffset = buf_offsets[i],
3793  .bufferRowLength = buf_stride[i] / desc->comp[i].step,
3794  .imageSubresource.layerCount = 1,
3795  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3796  .imageOffset = { 0, 0, 0, },
3797  };
3798 
3799  int p_w, p_h;
3800  get_plane_wh(&p_w, &p_h, pix_fmt, w, h, i);
3801 
3802  buf_reg.bufferImageHeight = p_h;
3803  buf_reg.imageExtent = (VkExtent3D){ p_w, p_h, 1, };
3804 
3805  if (to_buf)
3806  vk->CmdCopyImageToBuffer(cmd_buf, frame->img[i], frame->layout[i],
3807  vkbuf->buf, 1, &buf_reg);
3808  else
3809  vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[i],
3810  frame->layout[i], 1, &buf_reg);
3811  }
3812 
3813  /* When uploading, do this asynchronously if the source is refcounted by
3814  * keeping the buffers as a submission dependency.
3815  * The hwcontext is guaranteed to not be freed until all frames are freed
3816  * in the frames_unint function.
3817  * When downloading to buffer, do this synchronously and wait for the
3818  * queue submission to finish executing */
3819  if (!to_buf) {
3820  int ref;
3821  for (ref = 0; ref < AV_NUM_DATA_POINTERS; ref++) {
3822  if (!f->buf[ref])
3823  break;
3824  if ((err = add_buf_dep_exec_ctx(hwfc, ectx, &f->buf[ref], 1)))
3825  return err;
3826  }
3827  if (ref && (err = add_buf_dep_exec_ctx(hwfc, ectx, bufs, planes)))
3828  return err;
3829  return submit_exec_ctx(hwfc, ectx, &s_info, frame, !ref);
3830  } else {
3831  return submit_exec_ctx(hwfc, ectx, &s_info, frame, 1);
3832  }
3833 }
3834 
3835 static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf,
3836  const AVFrame *swf, int from)
3837 {
3838  int err = 0;
3839  VkResult ret;
3840  AVVkFrame *f = (AVVkFrame *)vkf->data[0];
3841  AVHWDeviceContext *dev_ctx = hwfc->device_ctx;
3842  AVVulkanDeviceContext *hwctx = dev_ctx->hwctx;
3844  FFVulkanFunctions *vk = &p->vkfn;
3845 
3846  AVFrame tmp;
3847  AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 };
3848  size_t buf_offsets[AV_NUM_DATA_POINTERS] = { 0 };
3849 
3850  int p_w, p_h;
3851  const int planes = av_pix_fmt_count_planes(swf->format);
3852 
3853  int host_mapped[AV_NUM_DATA_POINTERS] = { 0 };
3854  const int map_host = !!(p->extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY);
3855 
3856  if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) {
3857  av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n");
3858  return AVERROR(EINVAL);
3859  }
3860 
3861  if (swf->width > hwfc->width || swf->height > hwfc->height)
3862  return AVERROR(EINVAL);
3863 
3864  /* For linear, host visiable images */
3865  if (f->tiling == VK_IMAGE_TILING_LINEAR &&
3866  f->flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
3867  AVFrame *map = av_frame_alloc();
3868  if (!map)
3869  return AVERROR(ENOMEM);
3870  map->format = swf->format;
3871 
3873  if (err)
3874  return err;
3875 
3876  err = av_frame_copy((AVFrame *)(from ? swf : map), from ? map : swf);
3877  av_frame_free(&map);
3878  return err;
3879  }
3880 
3881  /* Create buffers */
3882  for (int i = 0; i < planes; i++) {
3883  size_t req_size;
3884 
3885  VkExternalMemoryBufferCreateInfo create_desc = {
3886  .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
3887  .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3888  };
3889 
3890  VkImportMemoryHostPointerInfoEXT import_desc = {
3891  .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
3892  .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
3893  };
3894 
3895  VkMemoryHostPointerPropertiesEXT p_props = {
3896  .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
3897  };
3898 
3899  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3900 
3901  tmp.linesize[i] = FFABS(swf->linesize[i]);
3902 
3903  /* Do not map images with a negative stride */
3904  if (map_host && swf->linesize[i] > 0) {
3905  size_t offs;
3906  offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment;
3907  import_desc.pHostPointer = swf->data[i] - offs;
3908 
3909  /* We have to compensate for the few extra bytes of padding we
3910  * completely ignore at the start */
3911  req_size = FFALIGN(offs + tmp.linesize[i] * p_h,
3912  p->hprops.minImportedHostPointerAlignment);
3913 
3914  ret = vk->GetMemoryHostPointerPropertiesEXT(hwctx->act_dev,
3915  import_desc.handleType,
3916  import_desc.pHostPointer,
3917  &p_props);
3918 
3919  if (ret == VK_SUCCESS) {
3920  host_mapped[i] = 1;
3921  buf_offsets[i] = offs;
3922  }
3923  }
3924 
3925  if (!host_mapped[i])
3926  req_size = get_req_buffer_size(p, &tmp.linesize[i], p_h);
3927 
3928  err = create_buf(dev_ctx, &bufs[i],
3929  from ? VK_BUFFER_USAGE_TRANSFER_DST_BIT :
3930  VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
3931  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
3932  req_size, p_props.memoryTypeBits, host_mapped[i],
3933  host_mapped[i] ? &create_desc : NULL,
3934  host_mapped[i] ? &import_desc : NULL);
3935  if (err)
3936  goto end;
3937  }
3938 
3939  if (!from) {
3940  /* Map, copy image TO buffer (which then goes to the VkImage), unmap */
3941  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3942  goto end;
3943 
3944  for (int i = 0; i < planes; i++) {
3945  if (host_mapped[i])
3946  continue;
3947 
3948  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3949 
3950  av_image_copy_plane(tmp.data[i], tmp.linesize[i],
3951  (const uint8_t *)swf->data[i], swf->linesize[i],
3952  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3953  p_h);
3954  }
3955 
3956  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3957  goto end;
3958  }
3959 
3960  /* Copy buffers into/from image */
3961  err = transfer_image_buf(hwfc, vkf, bufs, buf_offsets, tmp.linesize,
3962  swf->width, swf->height, swf->format, from);
3963 
3964  if (from) {
3965  /* Map, copy buffer (which came FROM the VkImage) to the frame, unmap */
3966  if ((err = map_buffers(dev_ctx, bufs, tmp.data, planes, 0)))
3967  goto end;
3968 
3969  for (int i = 0; i < planes; i++) {
3970  if (host_mapped[i])
3971  continue;
3972 
3973  get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
3974 
3975  av_image_copy_plane_uc_from(swf->data[i], swf->linesize[i],
3976  (const uint8_t *)tmp.data[i], tmp.linesize[i],
3977  FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])),
3978  p_h);
3979  }
3980 
3981  if ((err = unmap_buffers(dev_ctx, bufs, planes, 1)))
3982  goto end;
3983  }
3984 
3985 end:
3986  for (int i = 0; i < planes; i++)
3987  av_buffer_unref(&bufs[i]);
3988 
3989  return err;
3990 }
3991 
3993  const AVFrame *src)
3994 {
3996 
3997  switch (src->format) {
3998 #if CONFIG_CUDA
3999  case AV_PIX_FMT_CUDA:
4000 #ifdef _WIN32
4001  if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4002  (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4003 #else
4004  if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4005  (p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4006 #endif
4007  return vulkan_transfer_data_from_cuda(hwfc, dst, src);
4008 #endif
4009  default:
4010  if (src->hw_frames_ctx)
4011  return AVERROR(ENOSYS);
4012  else
4013  return vulkan_transfer_data(hwfc, dst, src, 0);
4014  }
4015 }
4016 
4017 #if CONFIG_CUDA
4018 static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
4019  const AVFrame *src)
4020 {
4021  int err;
4022  CUcontext dummy;
4023  AVVkFrame *dst_f;
4024  AVVkFrameInternal *dst_int;
4025  VulkanFramesPriv *fp = hwfc->internal->priv;
4026  const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
4028 
4030  AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
4031  AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
4032  AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
4033  CudaFunctions *cu = cu_internal->cuda_dl;
4034  CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS s_w_par[AV_NUM_DATA_POINTERS] = { 0 };
4035  CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS s_s_par[AV_NUM_DATA_POINTERS] = { 0 };
4036 
4037  dst_f = (AVVkFrame *)src->data[0];
4038 
4039  err = prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_EXPORT);
4040  if (err < 0)
4041  return err;
4042 
4043  err = CHECK_CU(cu->cuCtxPushCurrent(cuda_dev->cuda_ctx));
4044  if (err < 0)
4045  return err;
4046 
4047  err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
4048  if (err < 0) {
4049  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4050  return err;
4051  }
4052 
4053  dst_int = dst_f->internal;
4054 
4055  for (int i = 0; i < planes; i++) {
4056  s_w_par[i].params.fence.value = dst_f->sem_value[i] + 0;
4057  s_s_par[i].params.fence.value = dst_f->sem_value[i] + 1;
4058  }
4059 
4060  err = CHECK_CU(cu->cuWaitExternalSemaphoresAsync(dst_int->cu_sem, s_w_par,
4061  planes, cuda_dev->stream));
4062  if (err < 0)
4063  goto fail;
4064 
4065  for (int i = 0; i < planes; i++) {
4066  CUDA_MEMCPY2D cpy = {
4067  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
4068  .dstDevice = (CUdeviceptr)dst->data[i],
4069  .dstPitch = dst->linesize[i],
4070  .dstY = 0,
4071 
4072  .srcMemoryType = CU_MEMORYTYPE_ARRAY,
4073  .srcArray = dst_int->cu_array[i],
4074  };
4075 
4076  int w, h;
4077  get_plane_wh(&w, &h, hwfc->sw_format, hwfc->width, hwfc->height, i);
4078 
4079  cpy.WidthInBytes = w * desc->comp[i].step;
4080  cpy.Height = h;
4081 
4082  err = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, cuda_dev->stream));
4083  if (err < 0)
4084  goto fail;
4085  }
4086 
4087  err = CHECK_CU(cu->cuSignalExternalSemaphoresAsync(dst_int->cu_sem, s_s_par,
4088  planes, cuda_dev->stream));
4089  if (err < 0)
4090  goto fail;
4091 
4092  for (int i = 0; i < planes; i++)
4093  dst_f->sem_value[i]++;
4094 
4095  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4096 
4097  av_log(hwfc, AV_LOG_VERBOSE, "Transfered Vulkan image to CUDA!\n");
4098 
4099  return prepare_frame(hwfc, &fp->upload_ctx, dst_f, PREP_MODE_EXTERNAL_IMPORT);
4100 
4101 fail:
4102  CHECK_CU(cu->cuCtxPopCurrent(&dummy));
4103  vulkan_free_internal(dst_f);
4104  dst_f->internal = NULL;
4105  av_buffer_unref(&dst->buf[0]);
4106  return err;
4107 }
4108 #endif
4109 
4111  const AVFrame *src)
4112 {
4114 
4115  switch (dst->format) {
4116 #if CONFIG_CUDA
4117  case AV_PIX_FMT_CUDA:
4118 #ifdef _WIN32
4119  if ((p->extensions & FF_VK_EXT_EXTERNAL_WIN32_MEMORY) &&
4120  (p->extensions & FF_VK_EXT_EXTERNAL_WIN32_SEM))
4121 #else
4122  if ((p->extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
4123  (p->extensions & FF_VK_EXT_EXTERNAL_FD_SEM))
4124 #endif
4125  return vulkan_transfer_data_to_cuda(hwfc, dst, src);
4126 #endif
4127  default:
4128  if (dst->hw_frames_ctx)
4129  return AVERROR(ENOSYS);
4130  else
4131  return vulkan_transfer_data(hwfc, src, dst, 1);
4132  }
4133 }
4134 
4136  AVHWFramesContext *src_fc, int flags)
4137 {
4138  return vulkan_frames_init(dst_fc);
4139 }
4140 
4142 {
4143  return av_mallocz(sizeof(AVVkFrame));
4144 }
4145 
4148  .name = "Vulkan",
4149 
4150  .device_hwctx_size = sizeof(AVVulkanDeviceContext),
4151  .device_priv_size = sizeof(VulkanDevicePriv),
4152  .frames_hwctx_size = sizeof(AVVulkanFramesContext),
4153  .frames_priv_size = sizeof(VulkanFramesPriv),
4154 
4155  .device_init = &vulkan_device_init,
4156  .device_create = &vulkan_device_create,
4157  .device_derive = &vulkan_device_derive,
4158 
4159  .frames_get_constraints = &vulkan_frames_get_constraints,
4160  .frames_init = vulkan_frames_init,
4161  .frames_get_buffer = vulkan_get_buffer,
4162  .frames_uninit = vulkan_frames_uninit,
4163 
4164  .transfer_get_formats = vulkan_transfer_get_formats,
4165  .transfer_data_to = vulkan_transfer_data_to,
4166  .transfer_data_from = vulkan_transfer_data_from,
4167 
4168  .map_to = vulkan_map_to,
4169  .map_from = vulkan_map_from,
4170  .frames_derive_to = &vulkan_frames_derive_to,
4171 
4172  .pix_fmts = (const enum AVPixelFormat []) {
4175  },
4176 };
vulkan_loader.h
FF_VK_EXT_NO_FLAG
@ FF_VK_EXT_NO_FLAG
Definition: vulkan_functions.h:41
VulkanDevicePriv::extensions
FFVulkanExtensions extensions
Definition: hwcontext_vulkan.c:101
formats
formats
Definition: signature.h:48
AV_PIX_FMT_YUVA422P16
#define AV_PIX_FMT_YUVA422P16
Definition: pixfmt.h:502
load_libvulkan
static int load_libvulkan(AVHWDeviceContext *ctx)
Definition: hwcontext_vulkan.c:302
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
vulkan_device_init
static int vulkan_device_init(AVHWDeviceContext *ctx)
Definition: hwcontext_vulkan.c:1437
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:481
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVVulkanDeviceContext::phys_dev
VkPhysicalDevice phys_dev
Physical device.
Definition: hwcontext_vulkan.h:63
check_validation_layers
static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts, const char *const **dst, uint32_t *num, int *debug_mode)
Definition: hwcontext_vulkan.c:564
AV_PIX_FMT_CUDA
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition: pixfmt.h:253
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
VulkanDevicePriv::libvulkan
void * libvulkan
Definition: hwcontext_vulkan.c:81
VulkanOptExtension::name
const char * name
Definition: hwcontext_vulkan.c:337
VulkanDevicePriv::qfs
uint32_t qfs[5]
Definition: hwcontext_vulkan.c:94
AVCUDADeviceContextInternal
Definition: hwcontext_cuda_internal.h:31
VulkanDevicePriv::num_qfs
int num_qfs
Definition: hwcontext_vulkan.c:95
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
VulkanQueueCtx::nb_buf_deps
int nb_buf_deps
Definition: hwcontext_vulkan.c:67
VulkanMapping::flags
int flags
Definition: hwcontext_vulkan.c:2456
SETUP_QUEUE
#define SETUP_QUEUE(qf_idx)
hwcontext_cuda_internal.h
out
FILE * out
Definition: movenc.c:54
vk_link_struct
static void vk_link_struct(void *chain, void *in)
Definition: hwcontext_vulkan.c:263
AV_PIX_FMT_BGR32
#define AV_PIX_FMT_BGR32
Definition: pixfmt.h:434
vulkan_transfer_data_to
static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_vulkan.c:3992
sub
static float sub(float src0, float src1)
Definition: dnn_backend_native_layer_mathbinary.c:31
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2858
CHECK_QUEUE
#define CHECK_QUEUE(type, required, fidx, ctx_qf, qc)
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
vulkan_frames_get_constraints
static int vulkan_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
Definition: hwcontext_vulkan.c:1625
vulkan_transfer_data
static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, const AVFrame *swf, int from)
Definition: hwcontext_vulkan.c:3835
av_unused
#define av_unused
Definition: attributes.h:131
vulkan_frames_derive_to
static int vulkan_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags)
Definition: hwcontext_vulkan.c:4135
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:116
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
pixdesc.h
AVVulkanDeviceContext::get_proc_addr
PFN_vkGetInstanceProcAddr get_proc_addr
Pointer to the instance-provided vkGetInstanceProcAddr loading function.
Definition: hwcontext_vulkan.h:53
optional_device_exts
static const VulkanOptExtension optional_device_exts[]
Definition: hwcontext_vulkan.c:345
VulkanFramesPriv::download_ctx
VulkanExecCtx download_ctx
Definition: hwcontext_vulkan.c:122
AVFrame::width
int width
Definition: frame.h:397
AV_PIX_FMT_YUVA420P16
#define AV_PIX_FMT_YUVA420P16
Definition: pixfmt.h:501
w
uint8_t w
Definition: llviddspenc.c:38
VulkanQueueCtx::fence
VkFence fence
Definition: hwcontext_vulkan.c:61
AVDRMFrameDescriptor::nb_layers
int nb_layers
Number of layers in the frame.
Definition: hwcontext_drm.h:145
AV_PIX_FMT_DRM_PRIME
@ AV_PIX_FMT_DRM_PRIME
DRM-managed buffers exposed through PRIME buffer sharing.
Definition: pixfmt.h:348
AV_DRM_MAX_PLANES
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
Definition: hwcontext_drm.h:39
AV_PIX_FMT_YUVA420P10
#define AV_PIX_FMT_YUVA420P10
Definition: pixfmt.h:496
AVVulkanFramesContext::create_pnext
void * create_pnext
Extension data for image creation.
Definition: hwcontext_vulkan.h:181
av_hwframe_map
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:794
data
const char data[16]
Definition: mxf.c:146
linear
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:132
VulkanDevicePriv::vkfn
FFVulkanFunctions vkfn
Definition: hwcontext_vulkan.c:82
AVVulkanDeviceContext::queue_family_decode_index
int queue_family_decode_index
Queue family index for video decode ops, and the amount of queues enabled.
Definition: hwcontext_vulkan.h:136
try_export_flags
static void try_export_flags(AVHWFramesContext *hwfc, VkExternalMemoryHandleTypeFlags *comp_handle_types, VkExternalMemoryHandleTypeFlagBits *iexp, VkExternalMemoryHandleTypeFlagBits exp)
Definition: hwcontext_vulkan.c:2135
AV_PIX_FMT_YUV420P10
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:459
AVVulkanDeviceContext::inst
VkInstance inst
Vulkan instance.
Definition: hwcontext_vulkan.h:58
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
free_exec_ctx
static void free_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
Definition: hwcontext_vulkan.c:1126
vk_pixfmt_map
static const struct @333 vk_pixfmt_map[]
AVVAAPIDeviceContext::display
VADisplay display
The VADisplay handle, to be filled by the user.
Definition: hwcontext_vaapi.h:72
vulkan_map_from
static int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
Definition: hwcontext_vulkan.c:3452
AVHWDeviceContext::internal
AVHWDeviceInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:71
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
AVHWFramesContext::internal
AVHWFramesInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:134
AVDictionary
Definition: dict.c:32
ff_hwframe_map_create
int ff_hwframe_map_create(AVBufferRef *hwframe_ref, AVFrame *dst, const AVFrame *src, void(*unmap)(AVHWFramesContext *ctx, HWMapDescriptor *hwmap), void *priv)
Definition: hwcontext.c:742
VulkanExecCtx::cur_queue_idx
int cur_queue_idx
Definition: hwcontext_vulkan.c:76
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
HWMapDescriptor::priv
void * priv
Hardware-specific private data associated with the mapping.
Definition: hwcontext_internal.h:151
av_popcount
#define av_popcount
Definition: common.h:149
AVDRMFrameDescriptor
DRM frame descriptor.
Definition: hwcontext_drm.h:133
AVHWFramesConstraints::valid_hw_formats
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
VulkanExecCtx::queues
VulkanQueueCtx * queues
Definition: hwcontext_vulkan.c:74
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
AVFrame::buf
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:525
AV_PIX_FMT_YUVA422P10
#define AV_PIX_FMT_YUVA422P10
Definition: pixfmt.h:497
AVVulkanDeviceContext::nb_decode_queues
int nb_decode_queues
Definition: hwcontext_vulkan.h:137
AV_HWFRAME_MAP_OVERWRITE
@ AV_HWFRAME_MAP_OVERWRITE
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:534
prepare_frame
static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, AVVkFrame *frame, enum PrepMode pmode)
Definition: hwcontext_vulkan.c:1917
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:376
VulkanDeviceSelection::uuid
uint8_t uuid[VK_UUID_SIZE]
Definition: hwcontext_vulkan.c:762
AVVulkanDeviceContext::queue_family_index
int queue_family_index
Queue family index for graphics operations, and the number of queues enabled for it.
Definition: hwcontext_vulkan.h:106
AVHWFramesInternal::pool_internal
AVBufferPool * pool_internal
Definition: hwcontext_internal.h:118
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:346
AV_HWFRAME_MAP_WRITE
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition: hwcontext.h:528
av_image_copy_plane
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:374
VulkanExecCtx::bufs
VkCommandBuffer * bufs
Definition: hwcontext_vulkan.c:73
alloc_mem
static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req, VkMemoryPropertyFlagBits req_flags, const void *alloc_extension, VkMemoryPropertyFlagBits *mem_flags, VkDeviceMemory *mem)
Definition: hwcontext_vulkan.c:1671
AV_HWDEVICE_TYPE_VULKAN
@ AV_HWDEVICE_TYPE_VULKAN
Definition: hwcontext.h:39
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:453
AV_PIX_FMT_NB
@ 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:423
AV_HWDEVICE_TYPE_CUDA
@ AV_HWDEVICE_TYPE_CUDA
Definition: hwcontext.h:30
AVDRMDeviceContext::fd
int fd
File descriptor of DRM device.
Definition: hwcontext_drm.h:166
VulkanExecCtx::pool
VkCommandPool pool
Definition: hwcontext_vulkan.c:72
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2898
VulkanDevicePriv::hprops
VkPhysicalDeviceExternalMemoryHostPropertiesEXT hprops
Definition: hwcontext_vulkan.c:87
vulkan_device_derive
static int vulkan_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:1554
VulkanOptExtension::flag
FFVulkanExtensions flag
Definition: hwcontext_vulkan.c:338
VulkanExecCtx::nb_queues
int nb_queues
Definition: hwcontext_vulkan.c:75
AVVulkanDeviceContext::alloc
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
Definition: hwcontext_vulkan.h:46
AVHWFramesInternal::priv
void * priv
Definition: hwcontext_internal.h:116
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:205
AVVulkanDeviceContext::queue_family_comp_index
int queue_family_comp_index
Queue family index for compute operations and the number of queues enabled.
Definition: hwcontext_vulkan.h:120
fail
#define fail()
Definition: checkasm.h:134
AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
@ AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY
Definition: hwcontext_vulkan.h:151
AVDRMLayerDescriptor::nb_planes
int nb_planes
Number of planes in the layer.
Definition: hwcontext_drm.h:106
AV_HWFRAME_MAP_READ
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition: hwcontext.h:524
AV_PIX_FMT_YUVA444P16
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:503
AVVulkanFramesContext::flags
AVVkFrameFlags flags
A combination of AVVkFrameFlags.
Definition: hwcontext_vulkan.h:197
VulkanDevicePriv
Definition: hwcontext_vulkan.c:79
AVDRMLayerDescriptor::planes
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
Definition: hwcontext_drm.h:110
FF_VK_DEFAULT_USAGE_FLAGS
#define FF_VK_DEFAULT_USAGE_FLAGS
Definition: vulkan.h:29
dummy
int dummy
Definition: motion.c:65
AVVkFrame::mem
VkDeviceMemory mem[AV_NUM_DATA_POINTERS]
Memory backing the images.
Definition: hwcontext_vulkan.h:229
ImageBuffer::flags
VkMemoryPropertyFlagBits flags
Definition: hwcontext_vulkan.c:3480
ImageBuffer::buf
VkBuffer buf
Definition: hwcontext_vulkan.c:3478
AVVulkanFramesContext
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
Definition: hwcontext_vulkan.h:157
av_buffer_pool_init2
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:259
AVHWFramesConstraints::min_width
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:471
vulkan_map_frame_to_mem
static int vulkan_map_frame_to_mem(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
Definition: hwcontext_vulkan.c:2493
AVCUDADeviceContextInternal::cuda_device
CUdevice cuda_device
Definition: hwcontext_cuda_internal.h:34
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
cqueue_create
static cqueue * cqueue_create(int size, int max_size)
Definition: af_dynaudnorm.c:179
vulkan_frame_free
static void vulkan_frame_free(void *opaque, uint8_t *data)
Definition: hwcontext_vulkan.c:1767
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:443
VulkanDevicePriv::device_features_1_1
VkPhysicalDeviceVulkan11Features device_features_1_1
Definition: hwcontext_vulkan.c:90
VulkanDevicePriv::props
VkPhysicalDeviceProperties2 props
Definition: hwcontext_vulkan.c:85
AVDRMPlaneDescriptor::offset
ptrdiff_t offset
Offset within that object of this plane.
Definition: hwcontext_drm.h:83
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:104
AV_PIX_FMT_YUV444P10
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:462
wait_start_exec_ctx
static int wait_start_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
Definition: hwcontext_vulkan.c:1177
submit_exec_ctx
static int submit_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, VkSubmitInfo *s_info, AVVkFrame *f, int synchronous)
Definition: hwcontext_vulkan.c:1250
avassert.h
HWContextType::type
enum AVHWDeviceType type
Definition: hwcontext_internal.h:30
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
AV_PIX_FMT_YUV422P16
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:471
AV_VK_FRAME_FLAG_NONE
@ AV_VK_FRAME_FLAG_NONE
Definition: hwcontext_vulkan.h:146
AVHWFramesContext::height
int height
Definition: hwcontext.h:229
AVHWFramesConstraints::valid_sw_formats
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
AVVulkanDeviceContext::nb_graphics_queues
int nb_graphics_queues
Definition: hwcontext_vulkan.h:107
vulkan_map_to
static int vulkan_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
Definition: hwcontext_vulkan.c:3265
av_dict_get
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:60
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:384
AVHWFramesContext::pool
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:190
av_fast_realloc
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:505
VulkanDeviceSelection::pci_device
uint32_t pci_device
Definition: hwcontext_vulkan.c:765
AV_PIX_FMT_YUVA420P
@ 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_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:472
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:50
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
ff_vk_load_functions
static int ff_vk_load_functions(AVHWDeviceContext *ctx, FFVulkanFunctions *vk, uint64_t extensions_mask, int has_inst, int has_dev)
Function loader.
Definition: vulkan_loader.h:80
AV_PIX_FMT_0BGR32
#define AV_PIX_FMT_0BGR32
Definition: pixfmt.h:437
av_strtok
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:189
VulkanQueueCtx
Definition: hwcontext_vulkan.c:60
from
const char * from
Definition: jacosubdec.c:66
FF_VK_EXT_EXTERNAL_HOST_MEMORY
@ FF_VK_EXT_EXTERNAL_HOST_MEMORY
Definition: vulkan_functions.h:34
AV_PIX_FMT_YUVA444P12
#define AV_PIX_FMT_YUVA444P12
Definition: pixfmt.h:500
pixfmt_is_supported
static int pixfmt_is_supported(AVHWDeviceContext *dev_ctx, enum AVPixelFormat p, int linear)
Definition: hwcontext_vulkan.c:275
vulkan_frames_uninit
static void vulkan_frames_uninit(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:2260
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
AV_PIX_FMT_YUV420P16
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:470
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AVDRMObjectDescriptor::fd
int fd
DRM PRIME fd for the object.
Definition: hwcontext_drm.h:52
check_extensions
static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, const char *const **dst, uint32_t *num, int debug)
Definition: hwcontext_vulkan.c:435
VulkanDeviceSelection::index
int index
Definition: hwcontext_vulkan.c:767
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demuxing_decoding.c:41
vulkan_transfer_get_formats
static int vulkan_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
Definition: hwcontext_vulkan.c:2439
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
planes
static const struct @345 planes[]
AV_PIX_FMT_GRAYF32
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:491
LIBAVUTIL_VERSION_MINOR
#define LIBAVUTIL_VERSION_MINOR
Definition: version.h:82
ImageBuffer::mem
VkDeviceMemory mem
Definition: hwcontext_vulkan.c:3479
get_req_buffer_size
static size_t get_req_buffer_size(VulkanDevicePriv *p, int *stride, int height)
Definition: hwcontext_vulkan.c:3500
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:64
VulkanFramesPriv::conv_ctx
VulkanExecCtx conv_ctx
Definition: hwcontext_vulkan.c:118
if
if(ret)
Definition: filter_design.txt:179
av_vkfmt_from_pixfmt
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.
Definition: hwcontext_vulkan.c:242
AVVulkanDeviceContext
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_vulkan.h:42
opts
AVDictionary * opts
Definition: movenc.c:50
PREP_MODE_WRITE
@ PREP_MODE_WRITE
Definition: hwcontext_vulkan.c:1912
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:449
pick_queue_family
static int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf, VkQueueFlagBits flags)
Definition: hwcontext_vulkan.c:911
NULL
#define NULL
Definition: coverity.c:32
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
av_buffer_unref
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:139
AVVulkanDeviceContext::nb_enabled_dev_extensions
int nb_enabled_dev_extensions
Definition: hwcontext_vulkan.h:97
AVHWDeviceInternal::priv
void * priv
Definition: hwcontext_internal.h:105
vk_ret2str
static const char * vk_ret2str(VkResult res)
Definition: hwcontext_vulkan.c:372
AVVkFrameInternal
Definition: hwcontext_vulkan.c:128
VulkanDevicePriv::debug_ctx
VkDebugUtilsMessengerEXT debug_ctx
Definition: hwcontext_vulkan.c:98
AVVulkanFramesContext::alloc_pnext
void * alloc_pnext[AV_NUM_DATA_POINTERS]
Extension data for memory allocation.
Definition: hwcontext_vulkan.h:190
setup_queue_families
static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd)
Definition: hwcontext_vulkan.c:934
LIBAVUTIL_VERSION_MAJOR
#define LIBAVUTIL_VERSION_MAJOR
Definition: version.h:81
VulkanMapping
Definition: hwcontext_vulkan.c:2454
unmap_buffers
static int unmap_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, int nb_buffers, int flush)
Definition: hwcontext_vulkan.c:3658
ff_hwcontext_type_vulkan
const HWContextType ff_hwcontext_type_vulkan
Definition: hwcontext_vulkan.c:4146
hwcontext_vulkan.h
AVVulkanDeviceContext::enabled_inst_extensions
const char *const * enabled_inst_extensions
Enabled instance extensions.
Definition: hwcontext_vulkan.h:85
VulkanDevicePriv::device_features_1_2
VkPhysicalDeviceVulkan12Features device_features_1_2
Definition: hwcontext_vulkan.c:91
AVVulkanFramesContext::usage
VkImageUsageFlagBits usage
Defines extra usage of output frames.
Definition: hwcontext_vulkan.h:170
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:258
CASE
#define CASE(VAL)
AV_PIX_FMT_YUV422P10
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:460
AVVulkanDeviceContext::queue_family_tx_index
int queue_family_tx_index
Queue family index for transfer operations and the number of queues enabled.
Definition: hwcontext_vulkan.h:113
alloc_bind_mem
static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, void *alloc_pnext, size_t alloc_pnext_stride)
Definition: hwcontext_vulkan.c:1791
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
fp
#define fp
Definition: regdef.h:44
exp
int8_t exp
Definition: eval.c:72
create_buf
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)
Definition: hwcontext_vulkan.c:3509
VulkanFramesPriv
Definition: hwcontext_vulkan.c:116
index
int index
Definition: gxfenc.c:89
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
VulkanDeviceSelection
Definition: hwcontext_vulkan.c:761
FF_VK_EXT_DRM_MODIFIER_FLAGS
@ FF_VK_EXT_DRM_MODIFIER_FLAGS
Definition: vulkan_functions.h:31
source
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a source
Definition: filter_design.txt:255
AVDRMFrameDescriptor::layers
AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]
Array of layers in the frame.
Definition: hwcontext_drm.h:149
usage
const char * usage
Definition: floatimg_cmp.c:60
create_frame
static int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame, VkImageTiling tiling, VkImageUsageFlagBits usage, void *create_pnext)
Definition: hwcontext_vulkan.c:2029
AVVkFrame::size
size_t size[AV_NUM_DATA_POINTERS]
Definition: hwcontext_vulkan.h:230
vulkan_pool_alloc
static AVBufferRef * vulkan_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_vulkan.c:2197
PrepMode
PrepMode
Definition: hwcontext_vulkan.c:1911
f
f
Definition: af_crystalizer.c:122
AVCUDADeviceContext::internal
AVCUDADeviceContextInternal * internal
Definition: hwcontext_cuda.h:45
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
AV_PIX_FMT_P012
#define AV_PIX_FMT_P012
Definition: pixfmt.h:509
AV_PIX_FMT_FLAG_RGB
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:136
av_frame_copy
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:771
AVVkFrame
Definition: hwcontext_vulkan.h:213
av_vk_frame_alloc
AVVkFrame * av_vk_frame_alloc(void)
Allocates a single AVVkFrame and initializes everything as 0.
Definition: hwcontext_vulkan.c:4141
VulkanFramesPriv::upload_ctx
VulkanExecCtx upload_ctx
Definition: hwcontext_vulkan.c:121
vulkan_device_free
static void vulkan_device_free(AVHWDeviceContext *ctx)
Definition: hwcontext_vulkan.c:1295
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
VulkanQueueCtx::buf_deps_alloc_size
int buf_deps_alloc_size
Definition: hwcontext_vulkan.c:68
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:488
AV_PIX_FMT_YUV422P12
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:464
vulkan_unmap_frame
static void vulkan_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
Definition: hwcontext_vulkan.c:2459
transfer_image_buf
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)
Definition: hwcontext_vulkan.c:3705
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:445
size
int size
Definition: twinvq_data.h:10344
vulkan_transfer_data_from
static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_vulkan.c:4110
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:326
VulkanDevicePriv::use_linear_images
int use_linear_images
Definition: hwcontext_vulkan.c:104
AV_PIX_FMT_YUV444P12
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:466
FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
@ FF_VK_EXT_EXTERNAL_DMABUF_MEMORY
Definition: vulkan_functions.h:30
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:412
AV_PIX_FMT_NV16
@ AV_PIX_FMT_NV16
interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:191
VulkanDeviceSelection::vendor_id
uint32_t vendor_id
Definition: hwcontext_vulkan.c:766
AVDRMObjectDescriptor::size
size_t size
Total size of the object.
Definition: hwcontext_drm.h:58
height
#define height
ImageBuffer
Definition: hwcontext_vulkan.c:3477
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:167
AV_PIX_FMT_YUVA444P10
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:498
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
AVHWFramesConstraints::max_width
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:478
VulkanOptExtension
Definition: hwcontext_vulkan.c:336
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:256
CHECK_CU
#define CHECK_CU(x)
Definition: cuviddec.c:116
AV_PIX_FMT_VAAPI
@ AV_PIX_FMT_VAAPI
Hardware acceleration through VA-API, data[3] contains a VASurfaceID.
Definition: pixfmt.h:119
create_exec_ctx
static int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues)
Definition: hwcontext_vulkan.c:1068
VulkanDevicePriv::dev_is_nvidia
int dev_is_nvidia
Definition: hwcontext_vulkan.c:110
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
vulkan_free_internal
static void vulkan_free_internal(AVVkFrame *f)
Definition: hwcontext_vulkan.c:1729
AV_HWDEVICE_TYPE_VAAPI
@ AV_HWDEVICE_TYPE_VAAPI
Definition: hwcontext.h:31
add_buf_dep_exec_ctx
static int add_buf_dep_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, AVBufferRef *const *deps, int nb_deps)
Definition: hwcontext_vulkan.c:1220
COPY_FEATURE
#define COPY_FEATURE(DST, NAME)
vulkan.h
layout
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel layout
Definition: filter_design.txt:18
AVDRMFrameDescriptor::objects
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
Definition: hwcontext_drm.h:141
AVCUDADeviceContextInternal::cuda_dl
CudaFunctions * cuda_dl
Definition: hwcontext_cuda_internal.h:32
VulkanQueueCtx::buf_deps
AVBufferRef ** buf_deps
Definition: hwcontext_vulkan.c:66
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
FF_VK_EXT_EXTERNAL_FD_MEMORY
@ FF_VK_EXT_EXTERNAL_FD_MEMORY
Definition: vulkan_functions.h:32
AVDRMObjectDescriptor::format_modifier
uint64_t format_modifier
Format modifier applied to the object (DRM_FORMAT_MOD_*).
Definition: hwcontext_drm.h:65
VkFormat
enum VkFormat VkFormat
Definition: hwcontext_stub.c:25
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
weights
static const int weights[]
Definition: hevc_pel.c:32
AV_PIX_FMT_NV24
@ 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:368
plane_info
Definition: vf_edgedetect.c:52
vulkan_frames_init
static int vulkan_frames_init(AVHWFramesContext *hwfc)
Definition: hwcontext_vulkan.c:2275
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AVVulkanDeviceContext::nb_encode_queues
int nb_encode_queues
Definition: hwcontext_vulkan.h:129
get_buf_exec_ctx
static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
Definition: hwcontext_vulkan.c:1163
AV_PIX_FMT_X2RGB10
#define AV_PIX_FMT_X2RGB10
Definition: pixfmt.h:516
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:264
free_buf
static void free_buf(void *opaque, uint8_t *data)
Definition: hwcontext_vulkan.c:3484
VulkanDeviceSelection::has_uuid
int has_uuid
Definition: hwcontext_vulkan.c:763
hwcontext_drm.h
VulkanMapping::frame
AVVkFrame * frame
Definition: hwcontext_vulkan.c:2455
AVDRMPlaneDescriptor::object_index
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor.
Definition: hwcontext_drm.h:79
AV_PIX_FMT_NV21
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
Definition: pixfmt.h:90
AV_PIX_FMT_BGR565
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:451
vkfmts
const VkFormat vkfmts[4]
Definition: hwcontext_vulkan.c:167
ff_hwframe_map_replace
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:950
vk_dbg_callback
static VkBool32 vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *data, void *priv)
Definition: hwcontext_vulkan.c:412
AV_PIX_FMT_NV42
@ AV_PIX_FMT_NV42
as above, but U and V bytes are swapped
Definition: pixfmt.h:369
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:272
mod
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:750
AV_PIX_FMT_P016
#define AV_PIX_FMT_P016
Definition: pixfmt.h:510
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:446
AVHWFrameTransferDirection
AVHWFrameTransferDirection
Definition: hwcontext.h:415
create_instance
static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts)
Definition: hwcontext_vulkan.c:674
stride
#define stride
Definition: h264pred_template.c:537
AVVkFrame::sem
VkSemaphore sem[AV_NUM_DATA_POINTERS]
Synchronization timeline semaphores, one for each sw_format plane.
Definition: hwcontext_vulkan.h:249
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
AVCUDADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_cuda.h:42
hwcontext_vaapi.h
AVDRMLayerDescriptor::format
uint32_t format
Format of the layer (DRM_FORMAT_*).
Definition: hwcontext_drm.h:100
vk_find_struct
static const void * vk_find_struct(const void *chain, VkStructureType stype)
Definition: hwcontext_vulkan.c:250
ret
ret
Definition: filter_design.txt:187
AVHWDeviceContext::type
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:79
AV_PIX_FMT_NV12
@ 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
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVHWFramesContext::device_ctx
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:149
cuda_check.h
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:162
vulkan_get_buffer
static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
Definition: hwcontext_vulkan.c:2425
unref_exec_ctx_deps
static void unref_exec_ctx_deps(AVHWFramesContext *hwfc, VulkanExecCtx *cmd)
Definition: hwcontext_vulkan.c:1168
AVHWFramesConstraints::max_height
int max_height
Definition: hwcontext.h:479
AVVkFrame::internal
struct AVVkFrameInternal * internal
Internal data.
Definition: hwcontext_vulkan.h:261
get_plane_wh
static void get_plane_wh(int *w, int *h, enum AVPixelFormat format, int frame_w, int frame_h, int plane)
Definition: hwcontext_vulkan.c:2012
AV_PIX_FMT_YUV420P12
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:463
SIZE_SPECIFIER
#define SIZE_SPECIFIER
Definition: internal.h:150
map_buffers
static int map_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, uint8_t *mem[], int nb_buffers, int invalidate)
Definition: hwcontext_vulkan.c:3600
AVFrame::hw_frames_ctx
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition: frame.h:664
vulkan_device_create
static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:1538
AVFrame::height
int height
Definition: frame.h:397
av_image_copy_plane_uc_from
void av_image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, const uint8_t *src, ptrdiff_t src_linesize, ptrdiff_t bytewidth, int height)
Copy image data located in uncacheable (e.g.
Definition: imgutils.c:359
AVHWFramesConstraints::min_height
int min_height
Definition: hwcontext.h:472
VulkanQueueCtx::was_synchronous
int was_synchronous
Definition: hwcontext_vulkan.c:63
RELEASE_PROPS
#define RELEASE_PROPS(props, count)
Definition: hwcontext_vulkan.c:158
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AV_PIX_FMT_YUVA422P12
#define AV_PIX_FMT_YUVA422P12
Definition: pixfmt.h:499
AVVulkanDeviceContext::nb_comp_queues
int nb_comp_queues
Definition: hwcontext_vulkan.h:121
AV_PIX_FMT_GBRAPF32
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:489
LIBAVUTIL_VERSION_MICRO
#define LIBAVUTIL_VERSION_MICRO
Definition: version.h:83
find_device
static int find_device(AVHWDeviceContext *ctx, VulkanDeviceSelection *select)
Definition: hwcontext_vulkan.c:782
FF_VK_EXT_DEBUG_UTILS
@ FF_VK_EXT_DEBUG_UTILS
Definition: vulkan_functions.h:35
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:112
VulkanDevicePriv::dev_is_intel
int dev_is_intel
Definition: hwcontext_vulkan.c:113
optional_instance_exts
static const VulkanOptExtension optional_instance_exts[]
Definition: hwcontext_vulkan.c:341
AV_PIX_FMT_FLAG_PLANAR
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:132
PREP_MODE_EXTERNAL_IMPORT
@ PREP_MODE_EXTERNAL_IMPORT
Definition: hwcontext_vulkan.c:1914
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
AVVulkanFramesContext::tiling
VkImageTiling tiling
Controls the tiling of allocated frames.
Definition: hwcontext_vulkan.h:164
VulkanExecCtx
Definition: hwcontext_vulkan.c:71
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:508
AVVkFrame::sem_value
uint64_t sem_value[AV_NUM_DATA_POINTERS]
Up to date semaphore value at which each image becomes accessible.
Definition: hwcontext_vulkan.h:256
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:280
desc
const char * desc
Definition: libsvtav1.c:83
AVVulkanDeviceContext::enabled_dev_extensions
const char *const * enabled_dev_extensions
Enabled device extensions.
Definition: hwcontext_vulkan.h:96
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
flush
void(* flush)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
FFVulkanExtensions
FFVulkanExtensions
Definition: vulkan_functions.h:29
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
AVVulkanDeviceContext::act_dev
VkDevice act_dev
Active device.
Definition: hwcontext_vulkan.h:68
hwcontext_internal.h
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
AVVulkanDeviceContext::nb_enabled_inst_extensions
int nb_enabled_inst_extensions
Definition: hwcontext_vulkan.h:86
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVDictionaryEntry
Definition: dict.h:89
PREP_MODE_EXTERNAL_EXPORT
@ PREP_MODE_EXTERNAL_EXPORT
Definition: hwcontext_vulkan.c:1913
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
VulkanDevicePriv::mprops
VkPhysicalDeviceMemoryProperties mprops
Definition: hwcontext_vulkan.c:86
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
FF_VK_EXT_EXTERNAL_FD_SEM
@ FF_VK_EXT_EXTERNAL_FD_SEM
Definition: vulkan_functions.h:33
vulkan_device_create_internal
static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VulkanDeviceSelection *dev_select, AVDictionary *opts, int flags)
Definition: hwcontext_vulkan.c:1318
AVVulkanDeviceContext::nb_tx_queues
int nb_tx_queues
Definition: hwcontext_vulkan.h:114
vk_dev_type
static const char * vk_dev_type(enum VkPhysicalDeviceType type)
Definition: hwcontext_vulkan.c:770
imgutils.h
AV_PIX_FMT_XV36
#define AV_PIX_FMT_XV36
Definition: pixfmt.h:515
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
hwcontext.h
ImageBuffer::mapped_mem
int mapped_mem
Definition: hwcontext_vulkan.c:3481
AVDRMPlaneDescriptor::pitch
ptrdiff_t pitch
Pitch (linesize) of this plane.
Definition: hwcontext_drm.h:87
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:370
VulkanQueueCtx::queue
VkQueue queue
Definition: hwcontext_vulkan.c:62
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
HWContextType
Definition: hwcontext_internal.h:29
VulkanDevicePriv::contiguous_planes
int contiguous_planes
Definition: hwcontext_vulkan.c:107
AVVAAPIDeviceContext
VAAPI connection details.
Definition: hwcontext_vaapi.h:68
h
h
Definition: vp9dsp_template.c:2038
pixfmt
enum AVPixelFormat pixfmt
Definition: hwcontext_vulkan.c:166
AVVulkanDeviceContext::device_features
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation.
Definition: hwcontext_vulkan.h:76
AVDictionaryEntry::value
char * value
Definition: dict.h:91
avstring.h
AVDRMDeviceContext
DRM device.
Definition: hwcontext_drm.h:157
AV_PIX_FMT_VUYX
@ AV_PIX_FMT_VUYX
packed VUYX 4:4:4, 32bpp, Variant of VUYA where alpha channel is left undefined
Definition: pixfmt.h:403
ADD_VAL_TO_LIST
#define ADD_VAL_TO_LIST(list, count, val)
Definition: hwcontext_vulkan.c:144
AVDRMFrameDescriptor::nb_objects
int nb_objects
Number of DRM objects making up this frame.
Definition: hwcontext_drm.h:137
AVVulkanDeviceContext::queue_family_encode_index
int queue_family_encode_index
Queue family index for video encode ops, and the amount of queues enabled.
Definition: hwcontext_vulkan.h:128
HWMapDescriptor
Definition: hwcontext_internal.h:132
FFVulkanFunctions
Definition: vulkan_functions.h:175
VulkanFramesPriv::modifier_info
VkImageDrmFormatModifierListCreateInfoEXT * modifier_info
Definition: hwcontext_vulkan.c:125
VulkanDeviceSelection::name
const char * name
Definition: hwcontext_vulkan.c:764
AV_HWDEVICE_TYPE_DRM
@ AV_HWDEVICE_TYPE_DRM
Definition: hwcontext.h:36
AV_PIX_FMT_YUVA422P
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:166
w32dlfcn.h
av_get_pix_fmt_name
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:2778