1# coding=utf-8 2COPYRIGHT = """\ 3/* 4 * Copyright 2020 Intel Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26""" 27 28import argparse 29import math 30import os 31import xml.etree.ElementTree as et 32 33from collections import OrderedDict, namedtuple 34from mako.template import Template 35 36# Mesa-local imports must be declared in meson variable 37# '{file_without_suffix}_depend_files'. 38from vk_extensions import * 39 40# We generate a static hash table for entry point lookup 41# (vkGetProcAddress). We use a linear congruential generator for our hash 42# function and a power-of-two size table. The prime numbers are determined 43# experimentally. 44 45TEMPLATE_H = Template(COPYRIGHT + """\ 46/* This file generated from ${filename}, don't edit directly. */ 47 48#ifndef VK_DISPATCH_TABLE_H 49#define VK_DISPATCH_TABLE_H 50 51#include "vulkan/vulkan.h" 52#include "vulkan/vk_android_native_buffer.h" 53 54#include "vk_extensions.h" 55 56/* Windows api conflict */ 57#ifdef _WIN32 58#include <windows.h> 59#ifdef CreateSemaphore 60#undef CreateSemaphore 61#endif 62#ifdef CreateEvent 63#undef CreateEvent 64#endif 65#endif 66 67#ifdef __cplusplus 68extern "C" { 69#endif 70 71#ifdef _MSC_VER 72VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void); 73#endif 74 75<%def name="dispatch_table(entrypoints)"> 76% for e in entrypoints: 77 % if e.alias: 78 <% continue %> 79 % endif 80 % if e.guard is not None: 81#ifdef ${e.guard} 82 % endif 83 % if e.aliases: 84 union { 85 PFN_vk${e.name} ${e.name}; 86 % for a in e.aliases: 87 PFN_vk${a.name} ${a.name}; 88 % endfor 89 }; 90 % else: 91 PFN_vk${e.name} ${e.name}; 92 % endif 93 % if e.guard is not None: 94#else 95 % if e.aliases: 96 union { 97 PFN_vkVoidFunction ${e.name}; 98 % for a in e.aliases: 99 PFN_vkVoidFunction ${a.name}; 100 % endfor 101 }; 102 % else: 103 PFN_vkVoidFunction ${e.name}; 104 % endif 105#endif 106 % endif 107% endfor 108</%def> 109 110<%def name="entrypoint_table(type, entrypoints)"> 111struct vk_${type}_entrypoint_table { 112% for e in entrypoints: 113 % if e.guard is not None: 114#ifdef ${e.guard} 115 % endif 116 PFN_vk${e.name} ${e.name}; 117 % if e.guard is not None: 118#else 119 PFN_vkVoidFunction ${e.name}; 120# endif 121 % endif 122% endfor 123}; 124</%def> 125 126struct vk_instance_dispatch_table { 127 ${dispatch_table(instance_entrypoints)} 128}; 129 130struct vk_physical_device_dispatch_table { 131 ${dispatch_table(physical_device_entrypoints)} 132}; 133 134struct vk_device_dispatch_table { 135 ${dispatch_table(device_entrypoints)} 136}; 137 138struct vk_dispatch_table { 139 union { 140 struct { 141 struct vk_instance_dispatch_table instance; 142 struct vk_physical_device_dispatch_table physical_device; 143 struct vk_device_dispatch_table device; 144 }; 145 146 struct { 147 ${dispatch_table(instance_entrypoints)} 148 ${dispatch_table(physical_device_entrypoints)} 149 ${dispatch_table(device_entrypoints)} 150 }; 151 }; 152}; 153 154${entrypoint_table('instance', instance_entrypoints)} 155${entrypoint_table('physical_device', physical_device_entrypoints)} 156${entrypoint_table('device', device_entrypoints)} 157 158void 159vk_instance_dispatch_table_load(struct vk_instance_dispatch_table *table, 160 PFN_vkGetInstanceProcAddr gpa, 161 VkInstance instance); 162void 163vk_physical_device_dispatch_table_load(struct vk_physical_device_dispatch_table *table, 164 PFN_vkGetInstanceProcAddr gpa, 165 VkInstance instance); 166void 167vk_device_dispatch_table_load(struct vk_device_dispatch_table *table, 168 PFN_vkGetDeviceProcAddr gpa, 169 VkDevice device); 170 171void vk_instance_dispatch_table_from_entrypoints( 172 struct vk_instance_dispatch_table *dispatch_table, 173 const struct vk_instance_entrypoint_table *entrypoint_table, 174 bool overwrite); 175 176void vk_physical_device_dispatch_table_from_entrypoints( 177 struct vk_physical_device_dispatch_table *dispatch_table, 178 const struct vk_physical_device_entrypoint_table *entrypoint_table, 179 bool overwrite); 180 181void vk_device_dispatch_table_from_entrypoints( 182 struct vk_device_dispatch_table *dispatch_table, 183 const struct vk_device_entrypoint_table *entrypoint_table, 184 bool overwrite); 185 186PFN_vkVoidFunction 187vk_instance_dispatch_table_get(const struct vk_instance_dispatch_table *table, 188 const char *name); 189 190PFN_vkVoidFunction 191vk_physical_device_dispatch_table_get(const struct vk_physical_device_dispatch_table *table, 192 const char *name); 193 194PFN_vkVoidFunction 195vk_device_dispatch_table_get(const struct vk_device_dispatch_table *table, 196 const char *name); 197 198PFN_vkVoidFunction 199vk_instance_dispatch_table_get_if_supported( 200 const struct vk_instance_dispatch_table *table, 201 const char *name, 202 uint32_t core_version, 203 const struct vk_instance_extension_table *instance_exts); 204 205PFN_vkVoidFunction 206vk_physical_device_dispatch_table_get_if_supported( 207 const struct vk_physical_device_dispatch_table *table, 208 const char *name, 209 uint32_t core_version, 210 const struct vk_instance_extension_table *instance_exts); 211 212PFN_vkVoidFunction 213vk_device_dispatch_table_get_if_supported( 214 const struct vk_device_dispatch_table *table, 215 const char *name, 216 uint32_t core_version, 217 const struct vk_instance_extension_table *instance_exts, 218 const struct vk_device_extension_table *device_exts); 219 220extern struct vk_physical_device_dispatch_table vk_physical_device_trampolines; 221extern struct vk_device_dispatch_table vk_device_trampolines; 222 223#ifdef __cplusplus 224} 225#endif 226 227#endif /* VK_DISPATCH_TABLE_H */ 228""") 229 230TEMPLATE_C = Template(COPYRIGHT + """\ 231/* This file generated from ${filename}, don't edit directly. */ 232 233#include "vk_device.h" 234#include "vk_dispatch_table.h" 235#include "vk_instance.h" 236#include "vk_object.h" 237#include "vk_physical_device.h" 238 239#include "util/macros.h" 240#include "string.h" 241 242<%def name="load_dispatch_table(type, VkType, ProcAddr, entrypoints)"> 243void 244vk_${type}_dispatch_table_load(struct vk_${type}_dispatch_table *table, 245 PFN_vk${ProcAddr} gpa, 246 ${VkType} obj) 247{ 248% if type != 'physical_device': 249 table->${ProcAddr} = gpa; 250% endif 251% for e in entrypoints: 252 % if e.alias or e.name == '${ProcAddr}': 253 <% continue %> 254 % endif 255 % if e.guard is not None: 256#ifdef ${e.guard} 257 % endif 258 table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${e.name}"); 259 % for a in e.aliases: 260 if (table->${e.name} == NULL) { 261 table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${a.name}"); 262 } 263 % endfor 264 % if e.guard is not None: 265#endif 266 % endif 267% endfor 268} 269</%def> 270 271${load_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr', 272 instance_entrypoints)} 273 274${load_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr', 275 physical_device_entrypoints)} 276 277${load_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr', 278 device_entrypoints)} 279 280 281struct string_map_entry { 282 uint32_t name; 283 uint32_t hash; 284 uint32_t num; 285}; 286 287/* We use a big string constant to avoid lots of reloctions from the entry 288 * point table to lots of little strings. The entries in the entry point table 289 * store the index into this big string. 290 */ 291 292<%def name="strmap(strmap, prefix)"> 293static const char ${prefix}_strings[] = 294% for s in strmap.sorted_strings: 295 "${s.string}\\0" 296% endfor 297; 298 299static const struct string_map_entry ${prefix}_string_map_entries[] = { 300% for s in strmap.sorted_strings: 301 { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */ 302% endfor 303}; 304 305/* Hash table stats: 306 * size ${len(strmap.sorted_strings)} entries 307 * collisions entries: 308% for i in range(10): 309 * ${i}${'+' if i == 9 else ' '} ${strmap.collisions[i]} 310% endfor 311 */ 312 313#define none 0xffff 314static const uint16_t ${prefix}_string_map[${strmap.hash_size}] = { 315% for e in strmap.mapping: 316 ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' }, 317% endfor 318}; 319 320static int 321${prefix}_string_map_lookup(const char *str) 322{ 323 static const uint32_t prime_factor = ${strmap.prime_factor}; 324 static const uint32_t prime_step = ${strmap.prime_step}; 325 const struct string_map_entry *e; 326 uint32_t hash, h; 327 uint16_t i; 328 const char *p; 329 330 hash = 0; 331 for (p = str; *p; p++) 332 hash = hash * prime_factor + *p; 333 334 h = hash; 335 while (1) { 336 i = ${prefix}_string_map[h & ${strmap.hash_mask}]; 337 if (i == none) 338 return -1; 339 e = &${prefix}_string_map_entries[i]; 340 if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0) 341 return e->num; 342 h += prime_step; 343 } 344 345 return -1; 346} 347</%def> 348 349${strmap(instance_strmap, 'instance')} 350${strmap(physical_device_strmap, 'physical_device')} 351${strmap(device_strmap, 'device')} 352 353<% assert len(instance_entrypoints) < 2**8 %> 354static const uint8_t instance_compaction_table[] = { 355% for e in instance_entrypoints: 356 ${e.disp_table_index}, 357% endfor 358}; 359 360<% assert len(physical_device_entrypoints) < 2**8 %> 361static const uint8_t physical_device_compaction_table[] = { 362% for e in physical_device_entrypoints: 363 ${e.disp_table_index}, 364% endfor 365}; 366 367<% assert len(device_entrypoints) < 2**16 %> 368static const uint16_t device_compaction_table[] = { 369% for e in device_entrypoints: 370 ${e.disp_table_index}, 371% endfor 372}; 373 374static bool 375vk_instance_entrypoint_is_enabled(int index, uint32_t core_version, 376 const struct vk_instance_extension_table *instance) 377{ 378 switch (index) { 379% for e in instance_entrypoints: 380 case ${e.entry_table_index}: 381 /* ${e.name} */ 382 % if e.core_version: 383 return ${e.core_version.c_vk_version()} <= core_version; 384 % elif e.extensions: 385 % for ext in e.extensions: 386 % if ext.type == 'instance': 387 if (instance->${ext.name[3:]}) return true; 388 % else: 389 /* All device extensions are considered enabled at the instance level */ 390 return true; 391 % endif 392 % endfor 393 return false; 394 % else: 395 return true; 396 % endif 397% endfor 398 default: 399 return false; 400 } 401} 402 403/** Return true if the core version or extension in which the given entrypoint 404 * is defined is enabled. 405 * 406 * If device is NULL, all device extensions are considered enabled. 407 */ 408static bool 409vk_physical_device_entrypoint_is_enabled(int index, uint32_t core_version, 410 const struct vk_instance_extension_table *instance) 411{ 412 switch (index) { 413% for e in physical_device_entrypoints: 414 case ${e.entry_table_index}: 415 /* ${e.name} */ 416 % if e.core_version: 417 return ${e.core_version.c_vk_version()} <= core_version; 418 % elif e.extensions: 419 % for ext in e.extensions: 420 % if ext.type == 'instance': 421 if (instance->${ext.name[3:]}) return true; 422 % else: 423 /* All device extensions are considered enabled at the instance level */ 424 return true; 425 % endif 426 % endfor 427 return false; 428 % else: 429 return true; 430 % endif 431% endfor 432 default: 433 return false; 434 } 435} 436 437/** Return true if the core version or extension in which the given entrypoint 438 * is defined is enabled. 439 * 440 * If device is NULL, all device extensions are considered enabled. 441 */ 442static bool 443vk_device_entrypoint_is_enabled(int index, uint32_t core_version, 444 const struct vk_instance_extension_table *instance, 445 const struct vk_device_extension_table *device) 446{ 447 switch (index) { 448% for e in device_entrypoints: 449 case ${e.entry_table_index}: 450 /* ${e.name} */ 451 % if e.core_version: 452 return ${e.core_version.c_vk_version()} <= core_version; 453 % elif e.extensions: 454 % for ext in e.extensions: 455 % if ext.type == 'instance': 456 if (instance->${ext.name[3:]}) return true; 457 % else: 458 if (!device || device->${ext.name[3:]}) return true; 459 % endif 460 % endfor 461 return false; 462 % else: 463 return true; 464 % endif 465% endfor 466 default: 467 return false; 468 } 469} 470 471#ifdef _MSC_VER 472VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void) 473{ 474 unreachable(!"Entrypoint not implemented"); 475} 476#endif 477 478<%def name="dispatch_table_from_entrypoints(type)"> 479void vk_${type}_dispatch_table_from_entrypoints( 480 struct vk_${type}_dispatch_table *dispatch_table, 481 const struct vk_${type}_entrypoint_table *entrypoint_table, 482 bool overwrite) 483{ 484 PFN_vkVoidFunction *disp = (PFN_vkVoidFunction *)dispatch_table; 485 PFN_vkVoidFunction *entry = (PFN_vkVoidFunction *)entrypoint_table; 486 487 if (overwrite) { 488 memset(dispatch_table, 0, sizeof(*dispatch_table)); 489 for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { 490#ifdef _MSC_VER 491 assert(entry[i] != NULL); 492 if (entry[i] == vk_entrypoint_stub) 493#else 494 if (entry[i] == NULL) 495#endif 496 continue; 497 unsigned disp_index = ${type}_compaction_table[i]; 498 assert(disp[disp_index] == NULL); 499 disp[disp_index] = entry[i]; 500 } 501 } else { 502 for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { 503 unsigned disp_index = ${type}_compaction_table[i]; 504#ifdef _MSC_VER 505 assert(entry[i] != NULL); 506 if (disp[disp_index] == NULL && entry[i] != vk_entrypoint_stub) 507#else 508 if (disp[disp_index] == NULL) 509#endif 510 disp[disp_index] = entry[i]; 511 } 512 } 513} 514</%def> 515 516${dispatch_table_from_entrypoints('instance')} 517${dispatch_table_from_entrypoints('physical_device')} 518${dispatch_table_from_entrypoints('device')} 519 520<%def name="lookup_funcs(type)"> 521static PFN_vkVoidFunction 522vk_${type}_dispatch_table_get_for_entry_index( 523 const struct vk_${type}_dispatch_table *table, int entry_index) 524{ 525 assert(entry_index < ARRAY_SIZE(${type}_compaction_table)); 526 int disp_index = ${type}_compaction_table[entry_index]; 527 return ((PFN_vkVoidFunction *)table)[disp_index]; 528} 529 530PFN_vkVoidFunction 531vk_${type}_dispatch_table_get( 532 const struct vk_${type}_dispatch_table *table, const char *name) 533{ 534 int entry_index = ${type}_string_map_lookup(name); 535 if (entry_index < 0) 536 return NULL; 537 538 return vk_${type}_dispatch_table_get_for_entry_index(table, entry_index); 539} 540</%def> 541 542${lookup_funcs('instance')} 543${lookup_funcs('physical_device')} 544${lookup_funcs('device')} 545 546PFN_vkVoidFunction 547vk_instance_dispatch_table_get_if_supported( 548 const struct vk_instance_dispatch_table *table, 549 const char *name, 550 uint32_t core_version, 551 const struct vk_instance_extension_table *instance_exts) 552{ 553 int entry_index = instance_string_map_lookup(name); 554 if (entry_index < 0) 555 return NULL; 556 557 if (!vk_instance_entrypoint_is_enabled(entry_index, core_version, 558 instance_exts)) 559 return NULL; 560 561 return vk_instance_dispatch_table_get_for_entry_index(table, entry_index); 562} 563 564PFN_vkVoidFunction 565vk_physical_device_dispatch_table_get_if_supported( 566 const struct vk_physical_device_dispatch_table *table, 567 const char *name, 568 uint32_t core_version, 569 const struct vk_instance_extension_table *instance_exts) 570{ 571 int entry_index = physical_device_string_map_lookup(name); 572 if (entry_index < 0) 573 return NULL; 574 575 if (!vk_physical_device_entrypoint_is_enabled(entry_index, core_version, 576 instance_exts)) 577 return NULL; 578 579 return vk_physical_device_dispatch_table_get_for_entry_index(table, entry_index); 580} 581 582PFN_vkVoidFunction 583vk_device_dispatch_table_get_if_supported( 584 const struct vk_device_dispatch_table *table, 585 const char *name, 586 uint32_t core_version, 587 const struct vk_instance_extension_table *instance_exts, 588 const struct vk_device_extension_table *device_exts) 589{ 590 int entry_index = device_string_map_lookup(name); 591 if (entry_index < 0) 592 return NULL; 593 594 if (!vk_device_entrypoint_is_enabled(entry_index, core_version, 595 instance_exts, device_exts)) 596 return NULL; 597 598 return vk_device_dispatch_table_get_for_entry_index(table, entry_index); 599} 600 601% for e in physical_device_entrypoints: 602 % if e.alias: 603 <% continue %> 604 % endif 605 % if e.guard is not None: 606#ifdef ${e.guard} 607 % endif 608static VKAPI_ATTR ${e.return_type} VKAPI_CALL 609${e.prefixed_name('vk_tramp')}(${e.decl_params()}) 610{ 611 <% assert e.params[0].type == 'VkPhysicalDevice' %> 612 VK_FROM_HANDLE(vk_physical_device, vk_physical_device, ${e.params[0].name}); 613 % if e.return_type == 'void': 614 vk_physical_device->dispatch_table.${e.name}(${e.call_params()}); 615 % else: 616 return vk_physical_device->dispatch_table.${e.name}(${e.call_params()}); 617 % endif 618} 619 % if e.guard is not None: 620#endif 621 % endif 622% endfor 623 624struct vk_physical_device_dispatch_table vk_physical_device_trampolines = { 625% for e in physical_device_entrypoints: 626 % if e.alias: 627 <% continue %> 628 % endif 629 % if e.guard is not None: 630#ifdef ${e.guard} 631 % endif 632 .${e.name} = ${e.prefixed_name('vk_tramp')}, 633 % if e.guard is not None: 634#endif 635 % endif 636% endfor 637}; 638 639% for e in device_entrypoints: 640 % if e.alias: 641 <% continue %> 642 % endif 643 % if e.guard is not None: 644#ifdef ${e.guard} 645 % endif 646static VKAPI_ATTR ${e.return_type} VKAPI_CALL 647${e.prefixed_name('vk_tramp')}(${e.decl_params()}) 648{ 649 % if e.params[0].type == 'VkDevice': 650 VK_FROM_HANDLE(vk_device, vk_device, ${e.params[0].name}); 651 % if e.return_type == 'void': 652 vk_device->dispatch_table.${e.name}(${e.call_params()}); 653 % else: 654 return vk_device->dispatch_table.${e.name}(${e.call_params()}); 655 % endif 656 % elif e.params[0].type in ('VkCommandBuffer', 'VkQueue'): 657 struct vk_object_base *vk_object = (struct vk_object_base *)${e.params[0].name}; 658 % if e.return_type == 'void': 659 vk_object->device->dispatch_table.${e.name}(${e.call_params()}); 660 % else: 661 return vk_object->device->dispatch_table.${e.name}(${e.call_params()}); 662 % endif 663 % else: 664 assert(!"Unhandled device child trampoline case: ${e.params[0].type}"); 665 % endif 666} 667 % if e.guard is not None: 668#endif 669 % endif 670% endfor 671 672struct vk_device_dispatch_table vk_device_trampolines = { 673% for e in device_entrypoints: 674 % if e.alias: 675 <% continue %> 676 % endif 677 % if e.guard is not None: 678#ifdef ${e.guard} 679 % endif 680 .${e.name} = ${e.prefixed_name('vk_tramp')}, 681 % if e.guard is not None: 682#endif 683 % endif 684% endfor 685}; 686""") 687 688U32_MASK = 2**32 - 1 689 690PRIME_FACTOR = 5024183 691PRIME_STEP = 19 692 693class StringIntMapEntry(object): 694 def __init__(self, string, num): 695 self.string = string 696 self.num = num 697 698 # Calculate the same hash value that we will calculate in C. 699 h = 0 700 for c in string: 701 h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK 702 self.hash = h 703 704 self.offset = None 705 706def round_to_pow2(x): 707 return 2**int(math.ceil(math.log(x, 2))) 708 709class StringIntMap(object): 710 def __init__(self): 711 self.baked = False 712 self.strings = dict() 713 714 def add_string(self, string, num): 715 assert not self.baked 716 assert string not in self.strings 717 assert 0 <= num < 2**31 718 self.strings[string] = StringIntMapEntry(string, num) 719 720 def bake(self): 721 self.sorted_strings = \ 722 sorted(self.strings.values(), key=lambda x: x.string) 723 offset = 0 724 for entry in self.sorted_strings: 725 entry.offset = offset 726 offset += len(entry.string) + 1 727 728 # Save off some values that we'll need in C 729 self.hash_size = round_to_pow2(len(self.strings) * 1.25) 730 self.hash_mask = self.hash_size - 1 731 self.prime_factor = PRIME_FACTOR 732 self.prime_step = PRIME_STEP 733 734 self.mapping = [-1] * self.hash_size 735 self.collisions = [0] * 10 736 for idx, s in enumerate(self.sorted_strings): 737 level = 0 738 h = s.hash 739 while self.mapping[h & self.hash_mask] >= 0: 740 h = h + PRIME_STEP 741 level = level + 1 742 self.collisions[min(level, 9)] += 1 743 self.mapping[h & self.hash_mask] = idx 744 745EntrypointParam = namedtuple('EntrypointParam', 'type name decl len') 746 747class EntrypointBase(object): 748 def __init__(self, name): 749 assert name.startswith('vk') 750 self.name = name[2:] 751 self.alias = None 752 self.guard = None 753 self.entry_table_index = None 754 # Extensions which require this entrypoint 755 self.core_version = None 756 self.extensions = [] 757 758 def prefixed_name(self, prefix): 759 return prefix + '_' + self.name 760 761class Entrypoint(EntrypointBase): 762 def __init__(self, name, return_type, params, guard=None): 763 super(Entrypoint, self).__init__(name) 764 self.return_type = return_type 765 self.params = params 766 self.guard = guard 767 self.aliases = [] 768 self.disp_table_index = None 769 770 def is_physical_device_entrypoint(self): 771 return self.params[0].type in ('VkPhysicalDevice', ) 772 773 def is_device_entrypoint(self): 774 return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue') 775 776 def decl_params(self): 777 return ', '.join(p.decl for p in self.params) 778 779 def call_params(self): 780 return ', '.join(p.name for p in self.params) 781 782class EntrypointAlias(EntrypointBase): 783 def __init__(self, name, entrypoint): 784 super(EntrypointAlias, self).__init__(name) 785 self.alias = entrypoint 786 entrypoint.aliases.append(self) 787 788 def is_physical_device_entrypoint(self): 789 return self.alias.is_physical_device_entrypoint() 790 791 def is_device_entrypoint(self): 792 return self.alias.is_device_entrypoint() 793 794 def prefixed_name(self, prefix): 795 return self.alias.prefixed_name(prefix) 796 797 @property 798 def params(self): 799 return self.alias.params 800 801 @property 802 def return_type(self): 803 return self.alias.return_type 804 805 @property 806 def disp_table_index(self): 807 return self.alias.disp_table_index 808 809 def decl_params(self): 810 return self.alias.decl_params() 811 812 def call_params(self): 813 return self.alias.call_params() 814 815def get_entrypoints(doc, entrypoints_to_defines): 816 """Extract the entry points from the registry.""" 817 entrypoints = OrderedDict() 818 819 for command in doc.findall('./commands/command'): 820 if 'alias' in command.attrib: 821 alias = command.attrib['name'] 822 target = command.attrib['alias'] 823 entrypoints[alias] = EntrypointAlias(alias, entrypoints[target]) 824 else: 825 name = command.find('./proto/name').text 826 ret_type = command.find('./proto/type').text 827 params = [EntrypointParam( 828 type=p.find('./type').text, 829 name=p.find('./name').text, 830 decl=''.join(p.itertext()), 831 len=p.attrib.get('len', None) 832 ) for p in command.findall('./param')] 833 guard = entrypoints_to_defines.get(name) 834 # They really need to be unique 835 assert name not in entrypoints 836 entrypoints[name] = Entrypoint(name, ret_type, params, guard) 837 838 for feature in doc.findall('./feature'): 839 assert feature.attrib['api'] == 'vulkan' 840 version = VkVersion(feature.attrib['number']) 841 for command in feature.findall('./require/command'): 842 e = entrypoints[command.attrib['name']] 843 assert e.core_version is None 844 e.core_version = version 845 846 for extension in doc.findall('.extensions/extension'): 847 if extension.attrib['supported'] != 'vulkan': 848 continue 849 850 ext_name = extension.attrib['name'] 851 852 ext = Extension(ext_name, 1, True) 853 ext.type = extension.attrib['type'] 854 855 for command in extension.findall('./require/command'): 856 e = entrypoints[command.attrib['name']] 857 assert e.core_version is None 858 e.extensions.append(ext) 859 860 return entrypoints.values() 861 862 863def get_entrypoints_defines(doc): 864 """Maps entry points to extension defines.""" 865 entrypoints_to_defines = {} 866 867 platform_define = {} 868 for platform in doc.findall('./platforms/platform'): 869 name = platform.attrib['name'] 870 define = platform.attrib['protect'] 871 platform_define[name] = define 872 873 for extension in doc.findall('./extensions/extension[@platform]'): 874 platform = extension.attrib['platform'] 875 define = platform_define[platform] 876 877 for entrypoint in extension.findall('./require/command'): 878 fullname = entrypoint.attrib['name'] 879 entrypoints_to_defines[fullname] = define 880 881 return entrypoints_to_defines 882 883def get_entrypoints_from_xml(xml_files): 884 entrypoints = [] 885 886 for filename in xml_files: 887 doc = et.parse(filename) 888 entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc)) 889 890 return entrypoints 891 892def main(): 893 parser = argparse.ArgumentParser() 894 parser.add_argument('--out-c', help='Output C file.') 895 parser.add_argument('--out-h', help='Output H file.') 896 parser.add_argument('--xml', 897 help='Vulkan API XML file.', 898 required=True, 899 action='append', 900 dest='xml_files') 901 args = parser.parse_args() 902 903 entrypoints = get_entrypoints_from_xml(args.xml_files) 904 905 device_entrypoints = [] 906 physical_device_entrypoints = [] 907 instance_entrypoints = [] 908 for e in entrypoints: 909 if e.is_device_entrypoint(): 910 device_entrypoints.append(e) 911 elif e.is_physical_device_entrypoint(): 912 physical_device_entrypoints.append(e) 913 else: 914 instance_entrypoints.append(e) 915 916 for i, e in enumerate(e for e in device_entrypoints if not e.alias): 917 e.disp_table_index = i 918 919 device_strmap = StringIntMap() 920 for i, e in enumerate(device_entrypoints): 921 e.entry_table_index = i 922 device_strmap.add_string("vk" + e.name, e.entry_table_index) 923 device_strmap.bake() 924 925 for i, e in enumerate(e for e in physical_device_entrypoints if not e.alias): 926 e.disp_table_index = i 927 928 physical_device_strmap = StringIntMap() 929 for i, e in enumerate(physical_device_entrypoints): 930 e.entry_table_index = i 931 physical_device_strmap.add_string("vk" + e.name, e.entry_table_index) 932 physical_device_strmap.bake() 933 934 for i, e in enumerate(e for e in instance_entrypoints if not e.alias): 935 e.disp_table_index = i 936 937 instance_strmap = StringIntMap() 938 for i, e in enumerate(instance_entrypoints): 939 e.entry_table_index = i 940 instance_strmap.add_string("vk" + e.name, e.entry_table_index) 941 instance_strmap.bake() 942 943 # For outputting entrypoints.h we generate a anv_EntryPoint() prototype 944 # per entry point. 945 try: 946 if args.out_h: 947 with open(args.out_h, 'w') as f: 948 f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints, 949 physical_device_entrypoints=physical_device_entrypoints, 950 device_entrypoints=device_entrypoints, 951 filename=os.path.basename(__file__))) 952 if args.out_c: 953 with open(args.out_c, 'w') as f: 954 f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints, 955 physical_device_entrypoints=physical_device_entrypoints, 956 device_entrypoints=device_entrypoints, 957 instance_strmap=instance_strmap, 958 physical_device_strmap=physical_device_strmap, 959 device_strmap=device_strmap, 960 filename=os.path.basename(__file__))) 961 except Exception: 962 # In the event there's an error, this imports some helpers from mako 963 # to print a useful stack trace and prints it, then exits with 964 # status 1, if python is run with debug; otherwise it just raises 965 # the exception 966 if __debug__: 967 import sys 968 from mako import exceptions 969 sys.stderr.write(exceptions.text_error_template().render() + '\n') 970 sys.exit(1) 971 raise 972 973 974if __name__ == '__main__': 975 main() 976