5357278ded109abe6765d76df9d19189b87b597f
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 size_t vk_structure_type_size(const struct VkBaseInStructure *item)
100 switch(item->sType) {
101 % for struct in structs:
102 % if struct.extension is not None and struct.extension.define is not None:
103 #ifdef ${struct.extension.define}
104 case ${struct.stype}: return sizeof(${struct.name});
107 case ${struct.stype}: return sizeof(${struct.name});
111 unreachable("Undefined struct type.");
115 void vk_load_instance_commands(VkInstance instance,
116 PFN_vkGetInstanceProcAddr gpa,
117 struct vk_instance_dispatch_table *table)
119 memset(table, 0, sizeof(*table));
120 table->GetInstanceProcAddr = gpa;
121 % for cmd in commands:
122 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
123 % if cmd.extension is not None and cmd.extension.define is not None:
124 #ifdef ${cmd.extension.define}
125 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
128 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}");
134 void vk_load_device_commands(VkDevice device,
135 PFN_vkGetDeviceProcAddr gpa,
136 struct vk_device_dispatch_table *table)
138 memset(table, 0, sizeof(*table));
139 table->GetDeviceProcAddr = gpa;
140 % for cmd in commands:
141 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
142 % if cmd.extension is not None and cmd.extension.define is not None:
143 #ifdef ${cmd.extension.define}
144 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
147 table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}");
153 output_encoding
='utf-8')
155 H_TEMPLATE
= Template(textwrap
.dedent(u
"""\
156 /* Autogenerated file -- do not edit
157 * generated by ${file}
162 #ifndef MESA_VK_ENUM_TO_STR_H
163 #define MESA_VK_ENUM_TO_STR_H
165 #include <vulkan/vulkan.h>
166 #include <vulkan/vk_android_native_buffer.h>
172 % for ext in extensions:
173 #define _${ext.name}_number (${ext.number})
180 const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
186 size_t vk_structure_type_size(const struct VkBaseInStructure *item);
188 struct vk_instance_dispatch_table {
189 PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
190 % for cmd in commands:
191 % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr':
192 % if cmd.extension is not None and cmd.extension.define is not None:
193 #ifdef ${cmd.extension.define}
194 PFN_${cmd.name} ${cmd.name[2:]};
197 PFN_${cmd.name} ${cmd.name[2:]};
203 struct vk_device_dispatch_table {
204 PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
205 % for cmd in commands:
206 % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr':
207 % if cmd.extension is not None and cmd.extension.define is not None:
208 #ifdef ${cmd.extension.define}
209 PFN_${cmd.name} ${cmd.name[2:]};
212 PFN_${cmd.name} ${cmd.name[2:]};
218 void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table);
219 void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table);
226 output_encoding
='utf-8')
228 # These enums are defined outside their respective enum blocks, and thus cause
230 FOREIGN_ENUM_VALUES
= [
231 "VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID",
235 class NamedFactory(object):
236 """Factory for creating enums."""
238 def __init__(self
, type_
):
242 def __call__(self
, name
, **kwargs
):
244 return self
.registry
[name
]
246 n
= self
.registry
[name
] = self
.type(name
, **kwargs
)
250 return self
.registry
.get(name
)
253 class VkExtension(object):
254 """Simple struct-like class representing extensions"""
256 def __init__(self
, name
, number
=None, define
=None):
262 class VkEnum(object):
263 """Simple struct-like class representing a single Vulkan Enum."""
265 def __init__(self
, name
, values
=None):
267 self
.extension
= None
268 # Maps numbers to names
269 self
.values
= values
or dict()
270 self
.name_to_value
= dict()
273 def add_value(self
, name
, value
=None,
274 extnum
=None, offset
=None,
276 assert value
is not None or extnum
is not None
278 value
= 1000000000 + (extnum
- 1) * 1000 + offset
282 self
.name_to_value
[name
] = value
283 if value
not in self
.values
:
284 self
.values
[value
] = name
285 elif len(self
.values
[value
]) > len(name
):
286 self
.values
[value
] = name
288 def add_value_from_xml(self
, elem
, extension
=None):
289 self
.extension
= extension
290 if 'value' in elem
.attrib
:
291 self
.add_value(elem
.attrib
['name'],
292 value
=int(elem
.attrib
['value'], base
=0))
293 elif 'alias' in elem
.attrib
:
294 self
.add_value(elem
.attrib
['name'],
295 value
=self
.name_to_value
[elem
.attrib
['alias']])
297 error
= 'dir' in elem
.attrib
and elem
.attrib
['dir'] == '-'
298 if 'extnumber' in elem
.attrib
:
299 extnum
= int(elem
.attrib
['extnumber'])
301 extnum
= extension
.number
302 self
.add_value(elem
.attrib
['name'],
304 offset
=int(elem
.attrib
['offset']),
307 def set_guard(self
, g
):
311 class VkCommand(object):
312 """Simple struct-like class representing a single Vulkan command"""
314 def __init__(self
, name
, device_entrypoint
=False):
316 self
.device_entrypoint
= device_entrypoint
317 self
.extension
= None
320 class VkChainStruct(object):
321 """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType"""
322 def __init__(self
, name
, stype
):
325 self
.extension
= None
328 def struct_get_stype(xml_node
):
329 for member
in xml_node
.findall('./member'):
330 name
= member
.findall('./name')
331 if len(name
) > 0 and name
[0].text
== "sType":
332 return member
.get('values')
336 def parse_xml(cmd_factory
, enum_factory
, ext_factory
, struct_factory
, filename
):
337 """Parse the XML file. Accumulate results into the factories.
339 This parser is a memory efficient iterative XML parser that returns a list
343 xml
= et
.parse(filename
)
345 for enum_type
in xml
.findall('./enums[@type="enum"]'):
346 enum
= enum_factory(enum_type
.attrib
['name'])
347 for value
in enum_type
.findall('./enum'):
348 enum
.add_value_from_xml(value
)
350 for value
in xml
.findall('./feature/require/enum[@extends]'):
351 enum
= enum_factory
.get(value
.attrib
['extends'])
353 enum
.add_value_from_xml(value
)
355 for command
in xml
.findall('./commands/command'):
356 name
= command
.find('./proto/name')
357 first_arg
= command
.find('./param/type')
358 # Some commands are alias KHR -> nonKHR, ignore those
360 cmd_factory(name
.text
,
361 device_entrypoint
=(first_arg
.text
in ('VkDevice', 'VkCommandBuffer', 'VkQueue')))
363 for struct_type
in xml
.findall('./types/type[@category="struct"]'):
364 name
= struct_type
.attrib
['name']
365 stype
= struct_get_stype(struct_type
)
366 if stype
is not None:
367 struct_factory(name
, stype
=stype
)
370 for platform
in xml
.findall('./platforms/platform'):
371 name
= platform
.attrib
['name']
372 define
= platform
.attrib
['protect']
373 platform_define
[name
] = define
375 for ext_elem
in xml
.findall('./extensions/extension[@supported="vulkan"]'):
377 if "platform" in ext_elem
.attrib
:
378 define
= platform_define
[ext_elem
.attrib
['platform']]
379 extension
= ext_factory(ext_elem
.attrib
['name'],
380 number
=int(ext_elem
.attrib
['number']),
383 for value
in ext_elem
.findall('./require/enum[@extends]'):
384 enum
= enum_factory
.get(value
.attrib
['extends'])
386 enum
.add_value_from_xml(value
, extension
)
387 for t
in ext_elem
.findall('./require/type'):
388 struct
= struct_factory
.get(t
.attrib
['name'])
389 if struct
is not None:
390 struct
.extension
= extension
393 for value
in ext_elem
.findall('./require/type[@name]'):
394 enum
= enum_factory
.get(value
.attrib
['name'])
396 enum
.set_guard(define
)
398 for t
in ext_elem
.findall('./require/command'):
399 command
= cmd_factory
.get(t
.attrib
['name'])
400 if command
is not None:
401 command
.extension
= extension
405 parser
= argparse
.ArgumentParser()
406 parser
.add_argument('--xml', required
=True,
407 help='Vulkan API XML files',
410 parser
.add_argument('--outdir',
411 help='Directory to put the generated files in',
414 args
= parser
.parse_args()
416 command_factory
= NamedFactory(VkCommand
)
417 enum_factory
= NamedFactory(VkEnum
)
418 ext_factory
= NamedFactory(VkExtension
)
419 struct_factory
= NamedFactory(VkChainStruct
)
420 for filename
in args
.xml_files
:
421 parse_xml(command_factory
, enum_factory
, ext_factory
, struct_factory
, filename
)
422 commands
= sorted(command_factory
.registry
.values(), key
=lambda e
: e
.name
)
423 enums
= sorted(enum_factory
.registry
.values(), key
=lambda e
: e
.name
)
424 extensions
= sorted(ext_factory
.registry
.values(), key
=lambda e
: e
.name
)
425 structs
= sorted(struct_factory
.registry
.values(), key
=lambda e
: e
.name
)
427 for template
, file_
in [(C_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.c')),
428 (H_TEMPLATE
, os
.path
.join(args
.outdir
, 'vk_enum_to_str.h'))]:
429 with
open(file_
, 'wb') as f
:
430 f
.write(template
.render(
431 file=os
.path
.basename(__file__
),
434 extensions
=extensions
,
437 FOREIGN_ENUM_VALUES
=FOREIGN_ENUM_VALUES
))
440 if __name__
== '__main__':