1b8e80941Smrg# coding=utf-8
2b8e80941Smrg#
3b8e80941Smrg# Copyright © 2015, 2017 Intel Corporation
4b8e80941Smrg#
5b8e80941Smrg# Permission is hereby granted, free of charge, to any person obtaining a
6b8e80941Smrg# copy of this software and associated documentation files (the "Software"),
7b8e80941Smrg# to deal in the Software without restriction, including without limitation
8b8e80941Smrg# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9b8e80941Smrg# and/or sell copies of the Software, and to permit persons to whom the
10b8e80941Smrg# Software is furnished to do so, subject to the following conditions:
11b8e80941Smrg#
12b8e80941Smrg# The above copyright notice and this permission notice (including the next
13b8e80941Smrg# paragraph) shall be included in all copies or substantial portions of the
14b8e80941Smrg# Software.
15b8e80941Smrg#
16b8e80941Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b8e80941Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b8e80941Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19b8e80941Smrg# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20b8e80941Smrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21b8e80941Smrg# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22b8e80941Smrg# IN THE SOFTWARE.
23b8e80941Smrg#
24b8e80941Smrg
25b8e80941Smrgimport argparse
26b8e80941Smrgimport functools
27b8e80941Smrgimport math
28b8e80941Smrgimport os
29b8e80941Smrgimport xml.etree.cElementTree as et
30b8e80941Smrg
31b8e80941Smrgfrom collections import OrderedDict, namedtuple
32b8e80941Smrgfrom mako.template import Template
33b8e80941Smrg
34b8e80941Smrgfrom tu_extensions import VkVersion, MAX_API_VERSION, EXTENSIONS
35b8e80941Smrg
36b8e80941Smrg# We generate a static hash table for entry point lookup
37b8e80941Smrg# (vkGetProcAddress). We use a linear congruential generator for our hash
38b8e80941Smrg# function and a power-of-two size table. The prime numbers are determined
39b8e80941Smrg# experimentally.
40b8e80941Smrg
41b8e80941Smrg# We currently don't use layers in tu, but keeping the ability for anv
42b8e80941Smrg# anyways, so we can use it for device groups.
43b8e80941SmrgLAYERS = [
44b8e80941Smrg    'tu'
45b8e80941Smrg]
46b8e80941Smrg
47b8e80941SmrgTEMPLATE_H = Template("""\
48b8e80941Smrg/* This file generated from ${filename}, don't edit directly. */
49b8e80941Smrg
50b8e80941Smrgstruct tu_dispatch_table {
51b8e80941Smrg   union {
52b8e80941Smrg      void *entrypoints[${len(entrypoints)}];
53b8e80941Smrg      struct {
54b8e80941Smrg      % for e in entrypoints:
55b8e80941Smrg        % if e.guard is not None:
56b8e80941Smrg#ifdef ${e.guard}
57b8e80941Smrg          PFN_${e.name} ${e.name};
58b8e80941Smrg#else
59b8e80941Smrg          void *${e.name};
60b8e80941Smrg# endif
61b8e80941Smrg        % else:
62b8e80941Smrg          PFN_${e.name} ${e.name};
63b8e80941Smrg        % endif
64b8e80941Smrg      % endfor
65b8e80941Smrg      };
66b8e80941Smrg   };
67b8e80941Smrg};
68b8e80941Smrg
69b8e80941Smrg% for e in entrypoints:
70b8e80941Smrg  % if e.alias:
71b8e80941Smrg    <% continue %>
72b8e80941Smrg  % endif
73b8e80941Smrg  % if e.guard is not None:
74b8e80941Smrg#ifdef ${e.guard}
75b8e80941Smrg  % endif
76b8e80941Smrg  % for layer in LAYERS:
77b8e80941Smrg  ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
78b8e80941Smrg  % endfor
79b8e80941Smrg  % if e.guard is not None:
80b8e80941Smrg#endif // ${e.guard}
81b8e80941Smrg  % endif
82b8e80941Smrg% endfor
83b8e80941Smrg""", output_encoding='utf-8')
84b8e80941Smrg
85b8e80941SmrgTEMPLATE_C = Template(u"""\
86b8e80941Smrg/*
87b8e80941Smrg * Copyright © 2015 Intel Corporation
88b8e80941Smrg *
89b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
91b8e80941Smrg * to deal in the Software without restriction, including without limitation
92b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
93b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
94b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
95b8e80941Smrg *
96b8e80941Smrg * The above copyright notice and this permission notice (including the next
97b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
98b8e80941Smrg * Software.
99b8e80941Smrg *
100b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
101b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
102b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
103b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
104b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
105b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
106b8e80941Smrg * IN THE SOFTWARE.
107b8e80941Smrg */
108b8e80941Smrg
109b8e80941Smrg/* This file generated from ${filename}, don't edit directly. */
110b8e80941Smrg
111b8e80941Smrg#include "tu_private.h"
112b8e80941Smrg
113b8e80941Smrgstruct string_map_entry {
114b8e80941Smrg   uint32_t name;
115b8e80941Smrg   uint32_t hash;
116b8e80941Smrg   uint32_t num;
117b8e80941Smrg};
118b8e80941Smrg
119b8e80941Smrg/* We use a big string constant to avoid lots of relocations from the entry
120b8e80941Smrg * point table to lots of little strings. The entries in the entry point table
121b8e80941Smrg * store the index into this big string.
122b8e80941Smrg */
123b8e80941Smrg
124b8e80941Smrgstatic const char strings[] =
125b8e80941Smrg% for s in strmap.sorted_strings:
126b8e80941Smrg    "${s.string}\\0"
127b8e80941Smrg% endfor
128b8e80941Smrg;
129b8e80941Smrg
130b8e80941Smrgstatic const struct string_map_entry string_map_entries[] = {
131b8e80941Smrg% for s in strmap.sorted_strings:
132b8e80941Smrg    { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */
133b8e80941Smrg% endfor
134b8e80941Smrg};
135b8e80941Smrg
136b8e80941Smrg/* Hash table stats:
137b8e80941Smrg * size ${len(strmap.sorted_strings)} entries
138b8e80941Smrg * collisions entries:
139b8e80941Smrg% for i in range(10):
140b8e80941Smrg *     ${i}${'+' if i == 9 else ' '}     ${strmap.collisions[i]}
141b8e80941Smrg% endfor
142b8e80941Smrg */
143b8e80941Smrg
144b8e80941Smrg#define none 0xffff
145b8e80941Smrgstatic const uint16_t string_map[${strmap.hash_size}] = {
146b8e80941Smrg% for e in strmap.mapping:
147b8e80941Smrg    ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },
148b8e80941Smrg% endfor
149b8e80941Smrg};
150b8e80941Smrg
151b8e80941Smrg/* Weak aliases for all potential implementations. These will resolve to
152b8e80941Smrg * NULL if they're not defined, which lets the resolve_entrypoint() function
153b8e80941Smrg * either pick the correct entry point.
154b8e80941Smrg */
155b8e80941Smrg
156b8e80941Smrg% for layer in LAYERS:
157b8e80941Smrg  % for e in entrypoints:
158b8e80941Smrg    % if e.alias:
159b8e80941Smrg      <% continue %>
160b8e80941Smrg    % endif
161b8e80941Smrg    % if e.guard is not None:
162b8e80941Smrg#ifdef ${e.guard}
163b8e80941Smrg    % endif
164b8e80941Smrg    ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak));
165b8e80941Smrg    % if e.guard is not None:
166b8e80941Smrg#endif // ${e.guard}
167b8e80941Smrg    % endif
168b8e80941Smrg  % endfor
169b8e80941Smrg
170b8e80941Smrg  const struct tu_dispatch_table ${layer}_layer = {
171b8e80941Smrg  % for e in entrypoints:
172b8e80941Smrg    % if e.guard is not None:
173b8e80941Smrg#ifdef ${e.guard}
174b8e80941Smrg    % endif
175b8e80941Smrg    .${e.name} = ${e.prefixed_name(layer)},
176b8e80941Smrg    % if e.guard is not None:
177b8e80941Smrg#endif // ${e.guard}
178b8e80941Smrg    % endif
179b8e80941Smrg  % endfor
180b8e80941Smrg  };
181b8e80941Smrg% endfor
182b8e80941Smrg
183b8e80941Smrgstatic void * __attribute__ ((noinline))
184b8e80941Smrgtu_resolve_entrypoint(uint32_t index)
185b8e80941Smrg{
186b8e80941Smrg   return tu_layer.entrypoints[index];
187b8e80941Smrg}
188b8e80941Smrg
189b8e80941Smrg/** Return true if the core version or extension in which the given entrypoint
190b8e80941Smrg * is defined is enabled.
191b8e80941Smrg *
192b8e80941Smrg * If instance is NULL, we only allow the 3 commands explicitly allowed by the vk
193b8e80941Smrg * spec.
194b8e80941Smrg *
195b8e80941Smrg * If device is NULL, all device extensions are considered enabled.
196b8e80941Smrg */
197b8e80941Smrgstatic bool
198b8e80941Smrgtu_entrypoint_is_enabled(int index, uint32_t core_version,
199b8e80941Smrg                         const struct tu_instance_extension_table *instance,
200b8e80941Smrg                         const struct tu_device_extension_table *device)
201b8e80941Smrg{
202b8e80941Smrg   switch (index) {
203b8e80941Smrg% for e in entrypoints:
204b8e80941Smrg   case ${e.num}:
205b8e80941Smrg   % if not e.device_command:
206b8e80941Smrg      if (device) return false;
207b8e80941Smrg   % endif
208b8e80941Smrg   % if e.name == 'vkCreateInstance' or e.name == 'vkEnumerateInstanceExtensionProperties' or e.name == 'vkEnumerateInstanceLayerProperties' or e.name == 'vkEnumerateInstanceVersion':
209b8e80941Smrg      return !device;
210b8e80941Smrg   % elif e.core_version:
211b8e80941Smrg      return instance && ${e.core_version.c_vk_version()} <= core_version;
212b8e80941Smrg   % elif e.extensions:
213b8e80941Smrg      % for ext in e.extensions:
214b8e80941Smrg         % if ext.type == 'instance':
215b8e80941Smrg      if (instance && instance->${ext.name[3:]}) return true;
216b8e80941Smrg         % else:
217b8e80941Smrg      if (instance && (!device || device->${ext.name[3:]})) return true;
218b8e80941Smrg         % endif
219b8e80941Smrg      %endfor
220b8e80941Smrg      return false;
221b8e80941Smrg   % else:
222b8e80941Smrg      return instance;
223b8e80941Smrg   % endif
224b8e80941Smrg% endfor
225b8e80941Smrg   default:
226b8e80941Smrg      return false;
227b8e80941Smrg   }
228b8e80941Smrg}
229b8e80941Smrg
230b8e80941Smrgstatic int
231b8e80941Smrgtu_lookup_entrypoint(const char *name)
232b8e80941Smrg{
233b8e80941Smrg   static const uint32_t prime_factor = ${strmap.prime_factor};
234b8e80941Smrg   static const uint32_t prime_step = ${strmap.prime_step};
235b8e80941Smrg   const struct string_map_entry *e;
236b8e80941Smrg   uint32_t hash, h;
237b8e80941Smrg   uint16_t i;
238b8e80941Smrg   const char *p;
239b8e80941Smrg
240b8e80941Smrg   hash = 0;
241b8e80941Smrg   for (p = name; *p; p++)
242b8e80941Smrg       hash = hash * prime_factor + *p;
243b8e80941Smrg
244b8e80941Smrg   h = hash;
245b8e80941Smrg   while (1) {
246b8e80941Smrg       i = string_map[h & ${strmap.hash_mask}];
247b8e80941Smrg       if (i == none)
248b8e80941Smrg          return -1;
249b8e80941Smrg       e = &string_map_entries[i];
250b8e80941Smrg       if (e->hash == hash && strcmp(name, strings + e->name) == 0)
251b8e80941Smrg           return e->num;
252b8e80941Smrg       h += prime_step;
253b8e80941Smrg   }
254b8e80941Smrg
255b8e80941Smrg   return -1;
256b8e80941Smrg}
257b8e80941Smrg
258b8e80941Smrgvoid *
259b8e80941Smrgtu_lookup_entrypoint_unchecked(const char *name)
260b8e80941Smrg{
261b8e80941Smrg   int index = tu_lookup_entrypoint(name);
262b8e80941Smrg   if (index < 0)
263b8e80941Smrg      return NULL;
264b8e80941Smrg   return tu_resolve_entrypoint(index);
265b8e80941Smrg}
266b8e80941Smrg
267b8e80941Smrgvoid *
268b8e80941Smrgtu_lookup_entrypoint_checked(const char *name,
269b8e80941Smrg                              uint32_t core_version,
270b8e80941Smrg                              const struct tu_instance_extension_table *instance,
271b8e80941Smrg                              const struct tu_device_extension_table *device)
272b8e80941Smrg{
273b8e80941Smrg   int index = tu_lookup_entrypoint(name);
274b8e80941Smrg   if (index < 0 || !tu_entrypoint_is_enabled(index, core_version, instance, device))
275b8e80941Smrg      return NULL;
276b8e80941Smrg   return tu_resolve_entrypoint(index);
277b8e80941Smrg}""", output_encoding='utf-8')
278b8e80941Smrg
279b8e80941SmrgU32_MASK = 2**32 - 1
280b8e80941Smrg
281b8e80941SmrgPRIME_FACTOR = 5024183
282b8e80941SmrgPRIME_STEP = 19
283b8e80941Smrg
284b8e80941Smrgdef round_to_pow2(x):
285b8e80941Smrg    return 2**int(math.ceil(math.log(x, 2)))
286b8e80941Smrg
287b8e80941Smrgclass StringIntMapEntry(object):
288b8e80941Smrg    def __init__(self, string, num):
289b8e80941Smrg        self.string = string
290b8e80941Smrg        self.num = num
291b8e80941Smrg
292b8e80941Smrg        # Calculate the same hash value that we will calculate in C.
293b8e80941Smrg        h = 0
294b8e80941Smrg        for c in string:
295b8e80941Smrg            h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
296b8e80941Smrg        self.hash = h
297b8e80941Smrg
298b8e80941Smrg        self.offset = None
299b8e80941Smrg
300b8e80941Smrgclass StringIntMap(object):
301b8e80941Smrg    def __init__(self):
302b8e80941Smrg        self.baked = False
303b8e80941Smrg        self.strings = dict()
304b8e80941Smrg
305b8e80941Smrg    def add_string(self, string, num):
306b8e80941Smrg        assert not self.baked
307b8e80941Smrg        assert string not in self.strings
308b8e80941Smrg        assert num >= 0 and num < 2**31
309b8e80941Smrg        self.strings[string] = StringIntMapEntry(string, num)
310b8e80941Smrg
311b8e80941Smrg    def bake(self):
312b8e80941Smrg        self.sorted_strings = \
313b8e80941Smrg            sorted(self.strings.values(), key=lambda x: x.string)
314b8e80941Smrg        offset = 0
315b8e80941Smrg        for entry in self.sorted_strings:
316b8e80941Smrg            entry.offset = offset
317b8e80941Smrg            offset += len(entry.string) + 1
318b8e80941Smrg
319b8e80941Smrg        # Save off some values that we'll need in C
320b8e80941Smrg        self.hash_size = round_to_pow2(len(self.strings) * 1.25)
321b8e80941Smrg        self.hash_mask = self.hash_size - 1
322b8e80941Smrg        self.prime_factor = PRIME_FACTOR
323b8e80941Smrg        self.prime_step = PRIME_STEP
324b8e80941Smrg
325b8e80941Smrg        self.mapping = [-1] * self.hash_size
326b8e80941Smrg        self.collisions = [0] * 10
327b8e80941Smrg        for idx, s in enumerate(self.sorted_strings):
328b8e80941Smrg            level = 0
329b8e80941Smrg            h = s.hash
330b8e80941Smrg            while self.mapping[h & self.hash_mask] >= 0:
331b8e80941Smrg                h = h + PRIME_STEP
332b8e80941Smrg                level = level + 1
333b8e80941Smrg            self.collisions[min(level, 9)] += 1
334b8e80941Smrg            self.mapping[h & self.hash_mask] = idx
335b8e80941Smrg
336b8e80941SmrgEntrypointParam = namedtuple('EntrypointParam', 'type name decl')
337b8e80941Smrg
338b8e80941Smrgclass EntrypointBase(object):
339b8e80941Smrg    def __init__(self, name):
340b8e80941Smrg        self.name = name
341b8e80941Smrg        self.alias = None
342b8e80941Smrg        self.guard = None
343b8e80941Smrg        self.enabled = False
344b8e80941Smrg        self.num = None
345b8e80941Smrg        # Extensions which require this entrypoint
346b8e80941Smrg        self.core_version = None
347b8e80941Smrg        self.extensions = []
348b8e80941Smrg
349b8e80941Smrgclass Entrypoint(EntrypointBase):
350b8e80941Smrg    def __init__(self, name, return_type, params, guard = None):
351b8e80941Smrg        super(Entrypoint, self).__init__(name)
352b8e80941Smrg        self.return_type = return_type
353b8e80941Smrg        self.params = params
354b8e80941Smrg        self.guard = guard
355b8e80941Smrg        self.device_command = len(params) > 0 and (params[0].type == 'VkDevice' or params[0].type == 'VkQueue' or params[0].type == 'VkCommandBuffer')
356b8e80941Smrg
357b8e80941Smrg    def prefixed_name(self, prefix):
358b8e80941Smrg        assert self.name.startswith('vk')
359b8e80941Smrg        return prefix + '_' + self.name[2:]
360b8e80941Smrg
361b8e80941Smrg    def decl_params(self):
362b8e80941Smrg        return ', '.join(p.decl for p in self.params)
363b8e80941Smrg
364b8e80941Smrg    def call_params(self):
365b8e80941Smrg        return ', '.join(p.name for p in self.params)
366b8e80941Smrg
367b8e80941Smrgclass EntrypointAlias(EntrypointBase):
368b8e80941Smrg    def __init__(self, name, entrypoint):
369b8e80941Smrg        super(EntrypointAlias, self).__init__(name)
370b8e80941Smrg        self.alias = entrypoint
371b8e80941Smrg        self.device_command = entrypoint.device_command
372b8e80941Smrg
373b8e80941Smrg    def prefixed_name(self, prefix):
374b8e80941Smrg        return self.alias.prefixed_name(prefix)
375b8e80941Smrg
376b8e80941Smrgdef get_entrypoints(doc, entrypoints_to_defines, start_index):
377b8e80941Smrg    """Extract the entry points from the registry."""
378b8e80941Smrg    entrypoints = OrderedDict()
379b8e80941Smrg
380b8e80941Smrg    for command in doc.findall('./commands/command'):
381b8e80941Smrg       if 'alias' in command.attrib:
382b8e80941Smrg           alias = command.attrib['name']
383b8e80941Smrg           target = command.attrib['alias']
384b8e80941Smrg           entrypoints[alias] = EntrypointAlias(alias, entrypoints[target])
385b8e80941Smrg       else:
386b8e80941Smrg           name = command.find('./proto/name').text
387b8e80941Smrg           ret_type = command.find('./proto/type').text
388b8e80941Smrg           params = [EntrypointParam(
389b8e80941Smrg               type = p.find('./type').text,
390b8e80941Smrg               name = p.find('./name').text,
391b8e80941Smrg               decl = ''.join(p.itertext())
392b8e80941Smrg           ) for p in command.findall('./param')]
393b8e80941Smrg           guard = entrypoints_to_defines.get(name)
394b8e80941Smrg           # They really need to be unique
395b8e80941Smrg           assert name not in entrypoints
396b8e80941Smrg           entrypoints[name] = Entrypoint(name, ret_type, params, guard)
397b8e80941Smrg
398b8e80941Smrg    for feature in doc.findall('./feature'):
399b8e80941Smrg        assert feature.attrib['api'] == 'vulkan'
400b8e80941Smrg        version = VkVersion(feature.attrib['number'])
401b8e80941Smrg        if version > MAX_API_VERSION:
402b8e80941Smrg            continue
403b8e80941Smrg
404b8e80941Smrg        for command in feature.findall('./require/command'):
405b8e80941Smrg            e = entrypoints[command.attrib['name']]
406b8e80941Smrg            e.enabled = True
407b8e80941Smrg            assert e.core_version is None
408b8e80941Smrg            e.core_version = version
409b8e80941Smrg
410b8e80941Smrg    supported_exts = dict((ext.name, ext) for ext in EXTENSIONS)
411b8e80941Smrg    for extension in doc.findall('.extensions/extension'):
412b8e80941Smrg        ext_name = extension.attrib['name']
413b8e80941Smrg        if ext_name not in supported_exts:
414b8e80941Smrg            continue
415b8e80941Smrg
416b8e80941Smrg        ext = supported_exts[ext_name]
417b8e80941Smrg        ext.type = extension.attrib['type']
418b8e80941Smrg
419b8e80941Smrg        for command in extension.findall('./require/command'):
420b8e80941Smrg            e = entrypoints[command.attrib['name']]
421b8e80941Smrg            e.enabled = True
422b8e80941Smrg            assert e.core_version is None
423b8e80941Smrg            e.extensions.append(ext)
424b8e80941Smrg
425b8e80941Smrg    # if the base command is not supported by the driver yet, don't alias aliases
426b8e80941Smrg    for e in entrypoints.values():
427b8e80941Smrg        if e.alias and not e.alias.enabled:
428b8e80941Smrg            e_clone = copy.deepcopy(e.alias)
429b8e80941Smrg            e_clone.enabled = True
430b8e80941Smrg            e_clone.name = e.name
431b8e80941Smrg            entrypoints[e.name] = e_clone
432b8e80941Smrg
433b8e80941Smrg    return [e for e in entrypoints.values() if e.enabled]
434b8e80941Smrg
435b8e80941Smrg
436b8e80941Smrgdef get_entrypoints_defines(doc):
437b8e80941Smrg    """Maps entry points to extension defines."""
438b8e80941Smrg    entrypoints_to_defines = {}
439b8e80941Smrg
440b8e80941Smrg    for extension in doc.findall('./extensions/extension[@protect]'):
441b8e80941Smrg        define = extension.attrib['protect']
442b8e80941Smrg
443b8e80941Smrg        for entrypoint in extension.findall('./require/command'):
444b8e80941Smrg            fullname = entrypoint.attrib['name']
445b8e80941Smrg            entrypoints_to_defines[fullname] = define
446b8e80941Smrg
447b8e80941Smrg    platform_define = {}
448b8e80941Smrg    for platform in doc.findall('./platforms/platform'):
449b8e80941Smrg        name = platform.attrib['name']
450b8e80941Smrg        define = platform.attrib['protect']
451b8e80941Smrg        platform_define[name] = define
452b8e80941Smrg
453b8e80941Smrg    for extension in doc.findall('./extensions/extension[@platform]'):
454b8e80941Smrg        platform = extension.attrib['platform']
455b8e80941Smrg        define = platform_define[platform]
456b8e80941Smrg
457b8e80941Smrg        for entrypoint in extension.findall('./require/command'):
458b8e80941Smrg            fullname = entrypoint.attrib['name']
459b8e80941Smrg            entrypoints_to_defines[fullname] = define
460b8e80941Smrg
461b8e80941Smrg    return entrypoints_to_defines
462b8e80941Smrg
463b8e80941Smrg
464b8e80941Smrgdef gen_code(entrypoints):
465b8e80941Smrg    """Generate the C code."""
466b8e80941Smrg    strmap = StringIntMap()
467b8e80941Smrg    for e in entrypoints:
468b8e80941Smrg        strmap.add_string(e.name, e.num)
469b8e80941Smrg    strmap.bake()
470b8e80941Smrg
471b8e80941Smrg    return TEMPLATE_C.render(entrypoints=entrypoints,
472b8e80941Smrg                             LAYERS=LAYERS,
473b8e80941Smrg                             strmap=strmap,
474b8e80941Smrg                             filename=os.path.basename(__file__))
475b8e80941Smrg
476b8e80941Smrg
477b8e80941Smrgdef main():
478b8e80941Smrg    parser = argparse.ArgumentParser()
479b8e80941Smrg    parser.add_argument('--outdir', help='Where to write the files.',
480b8e80941Smrg                        required=True)
481b8e80941Smrg    parser.add_argument('--xml',
482b8e80941Smrg                        help='Vulkan API XML file.',
483b8e80941Smrg                        required=True,
484b8e80941Smrg                        action='append',
485b8e80941Smrg                        dest='xml_files')
486b8e80941Smrg    args = parser.parse_args()
487b8e80941Smrg
488b8e80941Smrg    entrypoints = []
489b8e80941Smrg
490b8e80941Smrg    for filename in args.xml_files:
491b8e80941Smrg        doc = et.parse(filename)
492b8e80941Smrg        entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc),
493b8e80941Smrg                                       start_index=len(entrypoints))
494b8e80941Smrg
495b8e80941Smrg    for num, e in enumerate(entrypoints):
496b8e80941Smrg        e.num = num
497b8e80941Smrg
498b8e80941Smrg    # For outputting entrypoints.h we generate a tu_EntryPoint() prototype
499b8e80941Smrg    # per entry point.
500b8e80941Smrg    with open(os.path.join(args.outdir, 'tu_entrypoints.h'), 'wb') as f:
501b8e80941Smrg        f.write(TEMPLATE_H.render(entrypoints=entrypoints,
502b8e80941Smrg                                  LAYERS=LAYERS,
503b8e80941Smrg                                  filename=os.path.basename(__file__)))
504b8e80941Smrg    with open(os.path.join(args.outdir, 'tu_entrypoints.c'), 'wb') as f:
505b8e80941Smrg        f.write(gen_code(entrypoints))
506b8e80941Smrg
507b8e80941Smrg
508b8e80941Smrgif __name__ == '__main__':
509b8e80941Smrg    main()
510