xref: /aosp_15_r20/external/mesa3d/src/vulkan/util/vk_entrypoints_gen.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1COPYRIGHT=u"""
2/* Copyright © 2015-2021 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23"""
24
25import argparse
26import os
27
28from mako.template import Template
29
30# Mesa-local imports must be declared in meson variable
31# '{file_without_suffix}_depend_files'.
32from vk_entrypoints import get_entrypoints_from_xml
33
34TEMPLATE_H = Template(COPYRIGHT + """\
35/* This file generated from ${filename}, don't edit directly. */
36
37#include "vk_dispatch_table.h"
38
39% for i in includes:
40#include "${i}"
41% endfor
42
43#ifndef ${guard}
44#define ${guard}
45
46% if not tmpl_prefix:
47#ifdef __cplusplus
48extern "C" {
49#endif
50% endif
51
52/* Entrypoint symbols are optional, and resolves to NULL if undefined.
53 * On Unix, this semantics is achieved through weak symbols.
54 * Note that we only declare the symbols as weak when it needs to be optional;
55 * otherwise, the symbol is declared as a regular symbol.
56 * This is to workaround a MinGW limitation: on MinGW, the definition for a
57 * weak symbol must be regular, or the linker will end up resolving to one of
58 * the fallback symbols with the absolute value of 0.
59 * On MSVC, weak symbols are not well supported, so we use the functionally
60 * equivalent /alternatename.
61 */
62#if !defined(_MSC_VER) && defined(VK_ENTRY_USE_WEAK)
63#define VK_ENTRY_WEAK __attribute__ ((weak))
64#else
65#define VK_ENTRY_WEAK
66#endif
67
68/* On Unix, we explicitly declare the symbols as hidden, as -fvisibility=hidden
69 * only applies to definitions, not declarations.
70 * Windows uses hidden visibility by default (requiring dllexport for public
71 * symbols), so we don't need to deal with visibility there.
72 */
73#ifndef _WIN32
74#define VK_ENTRY_HIDDEN __attribute__ ((visibility("hidden")))
75#else
76#define VK_ENTRY_HIDDEN
77#endif
78
79% for p in instance_prefixes:
80extern const struct vk_instance_entrypoint_table ${p}_instance_entrypoints;
81% endfor
82
83% for p in physical_device_prefixes:
84extern const struct vk_physical_device_entrypoint_table ${p}_physical_device_entrypoints;
85% endfor
86
87% for p in device_prefixes:
88extern const struct vk_device_entrypoint_table ${p}_device_entrypoints;
89% endfor
90
91% for v in tmpl_variants_sanitized:
92extern const struct vk_device_entrypoint_table ${tmpl_prefix}_device_entrypoints_${v};
93% endfor
94
95% if gen_proto:
96% for e in instance_entrypoints:
97  % if e.guard is not None:
98#ifdef ${e.guard}
99  % endif
100  % for p in physical_device_prefixes:
101  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) VK_ENTRY_WEAK VK_ENTRY_HIDDEN;
102  % endfor
103  % if e.guard is not None:
104#endif // ${e.guard}
105  % endif
106% endfor
107
108% for e in physical_device_entrypoints:
109  % if e.guard is not None:
110#ifdef ${e.guard}
111  % endif
112  % for p in physical_device_prefixes:
113  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) VK_ENTRY_WEAK VK_ENTRY_HIDDEN;
114  % endfor
115  % if e.guard is not None:
116#endif // ${e.guard}
117  % endif
118% endfor
119
120% for e in device_entrypoints:
121  % if e.guard is not None:
122#ifdef ${e.guard}
123  % endif
124  % for p in device_prefixes:
125  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) VK_ENTRY_WEAK VK_ENTRY_HIDDEN;
126  % endfor
127
128  % if tmpl_prefix:
129  template <${tmpl_param}>
130  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${tmpl_prefix}_${e.name}(${e.decl_params()});
131
132  #define ${tmpl_prefix}_${e.name}_GENS(X) \
133  template VKAPI_ATTR ${e.return_type} VKAPI_CALL ${tmpl_prefix}_${e.name}<X>(${e.decl_params()});
134  % endif
135
136  % if e.guard is not None:
137#endif // ${e.guard}
138  % endif
139% endfor
140% endif
141
142% if not tmpl_prefix:
143#ifdef __cplusplus
144}
145#endif
146% endif
147
148#endif /* ${guard} */
149""")
150
151TEMPLATE_C = Template(COPYRIGHT + """
152/* This file generated from ${filename}, don't edit directly. */
153
154/* This file is the only place we rely on undefined symbols to fall back to
155 * NULL. Other files use regular symbol declarations.
156 * See also comments on VK_ENTRY_WEAK.
157 */
158#define VK_ENTRY_USE_WEAK 1
159#include "${header}"
160
161/* Weak aliases for all potential implementations. These will resolve to
162 * NULL if they're not defined, which lets the resolve_entrypoint() function
163 * either pick the correct entry point.
164 *
165 * MSVC uses different decorated names for 32-bit versus 64-bit. Declare
166 * all argument sizes for 32-bit because computing the actual size would be
167 * difficult.
168 */
169
170<%def name="entrypoint_table(type, entrypoints, prefixes)">
171% if gen_weak:
172  % for e in entrypoints:
173    % if e.guard is not None:
174#ifdef ${e.guard}
175    % endif
176    % for p in prefixes:
177#ifdef _MSC_VER
178#ifdef _M_IX86
179      % for args_size in [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 60, 104]:
180    #pragma comment(linker, "/alternatename:_${p}_${e.name}@${args_size}=_vk_entrypoint_stub@0")
181      % endfor
182#else
183    #pragma comment(linker, "/alternatename:${p}_${e.name}=vk_entrypoint_stub")
184#if defined(_M_ARM64EC)
185    #pragma comment(linker, "/alternatename:#${p}_${e.name}=#vk_entrypoint_stub")
186#endif
187#endif
188#else
189    % if entrypoints == device_entrypoints:
190      % for v in tmpl_variants:
191    extern template
192    VKAPI_ATTR __attribute__ ((weak)) ${e.return_type} VKAPI_CALL ${tmpl_prefix}_${e.name}${v}(${e.decl_params()});
193      % endfor
194    % endif
195#endif
196    % endfor
197
198    % if e.guard is not None:
199#endif // ${e.guard}
200    % endif
201  % endfor
202% endif
203
204% for p in prefixes:
205const struct vk_${type}_entrypoint_table ${p}_${type}_entrypoints = {
206  % for e in entrypoints:
207    % if e.guard is not None:
208#ifdef ${e.guard}
209    % endif
210    .${e.name} = ${p}_${e.name},
211    % if e.guard is not None:
212#elif defined(_MSC_VER)
213    .${e.name} = (PFN_vkVoidFunction)vk_entrypoint_stub,
214#endif // ${e.guard}
215    % endif
216  % endfor
217};
218% endfor
219
220% if entrypoints == device_entrypoints:
221% for v, entrypoint_v in zip(tmpl_variants, tmpl_variants_sanitized):
222const struct vk_${type}_entrypoint_table ${tmpl_prefix}_${type}_entrypoints_${entrypoint_v} = {
223  % for e in entrypoints:
224    % if e.guard is not None:
225#ifdef ${e.guard}
226    % endif
227    .${e.name} = ${tmpl_prefix}_${e.name}${v},
228    % if e.guard is not None:
229#elif defined(_MSC_VER)
230    .${e.name} = (PFN_vkVoidFunction)vk_entrypoint_stub,
231#endif // ${e.guard}
232    % endif
233  % endfor
234};
235% endfor
236% endif
237</%def>
238
239${entrypoint_table('instance', instance_entrypoints, instance_prefixes)}
240${entrypoint_table('physical_device', physical_device_entrypoints, physical_device_prefixes)}
241${entrypoint_table('device', device_entrypoints, device_prefixes)}
242""")
243
244
245def main():
246    parser = argparse.ArgumentParser()
247    parser.add_argument('--out-c', required=True, help='Output C file.')
248    parser.add_argument('--out-h', required=True, help='Output H file.')
249    parser.add_argument('--beta', required=True, help='Enable beta extensions.')
250    parser.add_argument('--xml',
251                        help='Vulkan API XML file.',
252                        required=True, action='append', dest='xml_files')
253    parser.add_argument('--proto', help='Generate entrypoint prototypes',
254                        action='store_true', dest='gen_proto')
255    parser.add_argument('--weak', help='Generate weak entrypoint declarations',
256                        action='store_true', dest='gen_weak')
257    parser.add_argument('--prefix',
258                        help='Prefix to use for all dispatch tables.',
259                        action='append', default=[], dest='prefixes')
260    parser.add_argument('--device-prefix',
261                        help='Prefix to use for device dispatch tables.',
262                        action='append', default=[], dest='device_prefixes')
263    parser.add_argument('--include',
264                        help='Includes to add to the H file.',
265                        action='append', default=[], dest='includes')
266    parser.add_argument('--tmpl-prefix',
267                        help='Prefix to use for templated device dispatch tables.',
268                        dest='tmpl_prefix')
269    parser.add_argument('--tmpl-param',
270                        help='Param to use for templated device dispatch tables.',
271                        dest='tmpl_param')
272    parser.add_argument('--tmpl-variants',
273                      help='All template specializations.',
274                      nargs='+', default=[], dest='tmpl_variants')
275    args = parser.parse_args()
276
277    instance_prefixes = args.prefixes
278    physical_device_prefixes = args.prefixes
279    device_prefixes = args.prefixes + args.device_prefixes
280
281    tmpl_variants_sanitized = [
282        ''.join(filter(str.isalnum, v)).lower() for v in args.tmpl_variants]
283
284    entrypoints = get_entrypoints_from_xml(args.xml_files, args.beta)
285
286    device_entrypoints = []
287    physical_device_entrypoints = []
288    instance_entrypoints = []
289    for e in entrypoints:
290        if e.is_device_entrypoint():
291            device_entrypoints.append(e)
292        elif e.is_physical_device_entrypoint():
293            physical_device_entrypoints.append(e)
294        else:
295            instance_entrypoints.append(e)
296
297    assert os.path.dirname(args.out_c) == os.path.dirname(args.out_h)
298
299    environment = {
300        'gen_proto': args.gen_proto,
301        'gen_weak': args.gen_weak,
302        'header': os.path.basename(args.out_h),
303        'instance_entrypoints': instance_entrypoints,
304        'instance_prefixes': instance_prefixes,
305        'physical_device_entrypoints': physical_device_entrypoints,
306        'physical_device_prefixes': physical_device_prefixes,
307        'device_entrypoints': device_entrypoints,
308        'device_prefixes': device_prefixes,
309        'includes': args.includes,
310        'tmpl_prefix': args.tmpl_prefix,
311        'tmpl_param': args.tmpl_param,
312        'tmpl_variants': args.tmpl_variants,
313        'tmpl_variants_sanitized': tmpl_variants_sanitized,
314        'filename': os.path.basename(__file__),
315    }
316
317    # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
318    # per entry point.
319    try:
320        with open(args.out_h, 'w', encoding='utf-8') as f:
321            guard = os.path.basename(args.out_h).replace('.', '_').upper()
322            f.write(TEMPLATE_H.render(guard=guard, **environment))
323        with open(args.out_c, 'w', encoding='utf-8') as f:
324            f.write(TEMPLATE_C.render(**environment))
325
326    except Exception:
327        # In the event there's an error, this imports some helpers from mako
328        # to print a useful stack trace and prints it, then exits with
329        # status 1, if python is run with debug; otherwise it just raises
330        # the exception
331        import sys
332        from mako import exceptions
333        print(exceptions.text_error_template().render(), file=sys.stderr)
334        sys.exit(1)
335
336if __name__ == '__main__':
337    main()
338