1
# Copyright © 2017 Intel Corporation
3
# Permission is hereby granted, free of charge, to any person obtaining a copy
4
# of this software and associated documentation files (the "Software"), to deal
5
# in the Software without restriction, including without limitation the rights
6
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
# copies of the Software, and to permit persons to whom the Software is
8
# furnished to do so, subject to the following conditions:
10
# The above copyright notice and this permission notice shall be included in
11
# all copies or substantial portions of the Software.
13
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
"""Create enum to string functions for vulkan using vk.xml."""
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 <vulkan/vk_layer.h>
64
#include "util/macros.h"
65
#include "vk_enum_to_str.h"
73
vk_${enum.name[2:]}_to_str(${enum.name} input)
75
switch((int64_t)input) {
76
% for v in sorted(enum.values.keys()):
78
return "${enum.values[v]}";
80
case ${enum.max_enum_name}: return "${enum.max_enum_name}";
82
return "Unknown ${enum.name} value.";
91
size_t vk_structure_type_size(const struct VkBaseInStructure *item)
93
switch((int)item->sType) {
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});
103
case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: return sizeof(VkLayerInstanceCreateInfo);
104
case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: return sizeof(VkLayerDeviceCreateInfo);
106
unreachable("Undefined struct type.");
111
vk_ObjectType_to_ObjectName(VkObjectType type)
114
% for object_type in sorted(object_types[0].enum_to_name.keys()):
116
return "${object_types[0].enum_to_name[object_type]}";
119
return "Unknown VkObjectType value.";
124
H_TEMPLATE = Template(textwrap.dedent(u"""\
125
/* Autogenerated file -- do not edit
126
* generated by ${file}
131
#ifndef MESA_VK_ENUM_TO_STR_H
132
#define MESA_VK_ENUM_TO_STR_H
134
#include <vulkan/vulkan.h>
135
#include <vulkan/vk_android_native_buffer.h>
145
const char * vk_${enum.name[2:]}_to_str(${enum.name} input);
151
size_t vk_structure_type_size(const struct VkBaseInStructure *item);
153
const char * vk_ObjectType_to_ObjectName(VkObjectType type);
162
H_DEFINE_TEMPLATE = Template(textwrap.dedent(u"""\
163
/* Autogenerated file -- do not edit
164
* generated by ${file}
169
#ifndef MESA_VK_ENUM_DEFINES_H
170
#define MESA_VK_ENUM_DEFINES_H
172
#include <vulkan/vulkan.h>
173
#include <vulkan/vk_android_native_buffer.h>
179
% for ext in extensions:
180
#define _${ext.name}_number (${ext.number})
183
% for enum in bitmasks:
184
% if enum.bitwidth > 32:
190
#define ${enum.all_bits_name()} ${hex(enum.all_bits_value())}u
196
% for enum in bitmasks:
197
% if enum.bitwidth < 64:
200
/* Redefine bitmask values of ${enum.name} */
204
% for n, v in enum.name_to_value.items():
205
#define ${n} (${hex(v)}ULL)
219
class NamedFactory(object):
220
"""Factory for creating enums."""
222
def __init__(self, type_):
226
def __call__(self, name, **kwargs):
228
return self.registry[name]
230
n = self.registry[name] = self.type(name, **kwargs)
234
return self.registry.get(name)
237
class VkExtension(object):
238
"""Simple struct-like class representing extensions"""
240
def __init__(self, name, number=None, define=None):
246
def CamelCase_to_SHOUT_CASE(s):
247
return (s[:1] + re.sub(r'(?<![A-Z])([A-Z])', r'_\1', s[1:])).upper()
249
def compute_max_enum_name(s):
250
max_enum_name = CamelCase_to_SHOUT_CASE(s)
251
last_prefix = max_enum_name.rsplit('_', 1)[-1]
252
# Those special prefixes need to be always at the end
253
if last_prefix in ['AMD', 'EXT', 'INTEL', 'KHR', 'NV'] :
254
max_enum_name = "_".join(max_enum_name.split('_')[:-1])
255
max_enum_name = max_enum_name + "_MAX_ENUM_" + last_prefix
257
max_enum_name = max_enum_name + "_MAX_ENUM"
261
class VkEnum(object):
262
"""Simple struct-like class representing a single Vulkan Enum."""
264
def __init__(self, name, bitwidth=32, values=None):
266
self.max_enum_name = compute_max_enum_name(name)
267
self.bitwidth = bitwidth
268
self.extension = None
269
# Maps numbers to names
270
self.values = values or dict()
271
self.name_to_value = dict()
273
self.name_to_alias_list = {}
275
def all_bits_name(self):
276
assert self.name.startswith('Vk')
277
assert re.search(r'FlagBits[A-Z]*$', self.name)
279
return 'VK_ALL_' + CamelCase_to_SHOUT_CASE(self.name[2:])
281
def all_bits_value(self):
282
return functools.reduce(lambda a,b: a | b, self.values.keys(), 0)
284
def add_value(self, name, value=None,
285
extnum=None, offset=None, alias=None,
287
if alias is not None:
288
assert value is None and offset is None
289
if alias not in self.name_to_value:
290
# We don't have this alias yet. Just record the alias and
291
# we'll deal with it later.
292
alias_list = self.name_to_alias_list.setdefault(alias, [])
293
alias_list.append(name);
296
# Use the value from the alias
297
value = self.name_to_value[alias]
299
assert value is not None or extnum is not None
301
value = 1000000000 + (extnum - 1) * 1000 + offset
305
self.name_to_value[name] = value
306
if value not in self.values:
307
self.values[value] = name
308
elif len(self.values[value]) > len(name):
309
self.values[value] = name
311
# Now that the value has been fully added, resolve aliases, if any.
312
if name in self.name_to_alias_list:
313
for alias in self.name_to_alias_list[name]:
314
self.add_value(alias, value)
315
del self.name_to_alias_list[name]
317
def add_value_from_xml(self, elem, extension=None):
318
self.extension = extension
319
if 'value' in elem.attrib:
320
self.add_value(elem.attrib['name'],
321
value=int(elem.attrib['value'], base=0))
322
elif 'bitpos' in elem.attrib:
323
self.add_value(elem.attrib['name'],
324
value=(1 << int(elem.attrib['bitpos'], base=0)))
325
elif 'alias' in elem.attrib:
326
self.add_value(elem.attrib['name'], alias=elem.attrib['alias'])
328
error = 'dir' in elem.attrib and elem.attrib['dir'] == '-'
329
if 'extnumber' in elem.attrib:
330
extnum = int(elem.attrib['extnumber'])
332
extnum = extension.number
333
self.add_value(elem.attrib['name'],
335
offset=int(elem.attrib['offset']),
338
def set_guard(self, g):
342
class VkChainStruct(object):
343
"""Simple struct-like class representing a single Vulkan struct identified with a VkStructureType"""
344
def __init__(self, name, stype):
347
self.extension = None
350
def struct_get_stype(xml_node):
351
for member in xml_node.findall('./member'):
352
name = member.findall('./name')
353
if len(name) > 0 and name[0].text == "sType":
354
return member.get('values')
357
class VkObjectType(object):
358
"""Simple struct-like class representing a single Vulkan object type"""
359
def __init__(self, name):
361
self.enum_to_name = dict()
364
def parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory,
365
obj_type_factory, filename):
366
"""Parse the XML file. Accumulate results into the factories.
368
This parser is a memory efficient iterative XML parser that returns a list
372
xml = et.parse(filename)
374
for enum_type in xml.findall('./enums[@type="enum"]'):
375
enum = enum_factory(enum_type.attrib['name'])
376
for value in enum_type.findall('./enum'):
377
enum.add_value_from_xml(value)
379
# For bitmask we only add the Enum selected for convenience.
380
for enum_type in xml.findall('./enums[@type="bitmask"]'):
381
bitwidth = int(enum_type.attrib.get('bitwidth', 32))
382
enum = bitmask_factory(enum_type.attrib['name'], bitwidth=bitwidth)
383
for value in enum_type.findall('./enum'):
384
enum.add_value_from_xml(value)
386
for value in xml.findall('./feature/require/enum[@extends]'):
387
extends = value.attrib['extends']
388
enum = enum_factory.get(extends)
390
enum.add_value_from_xml(value)
391
enum = bitmask_factory.get(extends)
393
enum.add_value_from_xml(value)
395
for struct_type in xml.findall('./types/type[@category="struct"]'):
396
name = struct_type.attrib['name']
397
stype = struct_get_stype(struct_type)
398
if stype is not None:
399
struct_factory(name, stype=stype)
402
for platform in xml.findall('./platforms/platform'):
403
name = platform.attrib['name']
404
define = platform.attrib['protect']
405
platform_define[name] = define
407
for ext_elem in xml.findall('./extensions/extension[@supported="vulkan"]'):
409
if "platform" in ext_elem.attrib:
410
define = platform_define[ext_elem.attrib['platform']]
411
extension = ext_factory(ext_elem.attrib['name'],
412
number=int(ext_elem.attrib['number']),
415
for value in ext_elem.findall('./require/enum[@extends]'):
416
extends = value.attrib['extends']
417
enum = enum_factory.get(extends)
419
enum.add_value_from_xml(value, extension)
420
enum = bitmask_factory.get(extends)
422
enum.add_value_from_xml(value, extension)
423
for t in ext_elem.findall('./require/type'):
424
struct = struct_factory.get(t.attrib['name'])
425
if struct is not None:
426
struct.extension = extension
429
for value in ext_elem.findall('./require/type[@name]'):
430
enum = enum_factory.get(value.attrib['name'])
432
enum.set_guard(define)
434
obj_types = obj_type_factory("VkObjectType")
435
for object_type in xml.findall('./types/type[@category="handle"]'):
436
for object_name in object_type.findall('./name'):
437
# Convert to int to avoid undefined enums
438
enum = object_type.attrib['objtypeenum']
439
enum_val = enum_factory.get("VkObjectType").name_to_value[enum]
440
obj_types.enum_to_name[enum_val] = object_name.text
444
parser = argparse.ArgumentParser()
445
parser.add_argument('--xml', required=True,
446
help='Vulkan API XML files',
449
parser.add_argument('--outdir',
450
help='Directory to put the generated files in',
453
args = parser.parse_args()
455
enum_factory = NamedFactory(VkEnum)
456
ext_factory = NamedFactory(VkExtension)
457
struct_factory = NamedFactory(VkChainStruct)
458
obj_type_factory = NamedFactory(VkObjectType)
459
bitmask_factory = NamedFactory(VkEnum)
461
for filename in args.xml_files:
462
parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory,
463
obj_type_factory, filename)
464
enums = sorted(enum_factory.registry.values(), key=lambda e: e.name)
465
extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name)
466
structs = sorted(struct_factory.registry.values(), key=lambda e: e.name)
467
bitmasks = sorted(bitmask_factory.registry.values(), key=lambda e: e.name)
468
object_types = sorted(obj_type_factory.registry.values(), key=lambda e: e.name)
470
for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')),
471
(H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h')),
472
(H_DEFINE_TEMPLATE, os.path.join(args.outdir, 'vk_enum_defines.h'))]:
473
with open(file_, 'w', encoding='utf-8') as f:
474
f.write(template.render(
475
file=os.path.basename(__file__),
477
extensions=extensions,
480
object_types=object_types,
481
copyright=COPYRIGHT))
484
if __name__ == '__main__':