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