2 # Copyright © 2017 Intel Corporation
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:
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
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
22 """Create enum to string functions for vulkan using vk.xml."""
24 from __future__
import print_function
28 import xml
.etree
.cElementTree
as et
30 from mako
.template
import Template
32 COPYRIGHT
= textwrap
.dedent(u
"""\
33 * Copyright © 2017 Intel Corporation
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:
42 * The above copyright notice and this permission notice shall be included in
43 * all copies or substantial portions of the Software.
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
53 C_TEMPLATE
= Template(textwrap
.dedent(u
"""\
54 /* Autogenerated file -- do not edit
55 * generated by ${file}
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"
72 vk_${enum.name[2:]}_to_str(${enum.name} input)
74 #pragma GCC diagnostic push
75 #pragma GCC diagnostic ignored "-Wswitch"
77 % for v in sorted(enum.values.keys()):
79 return "${enum.values[v]}";
82 #pragma GCC diagnostic pop
83 unreachable("Undefined enum value.");
91 size_t vk_structure_type_size(const struct VkBaseInStructure *item)
94 % for struct in structs:
95 % if struct.extension is not None and struct.extension.define is not None:
96 #ifdef ${struct.extension.define}
97 case ${struct.stype}: return sizeof(${struct.name});
100 case ${struct.stype}: return sizeof(${struct.name});
104 unreachable("Undefined struct type.");
108 void vk_load_instance_commands(VkInstance instance,
109 PFN_vkGetInstanceProcAddr gpa,
110 struct vk_instance_dispatch_table *table)
112 memset(table, 0, sizeof(*table));
113 table->GetInstanceProcAddr = gpa;
114 % for cmd in commands:
115 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
116 % if cmd.extension is not None and cmd.extension.define is not None:
117 #ifdef ${cmd.extension.define}
118 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
121 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
127 void vk_load_device_commands(VkDevice device,
128 PFN_vkGetDeviceProcAddr gpa,
129 struct vk_device_dispatch_table *table)
131 memset(table, 0, sizeof(*table));
132 table->GetDeviceProcAddr = gpa;
133 % for cmd in commands:
134 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
135 % if cmd.extension is not None and cmd.extension.define is not None:
136 #ifdef ${cmd.extension.define}
137 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
140 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
146 output_encoding
='utf-8')
148 H_TEMPLATE
= Template(textwrap
.dedent(u
"""\
149 /* Autogenerated file -- do not edit
150 * generated by ${file}
155 #ifndef MESA_VK_ENUM_TO_STR_H
156 #define MESA_VK_ENUM_TO_STR_H
158 #include <vulkan/vulkan.h>
159 #include <vulkan/vk_android_native_buffer.h>
165 % for ext in extensions:
166 #define _${ext.name}_number (${ext.number})
173 const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
179 size_t vk_structure_type_size(const struct VkBaseInStructure *item);
181 struct vk_instance_dispatch_table {
182 PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
183 % for cmd in commands:
184 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
185 % if cmd.extension is not None and cmd.extension.define is not None:
186 #ifdef ${cmd.extension.define}
187 PFN_${cmd.name} ${cmd.name[2:]};
190 PFN_${cmd.name} ${cmd.name[2:]};
196 struct vk_device_dispatch_table {
197 PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
198 % for cmd in commands:
199 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
200 % if cmd.extension is not None and cmd.extension.define is not None:
201 #ifdef ${cmd.extension.define}
202 PFN_${cmd.name} ${cmd.name[2:]};
205 PFN_${cmd.name} ${cmd.name[2:]};
211 void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table);
212 void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table);
219 output_encoding
='utf-8')
222 class NamedFactory(object):
223 """Factory for creating enums."""
225 def __init__(self
, type_
):
229 def __call__(self
, name
, **kwargs
):
231 return self
.registry
[name
]
233 n
= self
.registry
[name
] = self
.type(name
, **kwargs
)
237 return self
.registry
.get(name
)
240 class VkExtension(object):
241 """Simple struct-like class representing extensions"""
243 def __init__(self
, name
, number
=None, define
=None):
249 class VkEnum(object):
250 """Simple struct-like class representing a single Vulkan Enum."""
252 def __init__(self
, name
, values
=None):
254 self
.extension
= None
255 # Maps numbers to names
256 self
.values
= values
or dict()
257 self
.name_to_value
= dict()
260 def add_value(self
, name
, value
=None,
261 extnum
=None, offset
=None,
263 assert value
is not None or extnum
is not None
265 value
= 1000000000 + (extnum
- 1) * 1000 + offset
269 self
.name_to_value
[name
] = value
270 if value
not in self
.values
:
271 self
.values
[value
] = name
272 elif len(self
.values
[value
]) > len(name
):
273 self
.values
[value
] = name
275 def add_value_from_xml(self
, elem
, extension
=None):
276 self
.extension
= extension
277 if 'value' in elem
.attrib
:
278 self
.add_value(elem
.attrib
['name'],
279 value
=int(elem
.attrib
['value'], base
=0))
280 elif 'alias' in elem
.attrib
:
281 self
.add_value(elem
.attrib
['name'],
282 value
=self
.name_to_value
[elem
.attrib
['alias']])
284 error
= 'dir' in elem
.attrib
and elem
.attrib
['dir'] == '-'
285 if 'extnumber' in elem
.attrib
:
286 extnum
= int(elem
.attrib
['extnumber'])
288 extnum
= extension
.number
289 self
.add_value(elem
.attrib
['name'],
291 offset
=int(elem
.attrib
['offset']),
294 def set_guard(self
, g
):
298 class VkCommand(object):
299 """Simple struct-like class representing a single Vulkan command"""
301 def __init__(self
, name
, device_entrypoint
=False):
303 self
.device_entrypoint
= device_entrypoint
304 self
.extension
= None
307 class VkChainStruct(object):
308 """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType"""
309 def __init__(self
, name
, stype
):
312 self
.extension
= None
315 def struct_get_stype(xml_node
):
316 for member
in xml_node
.findall('./member'):
317 name
= member
.findall('./name')
318 if len(name
) > 0 and name
[0].text
== "sType":
319 return member
.get('values')
323 def parse_xml(cmd_factory
, enum_factory
, ext_factory
, struct_factory
, filename
):
324 """Parse the XML file. Accumulate results into the factories.
326 This parser is a memory efficient iterative XML parser that returns a list
330 xml
= et
.parse(filename
)
332 for enum_type
in xml
.findall('./enums[@type="enum"]'):
333 enum
= enum_factory(enum_type
.attrib
['name'])
334 for value
in enum_type
.findall('./enum'):
335 enum
.add_value_from_xml(value
)
337 for value
in xml
.findall('./feature/require/enum[@extends]'):
338 enum
= enum_factory
.get(value
.attrib
['extends'])
340 enum
.add_value_from_xml(value
)
342 for command
in xml
.findall('./commands/command'):
343 name
= command
.find('./proto/name')
344 first_arg
= command
.find('./param/type')
345 # Some commands are alias KHR -> nonKHR, ignore those
347 cmd_factory(name
.text
,
348 device_entrypoint
=(first_arg
.text
in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
350 for struct_type
in xml
.findall('./types/type[@category="struct"]'):
351 name
= struct_type
.attrib
['name']
352 stype
= struct_get_stype(struct_type
)
353 if stype
is not None:
354 struct_factory(name
, stype
=stype
)
357 for platform
in xml
.findall('./platforms/platform'):
358 name
= platform
.attrib
['name']
359 define
= platform
.attrib
['protect']
360 platform_define
[name
] = define
362 for ext_elem
in xml
.findall('./extensions/extension[@supported="vulkan"]'):
364 if "platform" in ext_elem
.attrib
:
365 define
= platform_define
[ext_elem
.attrib
['platform']]
366 extension
= ext_factory(ext_elem
.attrib
['name'],
367 number
=int(ext_elem
.attrib
['number']),
370 for value
in ext_elem
.findall('./require/enum[@extends]'):
371 enum
= enum_factory
.get(value
.attrib
['extends'])
373 enum
.add_value_from_xml(value
, extension
)
374 for t
in ext_elem
.findall('./require/type'):
375 struct
= struct_factory
.get(t
.attrib
['name'])
376 if struct
is not None:
377 struct
.extension
= extension
380 for value
in ext_elem
.findall('./require/type[@name]'):
381 enum
= enum_factory
.get(value
.attrib
['name'])
383 enum
.set_guard(define
)
385 for t
in ext_elem
.findall('./require/command'):
386 command
= cmd_factory
.get(t
.attrib
['name'])
387 if command
is not None:
388 command
.extension
= extension
392 parser
= argparse
.ArgumentParser()
393 parser
.add_argument('--xml', required
=True,
394 help='Vulkan API XML files',
397 parser
.add_argument('--outdir',
398 help='Directory to put the generated files in',
401 args
= parser
.parse_args()
403 command_factory
= NamedFactory(VkCommand
)
404 enum_factory
= NamedFactory(VkEnum
)
405 ext_factory
= NamedFactory(VkExtension
)
406 struct_factory
= NamedFactory(VkChainStruct
)
407 for filename
in args
.xml_files
:
408 parse_xml(command_factory
, enum_factory
, ext_factory
, struct_factory
, filename
)
409 commands
= sorted(command_factory
.registry
.values(), key
=lambda e
: e
.name
)
410 enums
= sorted(enum_factory
.registry
.values(), key
=lambda e
: e
.name
)
411 extensions
= sorted(ext_factory
.registry
.values(), key
=lambda e
: e
.name
)
412 structs
= sorted(struct_factory
.registry
.values(), key
=lambda e
: e
.name
)
414 for template
, file_
in [(C_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.c')),
415 (H_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.h'))]:
416 with
open(file_
, 'wb') as f
:
417 f
.write(template
.render(
418 file=os
.path
.basename(__file__
),
421 extensions
=extensions
,
423 copyright
=COPYRIGHT
))
426 if __name__
== '__main__':