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/* clang wants function declarations in the header to have weak attribute */
53#if !defined(_MSC_VER) && !defined(__MINGW32__)
54#define ATTR_WEAK __attribute__ ((weak))
55#else
56#define ATTR_WEAK
57#endif
58
59% for p in instance_prefixes:
60extern const struct vk_instance_entrypoint_table ${p}_instance_entrypoints;
61% endfor
62
63% for p in physical_device_prefixes:
64extern const struct vk_physical_device_entrypoint_table ${p}_physical_device_entrypoints;
65% endfor
66
67% for p in device_prefixes:
68extern const struct vk_device_entrypoint_table ${p}_device_entrypoints;
69% endfor
70
71% for v in tmpl_variants_sanitized:
72extern const struct vk_device_entrypoint_table ${tmpl_prefix}_device_entrypoints_${v};
73% endfor
74
75% if gen_proto:
76% for e in instance_entrypoints:
77  % if e.guard is not None:
78#ifdef ${e.guard}
79  % endif
80  % for p in physical_device_prefixes:
81  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()});
82  % endfor
83  % if e.guard is not None:
84#endif // ${e.guard}
85  % endif
86% endfor
87
88% for e in physical_device_entrypoints:
89  % if e.guard is not None:
90#ifdef ${e.guard}
91  % endif
92  % for p in physical_device_prefixes:
93  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()});
94  % endfor
95  % if e.guard is not None:
96#endif // ${e.guard}
97  % endif
98% endfor
99
100% for e in device_entrypoints:
101  % if e.guard is not None:
102#ifdef ${e.guard}
103  % endif
104  % for p in device_prefixes:
105  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) ATTR_WEAK;
106  % endfor
107
108  % if tmpl_prefix:
109  template <${tmpl_param}>
110  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${tmpl_prefix}_${e.name}(${e.decl_params()});
111
112  #define ${tmpl_prefix}_${e.name}_GENS(X) \
113  template VKAPI_ATTR ${e.return_type} VKAPI_CALL ${tmpl_prefix}_${e.name}<X>(${e.decl_params()});
114  % endif
115
116  % if e.guard is not None:
117#endif // ${e.guard}
118  % endif
119% endfor
120% endif
121
122% if not tmpl_prefix:
123#ifdef __cplusplus
124}
125#endif
126% endif
127
128#endif /* ${guard} */
129""")
130
131TEMPLATE_C = Template(COPYRIGHT + """
132/* This file generated from ${filename}, don't edit directly. */
133
134#include "${header}"
135
136/* Weak aliases for all potential implementations. These will resolve to
137 * NULL if they're not defined, which lets the resolve_entrypoint() function
138 * either pick the correct entry point.
139 *
140 * MSVC uses different decorated names for 32-bit versus 64-bit. Declare
141 * all argument sizes for 32-bit because computing the actual size would be
142 * difficult.
143 */
144
145<%def name="entrypoint_table(type, entrypoints, prefixes)">
146% if gen_weak:
147  % for e in entrypoints:
148    % if e.guard is not None:
149#ifdef ${e.guard}
150    % endif
151    % for p in prefixes:
152#ifdef _MSC_VER
153#ifdef _M_IX86
154      % for args_size in [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 60, 104]:
155    #pragma comment(linker, "/alternatename:_${p}_${e.name}@${args_size}=_vk_entrypoint_stub@0")
156      % endfor
157#else
158    #pragma comment(linker, "/alternatename:${p}_${e.name}=vk_entrypoint_stub")
159#if defined(_M_ARM64EC)
160    #pragma comment(linker, "/alternatename:#${p}_${e.name}=#vk_entrypoint_stub")
161#endif
162#endif
163#else
164    VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) __attribute__ ((weak));
165
166    % if entrypoints == device_entrypoints:
167      % for v in tmpl_variants:
168    extern template
169    VKAPI_ATTR __attribute__ ((weak)) ${e.return_type} VKAPI_CALL ${tmpl_prefix}_${e.name}${v}(${e.decl_params()});
170      % endfor
171    % endif
172#endif
173    % endfor
174
175    % if e.guard is not None:
176#endif // ${e.guard}
177    % endif
178  % endfor
179% endif
180
181% for p in prefixes:
182const struct vk_${type}_entrypoint_table ${p}_${type}_entrypoints = {
183  % for e in entrypoints:
184    % if e.guard is not None:
185#ifdef ${e.guard}
186    % endif
187    .${e.name} = ${p}_${e.name},
188    % if e.guard is not None:
189#elif defined(_MSC_VER)
190    .${e.name} = (PFN_vkVoidFunction)vk_entrypoint_stub,
191#endif // ${e.guard}
192    % endif
193  % endfor
194};
195% endfor
196
197% if entrypoints == device_entrypoints:
198% for v, entrypoint_v in zip(tmpl_variants, tmpl_variants_sanitized):
199const struct vk_${type}_entrypoint_table ${tmpl_prefix}_${type}_entrypoints_${entrypoint_v} = {
200  % for e in entrypoints:
201    % if e.guard is not None:
202#ifdef ${e.guard}
203    % endif
204    .${e.name} = ${tmpl_prefix}_${e.name}${v},
205    % if e.guard is not None:
206#elif defined(_MSC_VER)
207    .${e.name} = (PFN_vkVoidFunction)vk_entrypoint_stub,
208#endif // ${e.guard}
209    % endif
210  % endfor
211};
212% endfor
213% endif
214</%def>
215
216${entrypoint_table('instance', instance_entrypoints, instance_prefixes)}
217${entrypoint_table('physical_device', physical_device_entrypoints, physical_device_prefixes)}
218${entrypoint_table('device', device_entrypoints, device_prefixes)}
219""")
220
221
222def main():
223    parser = argparse.ArgumentParser()
224    parser.add_argument('--out-c', required=True, help='Output C file.')
225    parser.add_argument('--out-h', required=True, help='Output H file.')
226    parser.add_argument('--beta', required=True, help='Enable beta extensions.')
227    parser.add_argument('--xml',
228                        help='Vulkan API XML file.',
229                        required=True, action='append', dest='xml_files')
230    parser.add_argument('--proto', help='Generate entrypoint prototypes',
231                        action='store_true', dest='gen_proto')
232    parser.add_argument('--weak', help='Generate weak entrypoint declarations',
233                        action='store_true', dest='gen_weak')
234    parser.add_argument('--prefix',
235                        help='Prefix to use for all dispatch tables.',
236                        action='append', default=[], dest='prefixes')
237    parser.add_argument('--device-prefix',
238                        help='Prefix to use for device dispatch tables.',
239                        action='append', default=[], dest='device_prefixes')
240    parser.add_argument('--include',
241                        help='Includes to add to the H file.',
242                        action='append', default=[], dest='includes')
243    parser.add_argument('--tmpl-prefix',
244                        help='Prefix to use for templated device dispatch tables.',
245                        dest='tmpl_prefix')
246    parser.add_argument('--tmpl-param',
247                        help='Param to use for templated device dispatch tables.',
248                        dest='tmpl_param')
249    parser.add_argument('--tmpl-variants',
250                      help='All template specializations.',
251                      nargs='+', default=[], dest='tmpl_variants')
252    args = parser.parse_args()
253
254    instance_prefixes = args.prefixes
255    physical_device_prefixes = args.prefixes
256    device_prefixes = args.prefixes + args.device_prefixes
257
258    tmpl_variants_sanitized = [
259        ''.join(filter(str.isalnum, v)).lower() for v in args.tmpl_variants]
260
261    entrypoints = get_entrypoints_from_xml(args.xml_files, args.beta)
262
263    device_entrypoints = []
264    physical_device_entrypoints = []
265    instance_entrypoints = []
266    for e in entrypoints:
267        if e.is_device_entrypoint():
268            device_entrypoints.append(e)
269        elif e.is_physical_device_entrypoint():
270            physical_device_entrypoints.append(e)
271        else:
272            instance_entrypoints.append(e)
273
274    assert os.path.dirname(args.out_c) == os.path.dirname(args.out_h)
275
276    environment = {
277        'gen_proto': args.gen_proto,
278        'gen_weak': args.gen_weak,
279        'header': os.path.basename(args.out_h),
280        'instance_entrypoints': instance_entrypoints,
281        'instance_prefixes': instance_prefixes,
282        'physical_device_entrypoints': physical_device_entrypoints,
283        'physical_device_prefixes': physical_device_prefixes,
284        'device_entrypoints': device_entrypoints,
285        'device_prefixes': device_prefixes,
286        'includes': args.includes,
287        'tmpl_prefix': args.tmpl_prefix,
288        'tmpl_param': args.tmpl_param,
289        'tmpl_variants': args.tmpl_variants,
290        'tmpl_variants_sanitized': tmpl_variants_sanitized,
291        'filename': os.path.basename(__file__),
292    }
293
294    # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
295    # per entry point.
296    try:
297        with open(args.out_h, 'w', encoding='utf-8') as f:
298            guard = os.path.basename(args.out_h).replace('.', '_').upper()
299            f.write(TEMPLATE_H.render(guard=guard, **environment))
300        with open(args.out_c, 'w', encoding='utf-8') as f:
301            f.write(TEMPLATE_C.render(**environment))
302
303    except Exception:
304        # In the event there's an error, this imports some helpers from mako
305        # to print a useful stack trace and prints it, then exits with
306        # status 1, if python is run with debug; otherwise it just raises
307        # the exception
308        import sys
309        from mako import exceptions
310        print(exceptions.text_error_template().render(), file=sys.stderr)
311        sys.exit(1)
312
313if __name__ == '__main__':
314    main()
315