1# coding=utf-8
2#
3# Copyright © 2015, 2017 Intel Corporation
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9# and/or sell copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice (including the next
13# paragraph) shall be included in all copies or substantial portions of the
14# Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23#
24
25import argparse
26import math
27import os
28import xml.etree.ElementTree as et
29
30from collections import OrderedDict, namedtuple
31from mako.template import Template
32
33from anv_extensions import VkVersion, MAX_API_VERSION, EXTENSIONS
34
35# We generate a static hash table for entry point lookup
36# (vkGetProcAddress). We use a linear congruential generator for our hash
37# function and a power-of-two size table. The prime numbers are determined
38# experimentally.
39
40LAYERS = [
41    'anv',
42    'gen7',
43    'gen75',
44    'gen8',
45    'gen9',
46    'gen11',
47    'gen12',
48]
49
50TEMPLATE_H = Template("""\
51/* This file generated from ${filename}, don't edit directly. */
52
53struct anv_instance_dispatch_table {
54   union {
55      void *entrypoints[${len(instance_entrypoints)}];
56      struct {
57      % for e in instance_entrypoints:
58        % if e.guard is not None:
59#ifdef ${e.guard}
60          PFN_${e.name} ${e.name};
61#else
62          void *${e.name};
63# endif
64        % else:
65          PFN_${e.name} ${e.name};
66        % endif
67      % endfor
68      };
69   };
70};
71
72struct anv_physical_device_dispatch_table {
73   union {
74      void *entrypoints[${len(physical_device_entrypoints)}];
75      struct {
76      % for e in physical_device_entrypoints:
77        % if e.guard is not None:
78#ifdef ${e.guard}
79          PFN_${e.name} ${e.name};
80#else
81          void *${e.name};
82# endif
83        % else:
84          PFN_${e.name} ${e.name};
85        % endif
86      % endfor
87      };
88   };
89};
90
91struct anv_device_dispatch_table {
92   union {
93      void *entrypoints[${len(device_entrypoints)}];
94      struct {
95      % for e in device_entrypoints:
96        % if e.guard is not None:
97#ifdef ${e.guard}
98          PFN_${e.name} ${e.name};
99#else
100          void *${e.name};
101# endif
102        % else:
103          PFN_${e.name} ${e.name};
104        % endif
105      % endfor
106      };
107   };
108};
109
110extern const struct anv_instance_dispatch_table anv_instance_dispatch_table;
111%for layer in LAYERS:
112extern const struct anv_physical_device_dispatch_table ${layer}_physical_device_dispatch_table;
113%endfor
114%for layer in LAYERS:
115extern const struct anv_device_dispatch_table ${layer}_device_dispatch_table;
116%endfor
117
118% for e in instance_entrypoints:
119  % if e.alias and e.alias.enabled:
120    <% continue %>
121  % endif
122  % if e.guard is not None:
123#ifdef ${e.guard}
124  % endif
125  ${e.return_type} ${e.prefixed_name('anv')}(${e.decl_params()});
126  % if e.guard is not None:
127#endif // ${e.guard}
128  % endif
129% endfor
130
131% for e in physical_device_entrypoints:
132  % if e.alias:
133    <% continue %>
134  % endif
135  % if e.guard is not None:
136#ifdef ${e.guard}
137  % endif
138  % for layer in LAYERS:
139  ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
140  % endfor
141  % if e.guard is not None:
142#endif // ${e.guard}
143  % endif
144% endfor
145
146% for e in device_entrypoints:
147  % if e.alias and e.alias.enabled:
148    <% continue %>
149  % endif
150  % if e.guard is not None:
151#ifdef ${e.guard}
152  % endif
153  % for layer in LAYERS:
154  ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
155  % endfor
156  % if e.guard is not None:
157#endif // ${e.guard}
158  % endif
159% endfor
160""", output_encoding='utf-8')
161
162TEMPLATE_C = Template(u"""\
163/*
164 * Copyright © 2015 Intel Corporation
165 *
166 * Permission is hereby granted, free of charge, to any person obtaining a
167 * copy of this software and associated documentation files (the "Software"),
168 * to deal in the Software without restriction, including without limitation
169 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
170 * and/or sell copies of the Software, and to permit persons to whom the
171 * Software is furnished to do so, subject to the following conditions:
172 *
173 * The above copyright notice and this permission notice (including the next
174 * paragraph) shall be included in all copies or substantial portions of the
175 * Software.
176 *
177 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
179 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
180 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
181 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
182 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
183 * IN THE SOFTWARE.
184 */
185
186/* This file generated from ${filename}, don't edit directly. */
187
188#include "anv_private.h"
189
190#include "util/macros.h"
191
192struct string_map_entry {
193   uint32_t name;
194   uint32_t hash;
195   uint32_t num;
196};
197
198/* We use a big string constant to avoid lots of reloctions from the entry
199 * point table to lots of little strings. The entries in the entry point table
200 * store the index into this big string.
201 */
202
203<%def name="strmap(strmap, prefix)">
204static const char ${prefix}_strings[] =
205% for s in strmap.sorted_strings:
206    "${s.string}\\0"
207% endfor
208;
209
210static const struct string_map_entry ${prefix}_string_map_entries[] = {
211% for s in strmap.sorted_strings:
212    { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */
213% endfor
214};
215
216/* Hash table stats:
217 * size ${len(strmap.sorted_strings)} entries
218 * collisions entries:
219% for i in range(10):
220 *     ${i}${'+' if i == 9 else ' '}     ${strmap.collisions[i]}
221% endfor
222 */
223
224#define none 0xffff
225static const uint16_t ${prefix}_string_map[${strmap.hash_size}] = {
226% for e in strmap.mapping:
227    ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },
228% endfor
229};
230
231static int
232${prefix}_string_map_lookup(const char *str)
233{
234    static const uint32_t prime_factor = ${strmap.prime_factor};
235    static const uint32_t prime_step = ${strmap.prime_step};
236    const struct string_map_entry *e;
237    uint32_t hash, h;
238    uint16_t i;
239    const char *p;
240
241    hash = 0;
242    for (p = str; *p; p++)
243        hash = hash * prime_factor + *p;
244
245    h = hash;
246    while (1) {
247        i = ${prefix}_string_map[h & ${strmap.hash_mask}];
248        if (i == none)
249           return -1;
250        e = &${prefix}_string_map_entries[i];
251        if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0)
252            return e->num;
253        h += prime_step;
254    }
255
256    return -1;
257}
258
259static const char *
260${prefix}_entry_name(int num)
261{
262   for (int i = 0; i < ARRAY_SIZE(${prefix}_string_map_entries); i++) {
263      if (${prefix}_string_map_entries[i].num == num)
264         return &${prefix}_strings[${prefix}_string_map_entries[i].name];
265   }
266   return NULL;
267}
268</%def>
269
270${strmap(instance_strmap, 'instance')}
271${strmap(physical_device_strmap, 'physical_device')}
272${strmap(device_strmap, 'device')}
273
274/* Weak aliases for all potential implementations. These will resolve to
275 * NULL if they're not defined, which lets the resolve_entrypoint() function
276 * either pick the correct entry point.
277 */
278
279% for e in instance_entrypoints:
280  % if e.alias and e.alias.enabled:
281    <% continue %>
282  % endif
283  % if e.guard is not None:
284#ifdef ${e.guard}
285  % endif
286  ${e.return_type} ${e.prefixed_name('anv')}(${e.decl_params()}) __attribute__ ((weak));
287  % if e.guard is not None:
288#endif // ${e.guard}
289  % endif
290% endfor
291
292const struct anv_instance_dispatch_table anv_instance_dispatch_table = {
293% for e in instance_entrypoints:
294  % if e.guard is not None:
295#ifdef ${e.guard}
296  % endif
297  .${e.name} = ${e.prefixed_name('anv')},
298  % if e.guard is not None:
299#endif // ${e.guard}
300  % endif
301% endfor
302};
303
304% for e in physical_device_entrypoints:
305  % if e.alias and e.alias.enabled:
306    <% continue %>
307  % endif
308  % if e.guard is not None:
309#ifdef ${e.guard}
310  % endif
311  ${e.return_type} ${e.prefixed_name('anv')}(${e.decl_params()}) __attribute__ ((weak));
312  % if e.guard is not None:
313#endif // ${e.guard}
314  % endif
315% endfor
316
317const struct anv_physical_device_dispatch_table anv_physical_device_dispatch_table = {
318% for e in physical_device_entrypoints:
319  % if e.guard is not None:
320#ifdef ${e.guard}
321  % endif
322  .${e.name} = ${e.prefixed_name('anv')},
323  % if e.guard is not None:
324#endif // ${e.guard}
325  % endif
326% endfor
327};
328
329
330% for layer in LAYERS:
331  % for e in device_entrypoints:
332    % if e.alias and e.alias.enabled:
333      <% continue %>
334    % endif
335    % if e.guard is not None:
336#ifdef ${e.guard}
337    % endif
338    % if layer == 'anv':
339      ${e.return_type} __attribute__ ((weak))
340      ${e.prefixed_name('anv')}(${e.decl_params()})
341      {
342        % if e.params[0].type == 'VkDevice':
343          ANV_FROM_HANDLE(anv_device, anv_device, ${e.params[0].name});
344          return anv_device->dispatch.${e.name}(${e.call_params()});
345        % elif e.params[0].type == 'VkCommandBuffer':
346          ANV_FROM_HANDLE(anv_cmd_buffer, anv_cmd_buffer, ${e.params[0].name});
347          return anv_cmd_buffer->device->dispatch.${e.name}(${e.call_params()});
348        % elif e.params[0].type == 'VkQueue':
349          ANV_FROM_HANDLE(anv_queue, anv_queue, ${e.params[0].name});
350          return anv_queue->device->dispatch.${e.name}(${e.call_params()});
351        % else:
352          assert(!"Unhandled device child trampoline case: ${e.params[0].type}");
353        % endif
354      }
355    % else:
356      ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak));
357    % endif
358    % if e.guard is not None:
359#endif // ${e.guard}
360    % endif
361  % endfor
362
363  const struct anv_device_dispatch_table ${layer}_device_dispatch_table = {
364  % for e in device_entrypoints:
365    % if e.guard is not None:
366#ifdef ${e.guard}
367    % endif
368    .${e.name} = ${e.prefixed_name(layer)},
369    % if e.guard is not None:
370#endif // ${e.guard}
371    % endif
372  % endfor
373  };
374% endfor
375
376
377/** Return true if the core version or extension in which the given entrypoint
378 * is defined is enabled.
379 *
380 * If device is NULL, all device extensions are considered enabled.
381 */
382bool
383anv_instance_entrypoint_is_enabled(int index, uint32_t core_version,
384                                   const struct anv_instance_extension_table *instance)
385{
386   switch (index) {
387% for e in instance_entrypoints:
388   case ${e.num}:
389      /* ${e.name} */
390   % if e.core_version:
391      return ${e.core_version.c_vk_version()} <= core_version;
392   % elif e.extensions:
393     % for ext in e.extensions:
394        % if ext.type == 'instance':
395      if (instance->${ext.name[3:]}) return true;
396        % else:
397      /* All device extensions are considered enabled at the instance level */
398      return true;
399        % endif
400     % endfor
401      return false;
402   % else:
403      return true;
404   % endif
405% endfor
406   default:
407      return false;
408   }
409}
410
411/** Return true if the core version or extension in which the given entrypoint
412 * is defined is enabled.
413 *
414 * If device is NULL, all device extensions are considered enabled.
415 */
416bool
417anv_physical_device_entrypoint_is_enabled(int index, uint32_t core_version,
418                                          const struct anv_instance_extension_table *instance)
419{
420   switch (index) {
421% for e in physical_device_entrypoints:
422   case ${e.num}:
423      /* ${e.name} */
424   % if e.core_version:
425      return ${e.core_version.c_vk_version()} <= core_version;
426   % elif e.extensions:
427     % for ext in e.extensions:
428        % if ext.type == 'instance':
429      if (instance->${ext.name[3:]}) return true;
430        % else:
431      /* All device extensions are considered enabled at the instance level */
432      return true;
433        % endif
434     % endfor
435      return false;
436   % else:
437      return true;
438   % endif
439% endfor
440   default:
441      return false;
442   }
443}
444
445/** Return true if the core version or extension in which the given entrypoint
446 * is defined is enabled.
447 *
448 * If device is NULL, all device extensions are considered enabled.
449 */
450bool
451anv_device_entrypoint_is_enabled(int index, uint32_t core_version,
452                                 const struct anv_instance_extension_table *instance,
453                                 const struct anv_device_extension_table *device)
454{
455   switch (index) {
456% for e in device_entrypoints:
457   case ${e.num}:
458      /* ${e.name} */
459   % if e.core_version:
460      return ${e.core_version.c_vk_version()} <= core_version;
461   % elif e.extensions:
462     % for ext in e.extensions:
463        % if ext.type == 'instance':
464           <% assert False %>
465        % else:
466      if (!device || device->${ext.name[3:]}) return true;
467        % endif
468     % endfor
469      return false;
470   % else:
471      return true;
472   % endif
473% endfor
474   default:
475      return false;
476   }
477}
478
479int
480anv_get_instance_entrypoint_index(const char *name)
481{
482   return instance_string_map_lookup(name);
483}
484
485int
486anv_get_physical_device_entrypoint_index(const char *name)
487{
488   return physical_device_string_map_lookup(name);
489}
490
491int
492anv_get_device_entrypoint_index(const char *name)
493{
494   return device_string_map_lookup(name);
495}
496
497const char *
498anv_get_instance_entry_name(int index)
499{
500   return instance_entry_name(index);
501}
502
503const char *
504anv_get_physical_device_entry_name(int index)
505{
506   return physical_device_entry_name(index);
507}
508
509const char *
510anv_get_device_entry_name(int index)
511{
512   return device_entry_name(index);
513}
514
515void * __attribute__ ((noinline))
516anv_resolve_device_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
517{
518   const struct anv_device_dispatch_table *genX_table;
519   switch (devinfo->gen) {
520   case 12:
521      genX_table = &gen12_device_dispatch_table;
522      break;
523   case 11:
524      genX_table = &gen11_device_dispatch_table;
525      break;
526   case 9:
527      genX_table = &gen9_device_dispatch_table;
528      break;
529   case 8:
530      genX_table = &gen8_device_dispatch_table;
531      break;
532   case 7:
533      if (devinfo->is_haswell)
534         genX_table = &gen75_device_dispatch_table;
535      else
536         genX_table = &gen7_device_dispatch_table;
537      break;
538   default:
539      unreachable("unsupported gen\\n");
540   }
541
542   if (genX_table->entrypoints[index])
543      return genX_table->entrypoints[index];
544   else
545      return anv_device_dispatch_table.entrypoints[index];
546}
547
548void *
549anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
550{
551   int idx = anv_get_instance_entrypoint_index(name);
552   if (idx >= 0)
553      return anv_instance_dispatch_table.entrypoints[idx];
554
555   idx = anv_get_physical_device_entrypoint_index(name);
556   if (idx >= 0)
557      return anv_physical_device_dispatch_table.entrypoints[idx];
558
559   idx = anv_get_device_entrypoint_index(name);
560   if (idx >= 0)
561      return anv_resolve_device_entrypoint(devinfo, idx);
562
563   return NULL;
564}""", output_encoding='utf-8')
565
566U32_MASK = 2**32 - 1
567
568PRIME_FACTOR = 5024183
569PRIME_STEP = 19
570
571class StringIntMapEntry(object):
572    def __init__(self, string, num):
573        self.string = string
574        self.num = num
575
576        # Calculate the same hash value that we will calculate in C.
577        h = 0
578        for c in string:
579            h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
580        self.hash = h
581
582        self.offset = None
583
584def round_to_pow2(x):
585    return 2**int(math.ceil(math.log(x, 2)))
586
587class StringIntMap(object):
588    def __init__(self):
589        self.baked = False
590        self.strings = dict()
591
592    def add_string(self, string, num):
593        assert not self.baked
594        assert string not in self.strings
595        assert 0 <= num < 2**31
596        self.strings[string] = StringIntMapEntry(string, num)
597
598    def bake(self):
599        self.sorted_strings = \
600            sorted(self.strings.values(), key=lambda x: x.string)
601        offset = 0
602        for entry in self.sorted_strings:
603            entry.offset = offset
604            offset += len(entry.string) + 1
605
606        # Save off some values that we'll need in C
607        self.hash_size = round_to_pow2(len(self.strings) * 1.25)
608        self.hash_mask = self.hash_size - 1
609        self.prime_factor = PRIME_FACTOR
610        self.prime_step = PRIME_STEP
611
612        self.mapping = [-1] * self.hash_size
613        self.collisions = [0] * 10
614        for idx, s in enumerate(self.sorted_strings):
615            level = 0
616            h = s.hash
617            while self.mapping[h & self.hash_mask] >= 0:
618                h = h + PRIME_STEP
619                level = level + 1
620            self.collisions[min(level, 9)] += 1
621            self.mapping[h & self.hash_mask] = idx
622
623EntrypointParam = namedtuple('EntrypointParam', 'type name decl')
624
625class EntrypointBase(object):
626    def __init__(self, name):
627        self.name = name
628        self.alias = None
629        self.guard = None
630        self.enabled = False
631        self.num = None
632        # Extensions which require this entrypoint
633        self.core_version = None
634        self.extensions = []
635
636    def prefixed_name(self, prefix):
637        assert self.name.startswith('vk')
638        return prefix + '_' + self.name[2:]
639
640class Entrypoint(EntrypointBase):
641    def __init__(self, name, return_type, params, guard=None):
642        super(Entrypoint, self).__init__(name)
643        self.return_type = return_type
644        self.params = params
645        self.guard = guard
646
647    def is_physical_device_entrypoint(self):
648        return self.params[0].type in ('VkPhysicalDevice', )
649
650    def is_device_entrypoint(self):
651        return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue')
652
653    def decl_params(self):
654        return ', '.join(p.decl for p in self.params)
655
656    def call_params(self):
657        return ', '.join(p.name for p in self.params)
658
659class EntrypointAlias(EntrypointBase):
660    def __init__(self, name, entrypoint):
661        super(EntrypointAlias, self).__init__(name)
662        self.alias = entrypoint
663
664    def is_physical_device_entrypoint(self):
665        return self.alias.is_physical_device_entrypoint()
666
667    def is_device_entrypoint(self):
668        return self.alias.is_device_entrypoint()
669
670    def prefixed_name(self, prefix):
671        if self.alias.enabled:
672            return self.alias.prefixed_name(prefix)
673        return super(EntrypointAlias, self).prefixed_name(prefix)
674
675    @property
676    def params(self):
677        return self.alias.params
678
679    @property
680    def return_type(self):
681        return self.alias.return_type
682
683    def decl_params(self):
684        return self.alias.decl_params()
685
686    def call_params(self):
687        return self.alias.call_params()
688
689def get_entrypoints(doc, entrypoints_to_defines):
690    """Extract the entry points from the registry."""
691    entrypoints = OrderedDict()
692
693    for command in doc.findall('./commands/command'):
694        if 'alias' in command.attrib:
695            alias = command.attrib['name']
696            target = command.attrib['alias']
697            entrypoints[alias] = EntrypointAlias(alias, entrypoints[target])
698        else:
699            name = command.find('./proto/name').text
700            ret_type = command.find('./proto/type').text
701            params = [EntrypointParam(
702                type=p.find('./type').text,
703                name=p.find('./name').text,
704                decl=''.join(p.itertext())
705            ) for p in command.findall('./param')]
706            guard = entrypoints_to_defines.get(name)
707            # They really need to be unique
708            assert name not in entrypoints
709            entrypoints[name] = Entrypoint(name, ret_type, params, guard)
710
711    for feature in doc.findall('./feature'):
712        assert feature.attrib['api'] == 'vulkan'
713        version = VkVersion(feature.attrib['number'])
714        if version > MAX_API_VERSION:
715            continue
716
717        for command in feature.findall('./require/command'):
718            e = entrypoints[command.attrib['name']]
719            e.enabled = True
720            assert e.core_version is None
721            e.core_version = version
722
723    supported_exts = dict((ext.name, ext) for ext in EXTENSIONS)
724    for extension in doc.findall('.extensions/extension'):
725        ext_name = extension.attrib['name']
726        if ext_name not in supported_exts:
727            continue
728
729        ext = supported_exts[ext_name]
730        ext.type = extension.attrib['type']
731
732        for command in extension.findall('./require/command'):
733            e = entrypoints[command.attrib['name']]
734            e.enabled = True
735            assert e.core_version is None
736            e.extensions.append(ext)
737
738    return [e for e in entrypoints.values() if e.enabled]
739
740
741def get_entrypoints_defines(doc):
742    """Maps entry points to extension defines."""
743    entrypoints_to_defines = {}
744
745    platform_define = {}
746    for platform in doc.findall('./platforms/platform'):
747        name = platform.attrib['name']
748        define = platform.attrib['protect']
749        platform_define[name] = define
750
751    for extension in doc.findall('./extensions/extension[@platform]'):
752        platform = extension.attrib['platform']
753        define = platform_define[platform]
754
755        for entrypoint in extension.findall('./require/command'):
756            fullname = entrypoint.attrib['name']
757            entrypoints_to_defines[fullname] = define
758
759    return entrypoints_to_defines
760
761
762def main():
763    parser = argparse.ArgumentParser()
764    parser.add_argument('--outdir', help='Where to write the files.',
765                        required=True)
766    parser.add_argument('--xml',
767                        help='Vulkan API XML file.',
768                        required=True,
769                        action='append',
770                        dest='xml_files')
771    args = parser.parse_args()
772
773    entrypoints = []
774
775    for filename in args.xml_files:
776        doc = et.parse(filename)
777        entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc))
778
779    # Manually add CreateDmaBufImageINTEL for which we don't have an extension
780    # defined.
781    entrypoints.append(Entrypoint('vkCreateDmaBufImageINTEL', 'VkResult', [
782        EntrypointParam('VkDevice', 'device', 'VkDevice device'),
783        EntrypointParam('VkDmaBufImageCreateInfo', 'pCreateInfo',
784                        'const VkDmaBufImageCreateInfo* pCreateInfo'),
785        EntrypointParam('VkAllocationCallbacks', 'pAllocator',
786                        'const VkAllocationCallbacks* pAllocator'),
787        EntrypointParam('VkDeviceMemory', 'pMem', 'VkDeviceMemory* pMem'),
788        EntrypointParam('VkImage', 'pImage', 'VkImage* pImage')
789    ]))
790
791    device_entrypoints = []
792    physical_device_entrypoints = []
793    instance_entrypoints = []
794    for e in entrypoints:
795        if e.is_device_entrypoint():
796            device_entrypoints.append(e)
797        elif e.is_physical_device_entrypoint():
798            physical_device_entrypoints.append(e)
799        else:
800            instance_entrypoints.append(e)
801
802    device_strmap = StringIntMap()
803    for num, e in enumerate(device_entrypoints):
804        device_strmap.add_string(e.name, num)
805        e.num = num
806    device_strmap.bake()
807
808    physical_device_strmap = StringIntMap()
809    for num, e in enumerate(physical_device_entrypoints):
810        physical_device_strmap.add_string(e.name, num)
811        e.num = num
812    physical_device_strmap.bake()
813
814    instance_strmap = StringIntMap()
815    for num, e in enumerate(instance_entrypoints):
816        instance_strmap.add_string(e.name, num)
817        e.num = num
818    instance_strmap.bake()
819
820    # For outputting entrypoints.h we generate a anv_EntryPoint() prototype
821    # per entry point.
822    try:
823        with open(os.path.join(args.outdir, 'anv_entrypoints.h'), 'wb') as f:
824            f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints,
825                                      physical_device_entrypoints=physical_device_entrypoints,
826                                      device_entrypoints=device_entrypoints,
827                                      LAYERS=LAYERS,
828                                      filename=os.path.basename(__file__)))
829        with open(os.path.join(args.outdir, 'anv_entrypoints.c'), 'wb') as f:
830            f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints,
831                                      physical_device_entrypoints=physical_device_entrypoints,
832                                      device_entrypoints=device_entrypoints,
833                                      LAYERS=LAYERS,
834                                      instance_strmap=instance_strmap,
835                                      physical_device_strmap=physical_device_strmap,
836                                      device_strmap=device_strmap,
837                                      filename=os.path.basename(__file__)))
838    except Exception:
839        # In the event there's an error, this imports some helpers from mako
840        # to print a useful stack trace and prints it, then exits with
841        # status 1, if python is run with debug; otherwise it just raises
842        # the exception
843        if __debug__:
844            import sys
845            from mako import exceptions
846            sys.stderr.write(exceptions.text_error_template().render() + '\n')
847            sys.exit(1)
848        raise
849
850
851if __name__ == '__main__':
852    main()
853