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)
75 % for v in sorted(enum.values.keys()):
76 % if enum.values[v] in FOREIGN_ENUM_VALUES:
78 #pragma GCC diagnostic push
79 #pragma GCC diagnostic ignored "-Wswitch"
82 return "${enum.values[v]}";
83 % if enum.values[v] in FOREIGN_ENUM_VALUES:
84 #pragma GCC diagnostic pop
89 unreachable("Undefined enum value.");
98 void vk_load_instance_commands(VkInstance instance,
99 PFN_vkGetInstanceProcAddr gpa,
100 struct vk_instance_dispatch_table *table)
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}");
111 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
117 void vk_load_device_commands(VkDevice device,
118 PFN_vkGetDeviceProcAddr gpa,
119 struct vk_device_dispatch_table *table)
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}");
130 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
136 output_encoding
='utf-8')
138 H_TEMPLATE
= Template(textwrap
.dedent(u
"""\
139 /* Autogenerated file -- do not edit
140 * generated by ${file}
145 #ifndef MESA_VK_ENUM_TO_STR_H
146 #define MESA_VK_ENUM_TO_STR_H
148 #include <vulkan/vulkan.h>
149 #include <vulkan/vk_android_native_buffer.h>
155 % for ext in extensions:
156 #define _${ext.name}_number (${ext.number})
163 const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
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:]};
178 PFN_${cmd.name} ${cmd.name[2:]};
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:]};
193 PFN_${cmd.name} ${cmd.name[2:]};
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);
207 output_encoding
='utf-8')
209 # These enums are defined outside their respective enum blocks, and thus cause
211 FOREIGN_ENUM_VALUES
= [
212 "VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID",
216 class NamedFactory(object):
217 """Factory for creating enums."""
219 def __init__(self
, type_
):
223 def __call__(self
, name
, **kwargs
):
225 return self
.registry
[name
]
227 n
= self
.registry
[name
] = self
.type(name
, **kwargs
)
231 return self
.registry
.get(name
)
234 class VkExtension(object):
235 """Simple struct-like class representing extensions"""
237 def __init__(self
, name
, number
=None, define
=None):
243 class VkEnum(object):
244 """Simple struct-like class representing a single Vulkan Enum."""
246 def __init__(self
, name
, values
=None):
248 # Maps numbers to names
249 self
.values
= values
or dict()
250 self
.name_to_value
= dict()
253 def add_value(self
, name
, value
=None,
254 extnum
=None, offset
=None,
256 assert value
is not None or extnum
is not None
258 value
= 1000000000 + (extnum
- 1) * 1000 + offset
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
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']])
276 error
= 'dir' in elem
.attrib
and elem
.attrib
['dir'] == '-'
277 if 'extnumber' in elem
.attrib
:
278 extnum
= int(elem
.attrib
['extnumber'])
280 extnum
= extension
.number
281 self
.add_value(elem
.attrib
['name'],
283 offset
=int(elem
.attrib
['offset']),
286 def set_guard(self
, g
):
290 class VkCommand(object):
291 """Simple struct-like class representing a single Vulkan command"""
293 def __init__(self
, name
, device_entrypoint
=False):
295 self
.device_entrypoint
= device_entrypoint
296 self
.extension
= None
299 def parse_xml(cmd_factory
, enum_factory
, ext_factory
, filename
):
300 """Parse the XML file. Accumulate results into the factories.
302 This parser is a memory efficient iterative XML parser that returns a list
306 xml
= et
.parse(filename
)
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
)
313 for value
in xml
.findall('./feature/require/enum[@extends]'):
314 enum
= enum_factory
.get(value
.attrib
['extends'])
316 enum
.add_value_from_xml(value
)
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
323 cmd_factory(name
.text
,
324 device_entrypoint
=(first_arg
.text
in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
327 for platform
in xml
.findall('./platforms/platform'):
328 name
= platform
.attrib
['name']
329 define
= platform
.attrib
['protect']
330 platform_define
[name
] = define
332 for ext_elem
in xml
.findall('./extensions/extension[@supported="vulkan"]'):
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']),
340 for value
in ext_elem
.findall('./require/enum[@extends]'):
341 enum
= enum_factory
.get(value
.attrib
['extends'])
343 enum
.add_value_from_xml(value
, extension
)
346 for value
in ext_elem
.findall('./require/type[@name]'):
347 enum
= enum_factory
.get(value
.attrib
['name'])
349 enum
.set_guard(define
)
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
358 parser
= argparse
.ArgumentParser()
359 parser
.add_argument('--xml', required
=True,
360 help='Vulkan API XML files',
363 parser
.add_argument('--outdir',
364 help='Directory to put the generated files in',
367 args
= parser
.parse_args()
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
)
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__
),
385 extensions
=extensions
,
387 FOREIGN_ENUM_VALUES
=FOREIGN_ENUM_VALUES
))
390 if __name__
== '__main__':