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