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