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"
69 vk_${enum.name[2:]}_to_str(${enum.name} input)
72 % for v in sorted(enum.values.keys()):
73 % if enum.values[v] in FOREIGN_ENUM_VALUES:
75 #pragma GCC diagnostic push
76 #pragma GCC diagnostic ignored "-Wswitch"
79 return "${enum.values[v]}";
80 % if enum.values[v] in FOREIGN_ENUM_VALUES:
81 #pragma GCC diagnostic pop
86 unreachable("Undefined enum value.");
91 void vk_load_instance_commands(VkInstance instance,
92 PFN_vkGetInstanceProcAddr gpa,
93 struct vk_instance_dispatch_table *table)
95 memset(table, 0, sizeof(*table));
96 table->GetInstanceProcAddr = gpa;
97 % for cmd in commands:
98 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
99 % if cmd.extension is not None and cmd.extension.define is not None:
100 #ifdef ${cmd.extension.define}
101 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
104 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
110 void vk_load_device_commands(VkDevice device,
111 PFN_vkGetDeviceProcAddr gpa,
112 struct vk_device_dispatch_table *table)
114 memset(table, 0, sizeof(*table));
115 table->GetDeviceProcAddr = gpa;
116 % for cmd in commands:
117 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
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(device, "${cmd.name}");
123 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
129 output_encoding
='utf-8')
131 H_TEMPLATE
= Template(textwrap
.dedent(u
"""\
132 /* Autogenerated file -- do not edit
133 * generated by ${file}
138 #ifndef MESA_VK_ENUM_TO_STR_H
139 #define MESA_VK_ENUM_TO_STR_H
141 #include <vulkan/vulkan.h>
142 #include <vulkan/vk_android_native_buffer.h>
148 % for ext in extensions:
149 #define _${ext.name}_number (${ext.number})
153 const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
156 struct vk_instance_dispatch_table {
157 PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
158 % for cmd in commands:
159 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
160 % if cmd.extension is not None and cmd.extension.define is not None:
161 #ifdef ${cmd.extension.define}
162 PFN_${cmd.name} ${cmd.name[2:]};
165 PFN_${cmd.name} ${cmd.name[2:]};
171 struct vk_device_dispatch_table {
172 PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
173 % for cmd in commands:
174 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
175 % if cmd.extension is not None and cmd.extension.define is not None:
176 #ifdef ${cmd.extension.define}
177 PFN_${cmd.name} ${cmd.name[2:]};
180 PFN_${cmd.name} ${cmd.name[2:]};
186 void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table);
187 void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table);
194 output_encoding
='utf-8')
196 # These enums are defined outside their respective enum blocks, and thus cause
198 FOREIGN_ENUM_VALUES
= [
199 "VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID",
203 class NamedFactory(object):
204 """Factory for creating enums."""
206 def __init__(self
, type_
):
210 def __call__(self
, name
, **kwargs
):
212 return self
.registry
[name
]
214 n
= self
.registry
[name
] = self
.type(name
, **kwargs
)
218 return self
.registry
.get(name
)
221 class VkExtension(object):
222 """Simple struct-like class representing extensions"""
224 def __init__(self
, name
, number
=None, platform
=None):
228 if platform
is not None:
230 if platform
.upper() == 'XLIB_XRANDR':
232 self
.define
= 'VK_USE_PLATFORM_' + platform
.upper() + ext
235 class VkEnum(object):
236 """Simple struct-like class representing a single Vulkan Enum."""
238 def __init__(self
, name
, values
=None):
240 # Maps numbers to names
241 self
.values
= values
or dict()
242 self
.name_to_value
= dict()
244 def add_value(self
, name
, value
=None,
245 extnum
=None, offset
=None,
247 assert value
is not None or extnum
is not None
249 value
= 1000000000 + (extnum
- 1) * 1000 + offset
253 self
.name_to_value
[name
] = value
254 if value
not in self
.values
:
255 self
.values
[value
] = name
256 elif len(self
.values
[value
]) > len(name
):
257 self
.values
[value
] = name
259 def add_value_from_xml(self
, elem
, extension
=None):
260 if 'value' in elem
.attrib
:
261 self
.add_value(elem
.attrib
['name'],
262 value
=int(elem
.attrib
['value'], base
=0))
263 elif 'alias' in elem
.attrib
:
264 self
.add_value(elem
.attrib
['name'],
265 value
=self
.name_to_value
[elem
.attrib
['alias']])
267 error
= 'dir' in elem
.attrib
and elem
.attrib
['dir'] == '-'
268 if 'extnumber' in elem
.attrib
:
269 extnum
= int(elem
.attrib
['extnumber'])
271 extnum
= extension
.number
272 self
.add_value(elem
.attrib
['name'],
274 offset
=int(elem
.attrib
['offset']),
278 class VkCommand(object):
279 """Simple struct-like class representing a single Vulkan command"""
281 def __init__(self
, name
, device_entrypoint
=False):
283 self
.device_entrypoint
= device_entrypoint
284 self
.extension
= None
287 def parse_xml(cmd_factory
, enum_factory
, ext_factory
, filename
):
288 """Parse the XML file. Accumulate results into the factories.
290 This parser is a memory efficient iterative XML parser that returns a list
294 xml
= et
.parse(filename
)
296 for enum_type
in xml
.findall('./enums[@type="enum"]'):
297 enum
= enum_factory(enum_type
.attrib
['name'])
298 for value
in enum_type
.findall('./enum'):
299 enum
.add_value_from_xml(value
)
301 for value
in xml
.findall('./feature/require/enum[@extends]'):
302 enum
= enum_factory
.get(value
.attrib
['extends'])
304 enum
.add_value_from_xml(value
)
306 for command
in xml
.findall('./commands/command'):
307 name
= command
.find('./proto/name')
308 first_arg
= command
.find('./param/type')
309 # Some commands are alias KHR -> nonKHR, ignore those
311 cmd_factory(name
.text
,
312 device_entrypoint
=(first_arg
.text
in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
314 for ext_elem
in xml
.findall('./extensions/extension[@supported="vulkan"]'):
316 if "platform" in ext_elem
.attrib
:
317 platform
= ext_elem
.attrib
['platform']
318 extension
= ext_factory(ext_elem
.attrib
['name'],
319 number
=int(ext_elem
.attrib
['number']),
322 for value
in ext_elem
.findall('./require/enum[@extends]'):
323 enum
= enum_factory
.get(value
.attrib
['extends'])
325 enum
.add_value_from_xml(value
, extension
)
327 for t
in ext_elem
.findall('./require/command'):
328 command
= cmd_factory
.get(t
.attrib
['name'])
329 if command
is not None:
330 command
.extension
= extension
334 parser
= argparse
.ArgumentParser()
335 parser
.add_argument('--xml', required
=True,
336 help='Vulkan API XML files',
339 parser
.add_argument('--outdir',
340 help='Directory to put the generated files in',
343 args
= parser
.parse_args()
345 command_factory
= NamedFactory(VkCommand
)
346 enum_factory
= NamedFactory(VkEnum
)
347 ext_factory
= NamedFactory(VkExtension
)
348 for filename
in args
.xml_files
:
349 parse_xml(command_factory
, enum_factory
, ext_factory
, filename
)
350 commands
= sorted(command_factory
.registry
.values(), key
=lambda e
: e
.name
)
351 enums
= sorted(enum_factory
.registry
.values(), key
=lambda e
: e
.name
)
352 extensions
= sorted(ext_factory
.registry
.values(), key
=lambda e
: e
.name
)
354 for template
, file_
in [(C_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.c')),
355 (H_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.h'))]:
356 with
open(file_
, 'wb') as f
:
357 f
.write(template
.render(
358 file=os
.path
.basename(__file__
),
361 extensions
=extensions
,
363 FOREIGN_ENUM_VALUES
=FOREIGN_ENUM_VALUES
))
366 if __name__
== '__main__':