• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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