delete autotools .gitignore files
[mesa.git] / src / vulkan / util / gen_enum_to_str.py
1 # encoding=utf-8
2 # Copyright © 2017 Intel Corporation
3
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to deal
6 # in the Software without restriction, including without limitation the rights
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 # copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
10
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
13
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 # SOFTWARE.
21
22 """Create enum to string functions for vulkan using vk.xml."""
23
24 from __future__ import print_function
25 import argparse
26 import os
27 import textwrap
28 import xml.etree.cElementTree as et
29
30 from mako.template import Template
31
32 COPYRIGHT = textwrap.dedent(u"""\
33 * Copyright © 2017 Intel Corporation
34 *
35 * Permission is hereby granted, free of charge, to any person obtaining a copy
36 * of this software and associated documentation files (the "Software"), to deal
37 * in the Software without restriction, including without limitation the rights
38 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39 * copies of the Software, and to permit persons to whom the Software is
40 * furnished to do so, subject to the following conditions:
41 *
42 * The above copyright notice and this permission notice shall be included in
43 * all copies or substantial portions of the Software.
44 *
45 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
51 * SOFTWARE.""")
52
53 C_TEMPLATE = Template(textwrap.dedent(u"""\
54 /* Autogenerated file -- do not edit
55 * generated by ${file}
56 *
57 ${copyright}
58 */
59
60 #include <string.h>
61 #include <vulkan/vulkan.h>
62 #include <vulkan/vk_android_native_buffer.h>
63 #include "util/macros.h"
64 #include "vk_enum_to_str.h"
65
66 % for enum in enums:
67
68 % if enum.guard:
69 #ifdef ${enum.guard}
70 % endif
71 const char *
72 vk_${enum.name[2:]}_to_str(${enum.name} input)
73 {
74 switch(input) {
75 % for v in sorted(enum.values.keys()):
76 % if enum.values[v] in FOREIGN_ENUM_VALUES:
77
78 #pragma GCC diagnostic push
79 #pragma GCC diagnostic ignored "-Wswitch"
80 % endif
81 case ${v}:
82 return "${enum.values[v]}";
83 % if enum.values[v] in FOREIGN_ENUM_VALUES:
84 #pragma GCC diagnostic pop
85
86 % endif
87 % endfor
88 default:
89 unreachable("Undefined enum value.");
90 }
91 }
92
93 % if enum.guard:
94 #endif
95 % endif
96 %endfor
97
98 void vk_load_instance_commands(VkInstance instance,
99 PFN_vkGetInstanceProcAddr gpa,
100 struct vk_instance_dispatch_table *table)
101 {
102 memset(table, 0, sizeof(*table));
103 table->GetInstanceProcAddr = gpa;
104 % for cmd in commands:
105 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
106 % if cmd.extension is not None and cmd.extension.define is not None:
107 #ifdef ${cmd.extension.define}
108 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
109 #endif
110 % else:
111 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
112 % endif
113 % endif
114 %endfor
115 }
116
117 void vk_load_device_commands(VkDevice device,
118 PFN_vkGetDeviceProcAddr gpa,
119 struct vk_device_dispatch_table *table)
120 {
121 memset(table, 0, sizeof(*table));
122 table->GetDeviceProcAddr = gpa;
123 % for cmd in commands:
124 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
125 % if cmd.extension is not None and cmd.extension.define is not None:
126 #ifdef ${cmd.extension.define}
127 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
128 #endif
129 % else:
130 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
131 % endif
132 % endif
133 %endfor
134 }
135 """),
136 output_encoding='utf-8')
137
138 H_TEMPLATE = Template(textwrap.dedent(u"""\
139 /* Autogenerated file -- do not edit
140 * generated by ${file}
141 *
142 ${copyright}
143 */
144
145 #ifndef MESA_VK_ENUM_TO_STR_H
146 #define MESA_VK_ENUM_TO_STR_H
147
148 #include <vulkan/vulkan.h>
149 #include <vulkan/vk_android_native_buffer.h>
150
151 #ifdef __cplusplus
152 extern "C" {
153 #endif
154
155 % for ext in extensions:
156 #define _${ext.name}_number (${ext.number})
157 % endfor
158
159 % for enum in enums:
160 % if enum.guard:
161 #ifdef ${enum.guard}
162 % endif
163 const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
164 % if enum.guard:
165 #endif
166 % endif
167 % endfor
168
169 struct vk_instance_dispatch_table {
170 PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
171 % for cmd in commands:
172 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
173 % if cmd.extension is not None and cmd.extension.define is not None:
174 #ifdef ${cmd.extension.define}
175 PFN_${cmd.name} ${cmd.name[2:]};
176 #endif
177 % else:
178 PFN_${cmd.name} ${cmd.name[2:]};
179 % endif
180 % endif
181 %endfor
182 };
183
184 struct vk_device_dispatch_table {
185 PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
186 % for cmd in commands:
187 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
188 % if cmd.extension is not None and cmd.extension.define is not None:
189 #ifdef ${cmd.extension.define}
190 PFN_${cmd.name} ${cmd.name[2:]};
191 #endif
192 % else:
193 PFN_${cmd.name} ${cmd.name[2:]};
194 % endif
195 % endif
196 %endfor
197 };
198
199 void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table);
200 void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table);
201
202 #ifdef __cplusplus
203 } /* extern "C" */
204 #endif
205
206 #endif"""),
207 output_encoding='utf-8')
208
209 # These enums are defined outside their respective enum blocks, and thus cause
210 # -Wswitch warnings.
211 FOREIGN_ENUM_VALUES = [
212 "VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID",
213 ]
214
215
216 class NamedFactory(object):
217 """Factory for creating enums."""
218
219 def __init__(self, type_):
220 self.registry = {}
221 self.type = type_
222
223 def __call__(self, name, **kwargs):
224 try:
225 return self.registry[name]
226 except KeyError:
227 n = self.registry[name] = self.type(name, **kwargs)
228 return n
229
230 def get(self, name):
231 return self.registry.get(name)
232
233
234 class VkExtension(object):
235 """Simple struct-like class representing extensions"""
236
237 def __init__(self, name, number=None, define=None):
238 self.name = name
239 self.number = number
240 self.define = define
241
242
243 class VkEnum(object):
244 """Simple struct-like class representing a single Vulkan Enum."""
245
246 def __init__(self, name, values=None):
247 self.name = name
248 # Maps numbers to names
249 self.values = values or dict()
250 self.name_to_value = dict()
251 self.guard = None
252
253 def add_value(self, name, value=None,
254 extnum=None, offset=None,
255 error=False):
256 assert value is not None or extnum is not None
257 if value is None:
258 value = 1000000000 + (extnum - 1) * 1000 + offset
259 if error:
260 value = -value
261
262 self.name_to_value[name] = value
263 if value not in self.values:
264 self.values[value] = name
265 elif len(self.values[value]) > len(name):
266 self.values[value] = name
267
268 def add_value_from_xml(self, elem, extension=None):
269 if 'value' in elem.attrib:
270 self.add_value(elem.attrib['name'],
271 value=int(elem.attrib['value'], base=0))
272 elif 'alias' in elem.attrib:
273 self.add_value(elem.attrib['name'],
274 value=self.name_to_value[elem.attrib['alias']])
275 else:
276 error = 'dir' in elem.attrib and elem.attrib['dir'] == '-'
277 if 'extnumber' in elem.attrib:
278 extnum = int(elem.attrib['extnumber'])
279 else:
280 extnum = extension.number
281 self.add_value(elem.attrib['name'],
282 extnum=extnum,
283 offset=int(elem.attrib['offset']),
284 error=error)
285
286 def set_guard(self, g):
287 self.guard = g
288
289
290 class VkCommand(object):
291 """Simple struct-like class representing a single Vulkan command"""
292
293 def __init__(self, name, device_entrypoint=False):
294 self.name = name
295 self.device_entrypoint = device_entrypoint
296 self.extension = None
297
298
299 def parse_xml(cmd_factory, enum_factory, ext_factory, filename):
300 """Parse the XML file. Accumulate results into the factories.
301
302 This parser is a memory efficient iterative XML parser that returns a list
303 of VkEnum objects.
304 """
305
306 xml = et.parse(filename)
307
308 for enum_type in xml.findall('./enums[@type="enum"]'):
309 enum = enum_factory(enum_type.attrib['name'])
310 for value in enum_type.findall('./enum'):
311 enum.add_value_from_xml(value)
312
313 for value in xml.findall('./feature/require/enum[@extends]'):
314 enum = enum_factory.get(value.attrib['extends'])
315 if enum is not None:
316 enum.add_value_from_xml(value)
317
318 for command in xml.findall('./commands/command'):
319 name = command.find('./proto/name')
320 first_arg = command.find('./param/type')
321 # Some commands are alias KHR -> nonKHR, ignore those
322 if name is not None:
323 cmd_factory(name.text,
324 device_entrypoint=(first_arg.text in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
325
326 platform_define = {}
327 for platform in xml.findall('./platforms/platform'):
328 name = platform.attrib['name']
329 define = platform.attrib['protect']
330 platform_define[name] = define
331
332 for ext_elem in xml.findall('./extensions/extension[@supported="vulkan"]'):
333 define = None
334 if "platform" in ext_elem.attrib:
335 define = platform_define[ext_elem.attrib['platform']]
336 extension = ext_factory(ext_elem.attrib['name'],
337 number=int(ext_elem.attrib['number']),
338 define=define)
339
340 for value in ext_elem.findall('./require/enum[@extends]'):
341 enum = enum_factory.get(value.attrib['extends'])
342 if enum is not None:
343 enum.add_value_from_xml(value, extension)
344
345 if define:
346 for value in ext_elem.findall('./require/type[@name]'):
347 enum = enum_factory.get(value.attrib['name'])
348 if enum is not None:
349 enum.set_guard(define)
350
351 for t in ext_elem.findall('./require/command'):
352 command = cmd_factory.get(t.attrib['name'])
353 if command is not None:
354 command.extension = extension
355
356
357 def main():
358 parser = argparse.ArgumentParser()
359 parser.add_argument('--xml', required=True,
360 help='Vulkan API XML files',
361 action='append',
362 dest='xml_files')
363 parser.add_argument('--outdir',
364 help='Directory to put the generated files in',
365 required=True)
366
367 args = parser.parse_args()
368
369 command_factory = NamedFactory(VkCommand)
370 enum_factory = NamedFactory(VkEnum)
371 ext_factory = NamedFactory(VkExtension)
372 for filename in args.xml_files:
373 parse_xml(command_factory, enum_factory, ext_factory, filename)
374 commands = sorted(command_factory.registry.values(), key=lambda e: e.name)
375 enums = sorted(enum_factory.registry.values(), key=lambda e: e.name)
376 extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name)
377
378 for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')),
379 (H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h'))]:
380 with open(file_, 'wb') as f:
381 f.write(template.render(
382 file=os.path.basename(__file__),
383 commands=commands,
384 enums=enums,
385 extensions=extensions,
386 copyright=COPYRIGHT,
387 FOREIGN_ENUM_VALUES=FOREIGN_ENUM_VALUES))
388
389
390 if __name__ == '__main__':
391 main()