X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fvulkan%2Futil%2Fgen_enum_to_str.py;h=ebaf2a1a0ccb1e923122dedd7c367832ecfb24a4;hb=323d5bbfd9a1d6684bb5381b67b8965ea98d5fc0;hp=c615ed08c48d57d58e554ef3fc472fa2b1ddb56c;hpb=935b42d9bc92db11a1b0d471c6de368b49a1604c;p=mesa.git diff --git a/src/vulkan/util/gen_enum_to_str.py b/src/vulkan/util/gen_enum_to_str.py index c615ed08c48..ebaf2a1a0cc 100644 --- a/src/vulkan/util/gen_enum_to_str.py +++ b/src/vulkan/util/gen_enum_to_str.py @@ -25,7 +25,7 @@ from __future__ import print_function import argparse import os import textwrap -import xml.etree.cElementTree as et +import xml.etree.ElementTree as et from mako.template import Template @@ -57,6 +57,7 @@ C_TEMPLATE = Template(textwrap.dedent(u"""\ ${copyright} */ + #include #include #include #include "util/macros.h" @@ -64,28 +65,86 @@ C_TEMPLATE = Template(textwrap.dedent(u"""\ % for enum in enums: + % if enum.guard: +#ifdef ${enum.guard} + % endif const char * vk_${enum.name[2:]}_to_str(${enum.name} input) { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wswitch" switch(input) { - % for v in enum.values: - % if v in FOREIGN_ENUM_VALUES: + % for v in sorted(enum.values.keys()): + case ${v}: + return "${enum.values[v]}"; + % endfor + } + #pragma GCC diagnostic pop + unreachable("Undefined enum value."); + } + + % if enum.guard: +#endif + % endif + %endfor - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wswitch" + size_t vk_structure_type_size(const struct VkBaseInStructure *item) + { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wswitch" + switch(item->sType) { + % for struct in structs: + % if struct.extension is not None and struct.extension.define is not None: + #ifdef ${struct.extension.define} + case ${struct.stype}: return sizeof(${struct.name}); + #endif + % else: + case ${struct.stype}: return sizeof(${struct.name}); + % endif + %endfor + } + #pragma GCC diagnostic pop + unreachable("Undefined struct type."); + } + + void vk_load_instance_commands(VkInstance instance, + PFN_vkGetInstanceProcAddr gpa, + struct vk_instance_dispatch_table *table) + { + memset(table, 0, sizeof(*table)); + table->GetInstanceProcAddr = gpa; + % for cmd in commands: + % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr': + % if cmd.extension is not None and cmd.extension.define is not None: + #ifdef ${cmd.extension.define} + table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}"); + #endif + % else: + table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(instance, "${cmd.name}"); % endif - case ${v}: - return "${v}"; - % if v in FOREIGN_ENUM_VALUES: - #pragma GCC diagnostic pop + % endif + %endfor + } + void vk_load_device_commands(VkDevice device, + PFN_vkGetDeviceProcAddr gpa, + struct vk_device_dispatch_table *table) + { + memset(table, 0, sizeof(*table)); + table->GetDeviceProcAddr = gpa; + % for cmd in commands: + % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr': + % if cmd.extension is not None and cmd.extension.define is not None: + #ifdef ${cmd.extension.define} + table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}"); + #endif + % else: + table->${cmd.name[2:]} = (PFN_${cmd.name}) gpa(device, "${cmd.name}"); % endif - % endfor - default: - unreachable("Undefined enum value."); - } + % endif + %endfor } - %endfor"""), + """), output_encoding='utf-8') H_TEMPLATE = Template(textwrap.dedent(u"""\ @@ -101,73 +160,252 @@ H_TEMPLATE = Template(textwrap.dedent(u"""\ #include #include + #ifdef __cplusplus + extern "C" { + #endif + + % for ext in extensions: + #define _${ext.name}_number (${ext.number}) + % endfor + % for enum in enums: + % if enum.guard: +#ifdef ${enum.guard} + % endif const char * vk_${enum.name[2:]}_to_str(${enum.name} input); + % if enum.guard: +#endif + % endif % endfor + size_t vk_structure_type_size(const struct VkBaseInStructure *item); + + struct vk_instance_dispatch_table { + PFN_vkGetInstanceProcAddr GetInstanceProcAddr; + % for cmd in commands: + % if not cmd.device_entrypoint and cmd.name != 'vkGetInstanceProcAddr': + % if cmd.extension is not None and cmd.extension.define is not None: + #ifdef ${cmd.extension.define} + PFN_${cmd.name} ${cmd.name[2:]}; + #endif + % else: + PFN_${cmd.name} ${cmd.name[2:]}; + % endif + % endif + %endfor + }; + + struct vk_device_dispatch_table { + PFN_vkGetDeviceProcAddr GetDeviceProcAddr; + % for cmd in commands: + % if cmd.device_entrypoint and cmd.name != 'vkGetDeviceProcAddr': + % if cmd.extension is not None and cmd.extension.define is not None: + #ifdef ${cmd.extension.define} + PFN_${cmd.name} ${cmd.name[2:]}; + #endif + % else: + PFN_${cmd.name} ${cmd.name[2:]}; + % endif + % endif + %endfor + }; + + void vk_load_instance_commands(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, struct vk_instance_dispatch_table *table); + void vk_load_device_commands(VkDevice device, PFN_vkGetDeviceProcAddr gpa, struct vk_device_dispatch_table *table); + + #ifdef __cplusplus + } /* extern "C" */ + #endif + #endif"""), output_encoding='utf-8') -# These enums are defined outside their respective enum blocks, and thus cause -# -Wswitch warnings. -FOREIGN_ENUM_VALUES = [ - "VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID", -] - -class EnumFactory(object): +class NamedFactory(object): """Factory for creating enums.""" def __init__(self, type_): self.registry = {} self.type = type_ - def __call__(self, name): + def __call__(self, name, **kwargs): try: return self.registry[name] except KeyError: - n = self.registry[name] = self.type(name) + n = self.registry[name] = self.type(name, **kwargs) return n + def get(self, name): + return self.registry.get(name) + + +class VkExtension(object): + """Simple struct-like class representing extensions""" + + def __init__(self, name, number=None, define=None): + self.name = name + self.number = number + self.define = define + class VkEnum(object): """Simple struct-like class representing a single Vulkan Enum.""" def __init__(self, name, values=None): self.name = name - self.values = values or [] + self.extension = None + # Maps numbers to names + self.values = values or dict() + self.name_to_value = dict() + self.guard = None + self.name_to_alias_list = {} + + def add_value(self, name, value=None, + extnum=None, offset=None, alias=None, + error=False): + if alias is not None: + assert value is None and offset is None + if alias not in self.name_to_value: + # We don't have this alias yet. Just record the alias and + # we'll deal with it later. + alias_list = self.name_to_alias_list.get(alias, []) + alias_list.append(name); + return + + # Use the value from the alias + value = self.name_to_value[alias] + + assert value is not None or extnum is not None + if value is None: + value = 1000000000 + (extnum - 1) * 1000 + offset + if error: + value = -value + + self.name_to_value[name] = value + if value not in self.values: + self.values[value] = name + elif len(self.values[value]) > len(name): + self.values[value] = name + + # Now that the value has been fully added, resolve aliases, if any. + if name in self.name_to_alias_list: + for alias in self.name_to_alias_list[name]: + add_value(alias, value) + del self.name_to_alias_list[name] + + def add_value_from_xml(self, elem, extension=None): + self.extension = extension + if 'value' in elem.attrib: + self.add_value(elem.attrib['name'], + value=int(elem.attrib['value'], base=0)) + elif 'alias' in elem.attrib: + self.add_value(elem.attrib['name'], alias=elem.attrib['alias']) + else: + error = 'dir' in elem.attrib and elem.attrib['dir'] == '-' + if 'extnumber' in elem.attrib: + extnum = int(elem.attrib['extnumber']) + else: + extnum = extension.number + self.add_value(elem.attrib['name'], + extnum=extnum, + offset=int(elem.attrib['offset']), + error=error) + + def set_guard(self, g): + self.guard = g + + +class VkCommand(object): + """Simple struct-like class representing a single Vulkan command""" + + def __init__(self, name, device_entrypoint=False): + self.name = name + self.device_entrypoint = device_entrypoint + self.extension = None -def parse_xml(efactory, filename): - """Parse the XML file. Accumulate results into the efactory. +class VkChainStruct(object): + """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType""" + def __init__(self, name, stype): + self.name = name + self.stype = stype + self.extension = None - This parser is a memory efficient iterative XML parser that returns a list - of VkEnum objects. - """ - with open(filename, 'rb') as f: - context = iter(et.iterparse(f, events=('start', 'end'))) +def struct_get_stype(xml_node): + for member in xml_node.findall('./member'): + name = member.findall('./name') + if len(name) > 0 and name[0].text == "sType": + return member.get('values') + return None - # This gives the root element, since goal is to iterate over the - # elements without building a tree, this allows the root to be cleared - # (erase the elements) after the children have been processed. - _, root = next(context) - for event, elem in context: - if event == 'end' and elem.tag == 'enums': - type_ = elem.attrib.get('type') - if type_ == 'enum': - enum = efactory(elem.attrib['name']) - enum.values.extend([e.attrib['name'] for e in elem - if e.tag == 'enum']) - elif event == 'end' and elem.tag == 'extension': - if elem.attrib['supported'] != 'vulkan': - continue - for e in elem.findall('.//enum[@extends][@offset]'): - enum = efactory(e.attrib['extends']) - enum.values.append(e.attrib['name']) +def parse_xml(cmd_factory, enum_factory, ext_factory, struct_factory, filename): + """Parse the XML file. Accumulate results into the factories. + + This parser is a memory efficient iterative XML parser that returns a list + of VkEnum objects. + """ - root.clear() + xml = et.parse(filename) + + for enum_type in xml.findall('./enums[@type="enum"]'): + enum = enum_factory(enum_type.attrib['name']) + for value in enum_type.findall('./enum'): + enum.add_value_from_xml(value) + + for value in xml.findall('./feature/require/enum[@extends]'): + enum = enum_factory.get(value.attrib['extends']) + if enum is not None: + enum.add_value_from_xml(value) + + for command in xml.findall('./commands/command'): + name = command.find('./proto/name') + first_arg = command.find('./param/type') + # Some commands are alias KHR -> nonKHR, ignore those + if name is not None: + cmd_factory(name.text, + device_entrypoint=(first_arg.text in ('VkDevice', 'VkCommandBuffer', 'VkQueue'))) + + for struct_type in xml.findall('./types/type[@category="struct"]'): + name = struct_type.attrib['name'] + stype = struct_get_stype(struct_type) + if stype is not None: + struct_factory(name, stype=stype) + + platform_define = {} + for platform in xml.findall('./platforms/platform'): + name = platform.attrib['name'] + define = platform.attrib['protect'] + platform_define[name] = define + + for ext_elem in xml.findall('./extensions/extension[@supported="vulkan"]'): + define = None + if "platform" in ext_elem.attrib: + define = platform_define[ext_elem.attrib['platform']] + extension = ext_factory(ext_elem.attrib['name'], + number=int(ext_elem.attrib['number']), + define=define) + + for value in ext_elem.findall('./require/enum[@extends]'): + enum = enum_factory.get(value.attrib['extends']) + if enum is not None: + enum.add_value_from_xml(value, extension) + for t in ext_elem.findall('./require/type'): + struct = struct_factory.get(t.attrib['name']) + if struct is not None: + struct.extension = extension + + if define: + for value in ext_elem.findall('./require/type[@name]'): + enum = enum_factory.get(value.attrib['name']) + if enum is not None: + enum.set_guard(define) + + for t in ext_elem.findall('./require/command'): + command = cmd_factory.get(t.attrib['name']) + if command is not None: + command.extension = extension def main(): @@ -182,19 +420,27 @@ def main(): args = parser.parse_args() - efactory = EnumFactory(VkEnum) + command_factory = NamedFactory(VkCommand) + enum_factory = NamedFactory(VkEnum) + ext_factory = NamedFactory(VkExtension) + struct_factory = NamedFactory(VkChainStruct) for filename in args.xml_files: - parse_xml(efactory, filename) - enums = sorted(efactory.registry.values(), key=lambda e: e.name) + parse_xml(command_factory, enum_factory, ext_factory, struct_factory, filename) + commands = sorted(command_factory.registry.values(), key=lambda e: e.name) + enums = sorted(enum_factory.registry.values(), key=lambda e: e.name) + extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name) + structs = sorted(struct_factory.registry.values(), key=lambda e: e.name) for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')), (H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h'))]: with open(file_, 'wb') as f: f.write(template.render( file=os.path.basename(__file__), + commands=commands, enums=enums, - copyright=COPYRIGHT, - FOREIGN_ENUM_VALUES=FOREIGN_ENUM_VALUES)) + extensions=extensions, + structs=structs, + copyright=COPYRIGHT)) if __name__ == '__main__':