ebaf2a1a0ccb1e923122dedd7c367832ecfb24a4
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
.ElementTree
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)
93 #pragma GCC diagnostic push
94 #pragma GCC diagnostic ignored "-Wswitch"
96 % for struct in structs:
97 % if struct.extension is not None and struct.extension.define is not None:
98 #ifdef ${struct.extension.define}
99 case ${struct.stype}: return sizeof(${struct.name});
102 case ${struct.stype}: return sizeof(${struct.name});
106 #pragma GCC diagnostic pop
107 unreachable("Undefined struct type.");
110 void vk_load_instance_commands(VkInstance instance,
111 PFN_vkGetInstanceProcAddr gpa,
112 struct vk_instance_dispatch_table *table)
114 memset(table, 0, sizeof(*table));
115 table->GetInstanceProcAddr = gpa;
116 % for cmd in commands:
117 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
118 % if cmd.extension is not None and cmd.extension.define is not None:
119 #ifdef ${cmd.extension.define}
120 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
123 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
129 void vk_load_device_commands(VkDevice device,
130 PFN_vkGetDeviceProcAddr gpa,
131 struct vk_device_dispatch_table *table)
133 memset(table, 0, sizeof(*table));
134 table->GetDeviceProcAddr = gpa;
135 % for cmd in commands:
136 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
137 % if cmd.extension is not None and cmd.extension.define is not None:
138 #ifdef ${cmd.extension.define}
139 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
142 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
148 output_encoding
='utf-8')
150 H_TEMPLATE
= Template(textwrap
.dedent(u
"""\
151 /* Autogenerated file -- do not edit
152 * generated by ${file}
157 #ifndef MESA_VK_ENUM_TO_STR_H
158 #define MESA_VK_ENUM_TO_STR_H
160 #include <vulkan/vulkan.h>
161 #include <vulkan/vk_android_native_buffer.h>
167 % for ext in extensions:
168 #define _${ext.name}_number (${ext.number})
175 const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
181 size_t vk_structure_type_size(const struct VkBaseInStructure *item);
183 struct vk_instance_dispatch_table {
184 PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
185 % for cmd in commands:
186 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
187 % if cmd.extension is not None and cmd.extension.define is not None:
188 #ifdef ${cmd.extension.define}
189 PFN_${cmd.name} ${cmd.name[2:]};
192 PFN_${cmd.name} ${cmd.name[2:]};
198 struct vk_device_dispatch_table {
199 PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
200 % for cmd in commands:
201 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
202 % if cmd.extension is not None and cmd.extension.define is not None:
203 #ifdef ${cmd.extension.define}
204 PFN_${cmd.name} ${cmd.name[2:]};
207 PFN_${cmd.name} ${cmd.name[2:]};
213 void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table);
214 void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table);
221 output_encoding
='utf-8')
224 class NamedFactory(object):
225 """Factory for creating enums."""
227 def __init__(self
, type_
):
231 def __call__(self
, name
, **kwargs
):
233 return self
.registry
[name
]
235 n
= self
.registry
[name
] = self
.type(name
, **kwargs
)
239 return self
.registry
.get(name
)
242 class VkExtension(object):
243 """Simple struct-like class representing extensions"""
245 def __init__(self
, name
, number
=None, define
=None):
251 class VkEnum(object):
252 """Simple struct-like class representing a single Vulkan Enum."""
254 def __init__(self
, name
, values
=None):
256 self
.extension
= None
257 # Maps numbers to names
258 self
.values
= values
or dict()
259 self
.name_to_value
= dict()
261 self
.name_to_alias_list
= {}
263 def add_value(self
, name
, value
=None,
264 extnum
=None, offset
=None, alias
=None,
266 if alias
is not None:
267 assert value
is None and offset
is None
268 if alias
not in self
.name_to_value
:
269 # We don't have this alias yet. Just record the alias and
270 # we'll deal with it later.
271 alias_list
= self
.name_to_alias_list
.get(alias
, [])
272 alias_list
.append(name
);
275 # Use the value from the alias
276 value
= self
.name_to_value
[alias
]
278 assert value
is not None or extnum
is not None
280 value
= 1000000000 + (extnum
- 1) * 1000 + offset
284 self
.name_to_value
[name
] = value
285 if value
not in self
.values
:
286 self
.values
[value
] = name
287 elif len(self
.values
[value
]) > len(name
):
288 self
.values
[value
] = name
290 # Now that the value has been fully added, resolve aliases, if any.
291 if name
in self
.name_to_alias_list
:
292 for alias
in self
.name_to_alias_list
[name
]:
293 add_value(alias
, value
)
294 del self
.name_to_alias_list
[name
]
296 def add_value_from_xml(self
, elem
, extension
=None):
297 self
.extension
= extension
298 if 'value' in elem
.attrib
:
299 self
.add_value(elem
.attrib
['name'],
300 value
=int(elem
.attrib
['value'], base
=0))
301 elif 'alias' in elem
.attrib
:
302 self
.add_value(elem
.attrib
['name'], alias
=elem
.attrib
['alias'])
304 error
= 'dir' in elem
.attrib
and elem
.attrib
['dir'] == '-'
305 if 'extnumber' in elem
.attrib
:
306 extnum
= int(elem
.attrib
['extnumber'])
308 extnum
= extension
.number
309 self
.add_value(elem
.attrib
['name'],
311 offset
=int(elem
.attrib
['offset']),
314 def set_guard(self
, g
):
318 class VkCommand(object):
319 """Simple struct-like class representing a single Vulkan command"""
321 def __init__(self
, name
, device_entrypoint
=False):
323 self
.device_entrypoint
= device_entrypoint
324 self
.extension
= None
327 class VkChainStruct(object):
328 """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType"""
329 def __init__(self
, name
, stype
):
332 self
.extension
= None
335 def struct_get_stype(xml_node
):
336 for member
in xml_node
.findall('./member'):
337 name
= member
.findall('./name')
338 if len(name
) > 0 and name
[0].text
== "sType":
339 return member
.get('values')
343 def parse_xml(cmd_factory
, enum_factory
, ext_factory
, struct_factory
, filename
):
344 """Parse the XML file. Accumulate results into the factories.
346 This parser is a memory efficient iterative XML parser that returns a list
350 xml
= et
.parse(filename
)
352 for enum_type
in xml
.findall('./enums[@type="enum"]'):
353 enum
= enum_factory(enum_type
.attrib
['name'])
354 for value
in enum_type
.findall('./enum'):
355 enum
.add_value_from_xml(value
)
357 for value
in xml
.findall('./feature/require/enum[@extends]'):
358 enum
= enum_factory
.get(value
.attrib
['extends'])
360 enum
.add_value_from_xml(value
)
362 for command
in xml
.findall('./commands/command'):
363 name
= command
.find('./proto/name')
364 first_arg
= command
.find('./param/type')
365 # Some commands are alias KHR -> nonKHR, ignore those
367 cmd_factory(name
.text
,
368 device_entrypoint
=(first_arg
.text
in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
370 for struct_type
in xml
.findall('./types/type[@category="struct"]'):
371 name
= struct_type
.attrib
['name']
372 stype
= struct_get_stype(struct_type
)
373 if stype
is not None:
374 struct_factory(name
, stype
=stype
)
377 for platform
in xml
.findall('./platforms/platform'):
378 name
= platform
.attrib
['name']
379 define
= platform
.attrib
['protect']
380 platform_define
[name
] = define
382 for ext_elem
in xml
.findall('./extensions/extension[@supported="vulkan"]'):
384 if "platform" in ext_elem
.attrib
:
385 define
= platform_define
[ext_elem
.attrib
['platform']]
386 extension
= ext_factory(ext_elem
.attrib
['name'],
387 number
=int(ext_elem
.attrib
['number']),
390 for value
in ext_elem
.findall('./require/enum[@extends]'):
391 enum
= enum_factory
.get(value
.attrib
['extends'])
393 enum
.add_value_from_xml(value
, extension
)
394 for t
in ext_elem
.findall('./require/type'):
395 struct
= struct_factory
.get(t
.attrib
['name'])
396 if struct
is not None:
397 struct
.extension
= extension
400 for value
in ext_elem
.findall('./require/type[@name]'):
401 enum
= enum_factory
.get(value
.attrib
['name'])
403 enum
.set_guard(define
)
405 for t
in ext_elem
.findall('./require/command'):
406 command
= cmd_factory
.get(t
.attrib
['name'])
407 if command
is not None:
408 command
.extension
= extension
412 parser
= argparse
.ArgumentParser()
413 parser
.add_argument('--xml', required
=True,
414 help='Vulkan API XML files',
417 parser
.add_argument('--outdir',
418 help='Directory to put the generated files in',
421 args
= parser
.parse_args()
423 command_factory
= NamedFactory(VkCommand
)
424 enum_factory
= NamedFactory(VkEnum
)
425 ext_factory
= NamedFactory(VkExtension
)
426 struct_factory
= NamedFactory(VkChainStruct
)
427 for filename
in args
.xml_files
:
428 parse_xml(command_factory
, enum_factory
, ext_factory
, struct_factory
, filename
)
429 commands
= sorted(command_factory
.registry
.values(), key
=lambda e
: e
.name
)
430 enums
= sorted(enum_factory
.registry
.values(), key
=lambda e
: e
.name
)
431 extensions
= sorted(ext_factory
.registry
.values(), key
=lambda e
: e
.name
)
432 structs
= sorted(struct_factory
.registry
.values(), key
=lambda e
: e
.name
)
434 for template
, file_
in [(C_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.c')),
435 (H_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.h'))]:
436 with
open(file_
, 'wb') as f
:
437 f
.write(template
.render(
438 file=os
.path
.basename(__file__
),
441 extensions
=extensions
,
443 copyright
=COPYRIGHT
))
446 if __name__
== '__main__':