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#ifndef ${guard}
40#define ${guard}
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46% for p in instance_prefixes:
47extern const struct vk_instance_entrypoint_table ${p}_instance_entrypoints;
48% endfor
49
50% for p in physical_device_prefixes:
51extern const struct vk_physical_device_entrypoint_table ${p}_physical_device_entrypoints;
52% endfor
53
54% for p in device_prefixes:
55extern const struct vk_device_entrypoint_table ${p}_device_entrypoints;
56% endfor
57
58% if gen_proto:
59% for e in instance_entrypoints:
60  % if e.guard is not None:
61#ifdef ${e.guard}
62  % endif
63  % for p in physical_device_prefixes:
64  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()});
65  % endfor
66  % if e.guard is not None:
67#endif // ${e.guard}
68  % endif
69% endfor
70
71% for e in physical_device_entrypoints:
72  % if e.guard is not None:
73#ifdef ${e.guard}
74  % endif
75  % for p in physical_device_prefixes:
76  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()});
77  % endfor
78  % if e.guard is not None:
79#endif // ${e.guard}
80  % endif
81% endfor
82
83% for e in device_entrypoints:
84  % if e.guard is not None:
85#ifdef ${e.guard}
86  % endif
87  % for p in device_prefixes:
88  VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()});
89  % endfor
90  % if e.guard is not None:
91#endif // ${e.guard}
92  % endif
93% endfor
94% endif
95
96#ifdef __cplusplus
97}
98#endif
99
100#endif /* ${guard} */
101""")
102
103TEMPLATE_C = Template(COPYRIGHT + """
104/* This file generated from ${filename}, don't edit directly. */
105
106#include "${header}"
107
108/* Weak aliases for all potential implementations. These will resolve to
109 * NULL if they're not defined, which lets the resolve_entrypoint() function
110 * either pick the correct entry point.
111 *
112 * MSVC uses different decorated names for 32-bit versus 64-bit. Declare
113 * all argument sizes for 32-bit because computing the actual size would be
114 * difficult.
115 */
116
117<%def name="entrypoint_table(type, entrypoints, prefixes)">
118% if gen_weak:
119  % for e in entrypoints:
120    % if e.guard is not None:
121#ifdef ${e.guard}
122    % endif
123    % for p in prefixes:
124#ifdef _MSC_VER
125#ifdef _M_IX86
126      % for args_size in [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 60, 104]:
127    #pragma comment(linker, "/alternatename:_${p}_${e.name}@${args_size}=_vk_entrypoint_stub@0")
128      % endfor
129#else
130    #pragma comment(linker, "/alternatename:${p}_${e.name}=vk_entrypoint_stub")
131#if defined(_M_ARM64EC)
132    #pragma comment(linker, "/alternatename:#${p}_${e.name}=#vk_entrypoint_stub")
133#endif
134#endif
135#else
136    VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) __attribute__ ((weak));
137#endif
138    % endfor
139    % if e.guard is not None:
140#endif // ${e.guard}
141    % endif
142  % endfor
143% endif
144
145% for p in prefixes:
146const struct vk_${type}_entrypoint_table ${p}_${type}_entrypoints = {
147  % for e in entrypoints:
148    % if e.guard is not None:
149#ifdef ${e.guard}
150    % endif
151    .${e.name} = ${p}_${e.name},
152    % if e.guard is not None:
153#elif defined(_MSC_VER)
154    .${e.name} = (PFN_vkVoidFunction)vk_entrypoint_stub,
155#endif // ${e.guard}
156    % endif
157  % endfor
158};
159% endfor
160</%def>
161
162${entrypoint_table('instance', instance_entrypoints, instance_prefixes)}
163${entrypoint_table('physical_device', physical_device_entrypoints, physical_device_prefixes)}
164${entrypoint_table('device', device_entrypoints, device_prefixes)}
165""")
166
167def get_entrypoints_defines(doc):
168    """Maps entry points to extension defines."""
169    entrypoints_to_defines = {}
170
171    platform_define = {}
172    for platform in doc.findall('./platforms/platform'):
173        name = platform.attrib['name']
174        define = platform.attrib['protect']
175        platform_define[name] = define
176
177    for extension in doc.findall('./extensions/extension[@platform]'):
178        platform = extension.attrib['platform']
179        define = platform_define[platform]
180
181        for entrypoint in extension.findall('./require/command'):
182            fullname = entrypoint.attrib['name']
183            entrypoints_to_defines[fullname] = define
184
185    return entrypoints_to_defines
186
187
188def main():
189    parser = argparse.ArgumentParser()
190    parser.add_argument('--out-c', required=True, help='Output C file.')
191    parser.add_argument('--out-h', required=True, help='Output H file.')
192    parser.add_argument('--xml',
193                        help='Vulkan API XML file.',
194                        required=True, action='append', dest='xml_files')
195    parser.add_argument('--proto', help='Generate entrypoint prototypes',
196                        action='store_true', dest='gen_proto')
197    parser.add_argument('--weak', help='Generate weak entrypoint declarations',
198                        action='store_true', dest='gen_weak')
199    parser.add_argument('--prefix',
200                        help='Prefix to use for all dispatch tables.',
201                        action='append', default=[], dest='prefixes')
202    parser.add_argument('--device-prefix',
203                        help='Prefix to use for device dispatch tables.',
204                        action='append', default=[], dest='device_prefixes')
205    args = parser.parse_args()
206
207    instance_prefixes = args.prefixes
208    physical_device_prefixes = args.prefixes
209    device_prefixes = args.prefixes + args.device_prefixes
210
211    entrypoints = get_entrypoints_from_xml(args.xml_files)
212
213    device_entrypoints = []
214    physical_device_entrypoints = []
215    instance_entrypoints = []
216    for e in entrypoints:
217        if e.is_device_entrypoint():
218            device_entrypoints.append(e)
219        elif e.is_physical_device_entrypoint():
220            physical_device_entrypoints.append(e)
221        else:
222            instance_entrypoints.append(e)
223
224    assert os.path.dirname(args.out_c) == os.path.dirname(args.out_h)
225
226    environment = {
227        'gen_proto': args.gen_proto,
228        'gen_weak': args.gen_weak,
229        'header': os.path.basename(args.out_h),
230        'instance_entrypoints': instance_entrypoints,
231        'instance_prefixes': instance_prefixes,
232        'physical_device_entrypoints': physical_device_entrypoints,
233        'physical_device_prefixes': physical_device_prefixes,
234        'device_entrypoints': device_entrypoints,
235        'device_prefixes': device_prefixes,
236        'filename': os.path.basename(__file__),
237    }
238
239    # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
240    # per entry point.
241    try:
242        with open(args.out_h, 'w', encoding='utf-8') as f:
243            guard = os.path.basename(args.out_h).replace('.', '_').upper()
244            f.write(TEMPLATE_H.render(guard=guard, **environment))
245        with open(args.out_c, 'w', encoding='utf-8') as f:
246            f.write(TEMPLATE_C.render(**environment))
247
248    except Exception:
249        # In the event there's an error, this imports some helpers from mako
250        # to print a useful stack trace and prints it, then exits with
251        # status 1, if python is run with debug; otherwise it just raises
252        # the exception
253        import sys
254        from mako import exceptions
255        print(exceptions.text_error_template().render(), file=sys.stderr)
256        sys.exit(1)
257
258if __name__ == '__main__':
259    main()
260