summaryrefslogtreecommitdiff
path: root/libavutil/vulkan_loader.h
blob: 3f1ee6aa4672a9b15b8664d183d90ca895ec456c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef AVUTIL_VULKAN_LOADER_H
#define AVUTIL_VULKAN_LOADER_H

#include "vulkan_functions.h"

/* Macro to turn a function name into a loader struct */
#define PFN_LOAD_INFO(req_inst, req_dev, ext_flag, name) \
    {                                                    \
        req_inst,                                        \
        req_dev,                                         \
        offsetof(FFVulkanFunctions, name),               \
        ext_flag,                                        \
        { "vk"#name, "vk"#name"EXT", "vk"#name"KHR" }    \
    },

static inline uint64_t ff_vk_extensions_to_mask(const char * const *extensions,
                                                int nb_extensions)
{
    static const struct ExtensionMap {
        const char *name;
        FFVulkanExtensions flag;
    } extension_map[] = {
        { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,   FF_VK_EXT_EXTERNAL_DMABUF_MEMORY },
        { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS     },
        { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,        FF_VK_EXT_EXTERNAL_FD_MEMORY     },
        { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,     FF_VK_EXT_EXTERNAL_FD_SEM        },
        { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,      FF_VK_EXT_EXTERNAL_HOST_MEMORY   },
        { VK_EXT_DEBUG_UTILS_EXTENSION_NAME,               FF_VK_EXT_DEBUG_UTILS            },
#ifdef _WIN32
        { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,     FF_VK_EXT_EXTERNAL_WIN32_MEMORY  },
        { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,  FF_VK_EXT_EXTERNAL_WIN32_SEM     },
#endif
    };

    FFVulkanExtensions mask = 0x0;

    for (int i = 0; i < nb_extensions; i++) {
        for (int j = 0; j < FF_ARRAY_ELEMS(extension_map); j++) {
            if (!strcmp(extensions[i], extension_map[j].name)) {
                mask |= extension_map[j].flag;
                continue;
            }
        }
    }

    return mask;
}

/**
 * Function loader.
 * Vulkan function from scratch loading happens in 3 stages - the first one
 * is before any initialization has happened, and you have neither an instance
 * structure nor a device structure. At this stage, you can only get the bare
 * minimals to initialize an instance.
 * The second stage is when you have an instance. At this stage, you can
 * initialize a VkDevice, and have an idea of what extensions each device
 * supports.
 * Finally, in the third stage, you can proceed and load all core functions,
 * plus you can be sure that any extensions you've enabled during device
 * initialization will be available.
 */
static inline int ff_vk_load_functions(AVHWDeviceContext *ctx,
                                       FFVulkanFunctions *vk,
                                       uint64_t extensions_mask,
                                       int has_inst, int has_dev)
{
    AVVulkanDeviceContext *hwctx = ctx->hwctx;

    static const struct FunctionLoadInfo {
        int req_inst;
        int req_dev;
        size_t struct_offset;
        FFVulkanExtensions ext_flag;
        const char *names[3];
    } vk_load_info[] = {
        FN_LIST(PFN_LOAD_INFO)
#ifdef _WIN32
        FN_LIST_WIN32(PFN_LOAD_INFO)
#endif
    };

    for (int i = 0; i < FF_ARRAY_ELEMS(vk_load_info); i++) {
        const struct FunctionLoadInfo *load = &vk_load_info[i];
        PFN_vkVoidFunction fn;

        if (load->req_dev  && !has_dev)
            continue;
        if (load->req_inst && !has_inst)
            continue;

        for (int j = 0; j < FF_ARRAY_ELEMS(load->names); j++) {
            const char *name = load->names[j];

            if (load->req_dev)
                fn = vk->GetDeviceProcAddr(hwctx->act_dev, name);
            else if (load->req_inst)
                fn = hwctx->get_proc_addr(hwctx->inst, name);
            else
                fn = hwctx->get_proc_addr(NULL, name);

            if (fn)
                break;
        }

        if (!fn && ((extensions_mask &~ FF_VK_EXT_NO_FLAG) & load->ext_flag)) {
            av_log(ctx, AV_LOG_ERROR, "Loader error, function \"%s\" indicated "
                   "as supported, but got NULL function pointer!\n", load->names[0]);
            return AVERROR_EXTERNAL;
        }

        *(PFN_vkVoidFunction *)((uint8_t *)vk + load->struct_offset) = fn;
    }

    return 0;
}

#endif /* AVUTIL_VULKAN_LOADER_H */