diff options
| author | Charles Giessen <charles@lunarg.com> | 2019-08-13 11:16:59 -0600 |
|---|---|---|
| committer | Charles Giessen <46324611+charles-lunarg@users.noreply.github.com> | 2019-10-04 09:14:44 -0600 |
| commit | 623d1cc06173a7e209affe6030311abc464beb74 (patch) | |
| tree | 68c33ef0491ab8d5515e5a9a3019bb1680f53124 /scripts/vulkaninfo_generator.py | |
| parent | 7513420a385869903b907d2d42e3ee93f93fa551 (diff) | |
| download | usermoji-623d1cc06173a7e209affe6030311abc464beb74.tar.xz | |
vulkaninfo: Major Refactor
Rewrote vulkan info to use C++ and include autogen capabilities
Properties and Features are now populated based on the xml spec
Improved readability and robustness by seperating vulkan
info gathering, formatting, and printing into seperate files
Files Added:
- scripts/generate_vulkaninfo.py
- vulkaninfo/vulkaninfo.h
- vulkaninfo/vulkaninfo.cpp
- vulkaninfo/outputprinter.h
- vulkaninfo/generated/vulkaninfo.hpp
- vulkaninfo/generated/.clang-format
Files Modified:
- scripts/kvt_genvk.py
- vulkaninfo/CMakeLists.txt
- vulkaninfo/macOS/vulkaninfo.cmake
Files Removed:
- vulkaninfo/vulkaninfo.c
Change-Id: I8042a6a7949595b75f03d1f3ba48e221d2cc0e8a
Diffstat (limited to 'scripts/vulkaninfo_generator.py')
| -rw-r--r-- | scripts/vulkaninfo_generator.py | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/scripts/vulkaninfo_generator.py b/scripts/vulkaninfo_generator.py new file mode 100644 index 00000000..10d5cac2 --- /dev/null +++ b/scripts/vulkaninfo_generator.py @@ -0,0 +1,855 @@ +#!/usr/bin/python3 +# +# Copyright (c) 2019 Valve Corporation +# Copyright (c) 2019 LunarG, Inc. +# Copyright (c) 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: Charles Giessen <charles@lunarg.com> + +import os +import re +import sys +import string +import xml.etree.ElementTree as etree +import generator as gen +import operator +from collections import namedtuple +from collections import OrderedDict +from generator import * +from common_codegen import * + +license_header = ''' +/* + * Copyright (c) 2019 The Khronos Group Inc. + * Copyright (c) 2019 Valve Corporation + * Copyright (c) 2019 LunarG, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Charles Giessen <charles@lunarg.com> + * + */ + +/* + * This file is generated from the Khronos Vulkan XML API Registry. + */ +''' + +custom_formaters = ''' +std::ostream &operator<<(std::ostream &o, VkConformanceVersionKHR &c) { + return o << std::to_string(c.major) << "." << std::to_string(c.minor) << "." << std::to_string(c.subminor) << "." + << std::to_string(c.patch); +} + +std::string VkExtent3DString(VkExtent3D e) { + return std::string("(") + std::to_string(e.width) + ", " + std::to_string(e.height) + ", " + std::to_string(e.depth) + ")"; +} + +template <typename T> +std::string to_hex_str(T i) { + std::stringstream stream; + stream << "0x" << std::setfill('0') << std::setw(sizeof(T)) << std::hex << i; + return stream.str(); +} + +template <typename T> +std::string to_hex_str(Printer &p, T i) { + if (p.Type() == OutputType::json) + return std::to_string(i); + else + return to_hex_str(i); +} +''' + +# used in the .cpp code +structures_to_gen = ['VkExtent3D', 'VkExtent2D', 'VkPhysicalDeviceLimits', 'VkPhysicalDeviceFeatures', + 'VkPhysicalDeviceSparseProperties', 'VkSurfaceCapabilitiesKHR', 'VkSurfaceFormatKHR', 'VkLayerProperties'] +enums_to_gen = ['VkResult', 'VkFormat', 'VkPresentModeKHR', + 'VkPhysicalDeviceType', 'VkImageTiling'] +flags_to_gen = ['VkSurfaceTransformFlagsKHR', 'VkCompositeAlphaFlagsKHR', + 'VkDeviceGroupPresentModeFlagsKHR', 'VkFormatFeatureFlags', 'VkMemoryPropertyFlags', 'VkMemoryHeapFlags'] +flags_strings_to_gen = ['VkQueueFlags'] + +# iostream or custom outputter handles these types +predefined_types = ['char', 'VkBool32', 'uint32_t', 'uint8_t', 'int32_t', + 'float', 'uint64_t', 'size_t', 'VkDeviceSize', 'VkConformanceVersionKHR'] +# need list of venders to blacklist vendor extensions +vendor_abbreviations = ['_IMG', '_AMD', '_AMDX', '_ARM', '_FSL', '_BRCM', '_NXP', '_NV', '_NVX', '_VIV', '_VSI', '_KDAB', + '_ANDROID', '_CHROMIUM', '_FUCHSIA', '_GGP', '_GOOGLE', '_QCOM', '_LUNARG', '_SAMSUNG', '_SEC', '_TIZEN', + '_RENDERDOC', '_NN', '_MVK', '_KHX', '_MESA', '_INTEL'] + +# Types that need pNext Chains built. 'extends' is the xml tag used in the structextends member. 'type' can be device, instance, or both +EXTENSION_CATEGORIES = {'phys_device_props2': {'extends': 'VkPhysicalDeviceProperties2', 'type': 'device'}, + 'phys_device_mem_props2': {'extends': 'VkPhysicalDeviceMemoryProperties2', 'type': 'device'}, + 'phys_device_features2': {'extends': 'VkPhysicalDeviceFeatures2,VkDeviceCreateInfo', 'type': 'device'}, + 'surface_capabilities2': {'extends': 'VkSurfaceCapabilities2KHR', 'type': 'both'}, + 'format_properties2': {'extends': 'VkFormatProperties2', 'type': 'device'} + } + + +class VulkanInfoGeneratorOptions(GeneratorOptions): + def __init__(self, + conventions=None, + input=None, + filename=None, + directory='.', + apiname=None, + profile=None, + versions='.*', + emitversions='.*', + defaultExtensions=None, + addExtensions=None, + removeExtensions=None, + emitExtensions=None, + sortProcedure=None, + prefixText="", + genFuncPointers=True, + protectFile=True, + protectFeature=True, + protectProto=None, + protectProtoStr=None, + apicall='', + apientry='', + apientryp='', + indentFuncProto=True, + indentFuncPointer=False, + alignFuncParam=0, + expandEnumerants=True, + ): + GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile, + versions, emitversions, defaultExtensions, + addExtensions, removeExtensions, emitExtensions, sortProcedure) + self.input = input + self.prefixText = prefixText + self.genFuncPointers = genFuncPointers + self.protectFile = protectFile + self.protectFeature = protectFeature + self.protectProto = protectProto + self.protectProtoStr = protectProtoStr + self.apicall = apicall + self.apientry = apientry + self.apientryp = apientryp + self.indentFuncProto = indentFuncProto + self.indentFuncPointer = indentFuncPointer + self.alignFuncParam = alignFuncParam + +# VulkanInfoGenerator - subclass of OutputGenerator. +# Generates a vulkan info output helper function + + +class VulkanInfoGenerator(OutputGenerator): + + def __init__(self, + errFile=sys.stderr, + warnFile=sys.stderr, + diagFile=sys.stdout): + OutputGenerator.__init__(self, errFile, warnFile, diagFile) + + self.constants = OrderedDict() + + self.extension_sets = OrderedDict() + for ext_cat in EXTENSION_CATEGORIES.keys(): + self.extension_sets[ext_cat] = set() + + self.enums = set() + self.flags = set() + self.bitmasks = set() + self.structures = set() + self.all_structures = set() + + self.types_to_gen = set() + + self.extFuncs = OrderedDict() + self.extTypes = OrderedDict() + self.extensions = set() + + def beginFile(self, genOpts): + gen.OutputGenerator.beginFile(self, genOpts) + + root = self.registry.reg + + for node in self.registry.reg.findall('enums'): + if node.get('name') == 'API Constants': + for item in node.findall('enum'): + self.constants[item.get('name')] = item.get('value') + + for node in root.find('extensions').findall('extension'): + ext = VulkanExtension(node) + self.extensions.add(ext) + for item in ext.vktypes: + self.extTypes[item] = ext + for item in ext.vkfuncs: + self.extFuncs[item] = ext + + def endFile(self): + types_to_gen = set() + for s in enums_to_gen: + types_to_gen.add(s) + + for f in flags_to_gen: + types_to_gen.add(f) + + types_to_gen = types_to_gen.union(GatherTypesToGen(self.structures)) + for key, value in EXTENSION_CATEGORIES.items(): + types_to_gen = types_to_gen.union( + GatherTypesToGen(self.extension_sets[key])) + + self.enums = sorted(self.enums, key=operator.attrgetter('name')) + self.flags = sorted(self.flags, key=operator.attrgetter('name')) + self.bitmasks = sorted(self.bitmasks, key=operator.attrgetter('name')) + self.structures = sorted( + self.structures, key=operator.attrgetter('name')) + self.all_structures = sorted( + self.all_structures, key=operator.attrgetter('name')) + + for key, value in self.extension_sets.items(): + self.extension_sets[key] = sorted( + value, key=operator.attrgetter('name')) + + out = '' + out += license_header + "\n" + out += "#include \"vulkaninfo.h\"\n" + out += "#include \"outputprinter.h\"\n" + out += custom_formaters + + for e in self.enums: + if e.name in types_to_gen: + out += PrintEnumToString(e, self) + out += PrintEnum(e, self) + + for f in self.flags: + if f.name in types_to_gen: + for b in self.bitmasks: + if b.name == f.enum: + out += PrintFlags(f, b, self) + out += PrintBitMask(b, f.name, self) + + if f.name in flags_strings_to_gen: + for b in self.bitmasks: + if b.name == f.enum: + out += PrintBitMaskToString(b, f.name, self) + + # find all structures needed to dump the requested structures + structure_names = set() + for s in self.all_structures: + if s.name in types_to_gen: + structure_names.add(s.name) + + for s in self.all_structures: + if s.name in types_to_gen: + out += PrintForwardDeclaration(s, self) + + for s in self.all_structures: + if s.name in types_to_gen: + out += PrintStructure(s, structure_names, self) + + out += "pNextChainInfos get_chain_infos() {\n" + out += " pNextChainInfos infos;\n" + for key, value in EXTENSION_CATEGORIES.items(): + out += PrintChainBuilders(key, self.extension_sets[key]) + out += " return infos;\n}\n" + + for key, value in EXTENSION_CATEGORIES.items(): + out += PrintChainIterator(key, + self.extension_sets[key], value.get('type')) + + gen.write(out, file=self.outFile) + + gen.OutputGenerator.endFile(self) + + def genCmd(self, cmd, name, alias): + gen.OutputGenerator.genCmd(self, cmd, name, alias) + + # These are actually constants + def genEnum(self, enuminfo, name, alias): + gen.OutputGenerator.genEnum(self, enuminfo, name, alias) + + # These are actually enums + def genGroup(self, groupinfo, groupName, alias): + gen.OutputGenerator.genGroup(self, groupinfo, groupName, alias) + + if alias is not None: + return + + if groupinfo.elem.get('type') == 'bitmask': + self.bitmasks.add(VulkanBitmask(groupinfo.elem, self.extensions)) + elif groupinfo.elem.get('type') == 'enum': + self.enums.add(VulkanEnum(groupinfo.elem, self.extensions)) + + def genType(self, typeinfo, name, alias): + gen.OutputGenerator.genType(self, typeinfo, name, alias) + + if alias is not None: + return + + if typeinfo.elem.get('category') == 'bitmask': + self.flags.add(VulkanFlags(typeinfo.elem)) + + if typeinfo.elem.get('category') == 'struct' and name in structures_to_gen: + self.structures.add(VulkanStructure( + name, typeinfo.elem, self.constants, self.extTypes)) + + if typeinfo.elem.get('category') == 'struct': + self.all_structures.add(VulkanStructure( + name, typeinfo.elem, self.constants, self.extTypes)) + + for vendor in vendor_abbreviations: + for node in typeinfo.elem.findall('member'): + if(node.get('values') is not None): + if(node.get('values').find(vendor)) != -1: + return + + for key, value in EXTENSION_CATEGORIES.items(): + if typeinfo.elem.get('structextends') == value.get('extends'): + self.extension_sets[key].add(VulkanStructure( + name, typeinfo.elem, self.constants, self.extTypes)) + + +def GatherTypesToGen(structures): + types_to_gen = set() + for s in structures: + types_to_gen.add(s.name) + for m in s.members: + if m.typeID not in predefined_types and m.name not in ['sType', 'pNext']: + types_to_gen.add(m.typeID) + return types_to_gen + + +def GetExtension(name, generator): + if name in generator.extFuncs: + return generator.extFuncs[name] + elif name in generator.extTypes: + return generator.extTypes[name] + else: + return None + + +def AddGuardHeader(obj): + if obj is not None and obj.guard is not None: + return "#ifdef {}\n".format(obj.guard) + else: + return "" + + +def AddGuardFooter(obj): + if obj is not None and obj.guard is not None: + return "#endif // {}\n".format(obj.guard) + else: + return "" + + +def PrintEnumToString(e, gen): + out = '' + out += AddGuardHeader(GetExtension(e.name, gen)) + + out += "static const char *" + e.name + "String(" + e.name + " value) {\n" + out += " switch (value) {\n" + for v in e.options: + out += " case (" + str(v.value) + \ + "): return \"" + v.name[3:] + "\";\n" + out += " default: return \"UNKNOWN_" + e.name + "\";\n" + out += " }\n}\n" + out += AddGuardFooter(GetExtension(e.name, gen)) + return out + + +def PrintEnum(e, gen): + out = '' + out += AddGuardHeader(GetExtension(e.name, gen)) + out += "void Dump" + e.name + \ + "(Printer &p, std::string name, " + \ + e.name + " value, int width = 0) {\n" + out += " if (p.Type() == OutputType::json) {\n" + out += " p.PrintKeyValue(name, value, width);\n" + out += " return;\n" + out += " } else {\n" + out += " p.PrintKeyValue(name, " + \ + e.name + "String(value), width);\n }\n" + out += "}\n" + out += AddGuardFooter(GetExtension(e.name, gen)) + return out + + +def PrintFlags(f, b, gen): + out = '' + out += AddGuardHeader(GetExtension(f.name, gen)) + + out += "void Dump" + f.name + \ + "(Printer &p, std::string name, " + \ + f.enum + " value, int width = 0) {\n" + out += " if (value == 0) p.PrintElement(\"None\");\n" + for v in b.options: + out += " if (" + str(v.value) + \ + " & value) p.SetAsType().PrintElement(\"" + \ + str(v.name[3:]) + "\");\n" + out += "}\n" + + out += AddGuardFooter(GetExtension(f.name, gen)) + return out + + +def PrintBitMask(b, name, gen): + out = '' + out += AddGuardHeader(GetExtension(b.name, gen)) + out += "void Dump" + name + \ + "(Printer &p, std::string name, " + name + " value, int width = 0) {\n" + out += " if (p.Type() == OutputType::json) { p.PrintKeyValue(name, value); return; }\n" + out += " p.ObjectStart(name);\n" + out += " Dump" + name + \ + "(p, name, static_cast<" + b.name + ">(value), width);\n" + out += " p.ObjectEnd();\n" + out += "}\n" + out += "void Dump" + b.name + \ + "(Printer &p, std::string name, " + \ + b.name + " value, int width = 0) {\n" + out += " if (p.Type() == OutputType::json) { p.PrintKeyValue(name, value); return; }\n" + out += " p.ObjectStart(name);\n" + out += " Dump" + name + "(p, name, value, width);\n" + out += " p.ObjectEnd();\n" + out += "}\n" + out += AddGuardFooter(GetExtension(b.name, gen)) + return out + + +def PrintBitMaskToString(b, name, gen): + out = '' + out += AddGuardHeader(GetExtension(b.name, gen)) + out += "std::string " + name + \ + "String(" + name + " value, int width = 0) {\n" + out += " std::string out;\n" + out += " bool is_first = true;\n" + for v in b.options: + out += " if (" + str(v.value) + " & value) {\n" + out += " if (is_first) { is_first = false; } else { out += \" | \"; }\n" + out += " out += \"" + \ + str(v.name).strip("VK_").strip("_BIT") + "\";\n" + out += " }\n" + out += " return out;\n" + out += "}\n" + out += AddGuardFooter(GetExtension(b.name, gen)) + return out + + +def PrintForwardDeclaration(struct, gen): + out = '' + out += AddGuardHeader(struct) + out += "void Dump" + struct.name + \ + "(Printer &p, std::string name, " + struct.name + " &obj);\n" + out += AddGuardFooter(struct) + + return out + + +def PrintStructure(struct, structure_names, gen): + out = '' + out += AddGuardHeader(struct) + max_key_len = len(struct.members[0].name) + for v in struct.members: + if v.arrayLength is not None: + if len(v.name) + len(v.arrayLength) + 2 > max_key_len: + max_key_len = len(v.name) + len(v.arrayLength) + 2 + elif v.typeID in predefined_types: + if len(v.name) > max_key_len: + max_key_len = len(v.name) + + out += "void Dump" + struct.name + \ + "(Printer &p, std::string name, " + struct.name + " &obj) {\n" + if struct.name == "VkPhysicalDeviceLimits": + out += " if (p.Type() == OutputType::json)\n" + out += " p.ObjectStart(\"limits\");\n" + out += " else\n" + out += " p.SetSubHeader().ObjectStart(name);\n" + elif struct.name == "VkPhysicalDeviceSparseProperties": + out += " if (p.Type() == OutputType::json)\n" + out += " p.ObjectStart(\"sparseProperties\");\n" + out += " else\n" + out += " p.SetSubHeader().ObjectStart(name);\n" + else: + out += " p.ObjectStart(name);\n" + + for v in struct.members: + # arrays + if v.arrayLength is not None: + # strings + if v.typeID == "char": + out += " p.PrintKeyString(\"" + v.name + "\", obj." + \ + v.name + ", " + str(max_key_len) + ");\n" + # uuid's + elif (v.arrayLength == str(16) and v.typeID == "uint8_t"): # VK_UUID_SIZE + out += " p.PrintKeyString(\"" + v.name + "\", to_string_16(obj." + \ + v.name + "), " + str(max_key_len) + ");\n" + elif (v.arrayLength == str(8) and v.typeID == "uint8_t"): # VK_LUID_SIZE + out += " if (obj.deviceLUIDValid)" # special case + out += " p.PrintKeyString(\"" + v.name + "\", to_string_8(obj." + \ + v.name + "), " + str(max_key_len) + ");\n" + elif v.arrayLength.isdigit(): + out += " p.ArrayStart(\"" + v.name + \ + "\", "+v.arrayLength+");\n" + for i in range(0, int(v.arrayLength)): + out += " p.PrintElement(obj." + \ + v.name + "[" + str(i) + "]);\n" + out += " p.ArrayEnd();\n" + else: # dynamic array length based on other member + out += " p.ArrayStart(\"" + v.name + \ + "\", obj."+v.arrayLength+");\n" + out += " for (uint32_t i = 0; i < obj." + \ + v.arrayLength+"; i++) {\n" + if v.typeID in structure_names: + out += " if (obj." + v.name + " != nullptr) {\n" + out += " p.SetElementIndex(i);\n" + out += " Dump" + v.typeID + \ + "(p, \"" + v.name + "\", obj." + v.name + "[i]);\n" + out += " }\n" + else: + out += " p.PrintElement(obj." + v.name + "[i]);\n" + out += " }\n p.ArrayEnd();\n" + elif v.typeID == "VkBool32": + out += " p.PrintKeyBool(\"" + v.name + "\", obj." + \ + v.name + ", " + str(max_key_len) + ");\n" + elif v.typeID == "VkDeviceSize": + out += " p.PrintKeyValue(\"" + v.name + "\", to_hex_str(p, obj." + \ + v.name + "), " + str(max_key_len) + ");\n" + elif v.typeID in predefined_types: + out += " p.PrintKeyValue(\"" + v.name + "\", obj." + \ + v.name + ", " + str(max_key_len) + ");\n" + elif v.name not in ['sType', 'pNext']: + if v.typeID in structure_names: + out += " Dump" + v.typeID + \ + "(p, \"" + v.name + "\", obj." + v.name + ");\n" + else: + out += " Dump" + v.typeID + \ + "(p, \"" + v.name + "\", obj." + \ + v.name + ", " + str(max_key_len) + ");\n" + + out += " p.ObjectEnd();\n" + out += "}\n" + + out += AddGuardFooter(struct) + return out + + +def PrintChainBuilders(listName, structures): + out = '' + out += " infos." + listName + " = {\n" + for s in structures: + out += AddGuardHeader(s) + if s.sTypeName is not None: + out += " {" + s.sTypeName + ", sizeof(" + s.name + ")},\n" + out += AddGuardFooter(s) + out += " };\n" + return out + + +def PrintChainIterator(listName, structures, checkExtLoc): + sorted_structures = sorted(structures, key=operator.attrgetter("name")) + + out = '' + out += "void chain_iterator_" + listName + "(Printer &p, " + if checkExtLoc == "device": + out += "AppGpu &gpu" + elif checkExtLoc == "instance": + out += "AppInstance &inst" + elif checkExtLoc == "both": + out += "AppInstance &inst, AppGpu &gpu" + out += ", void * place) {\n" + + out += " while (place) {\n" + out += " struct VkStructureHeader *structure = (struct VkStructureHeader *)place;\n" + out += " p.SetSubHeader();\n" + for s in sorted_structures: + out += AddGuardHeader(s) + if s.sTypeName is not None: + if s.extNameStr is not None: + out += " if (structure->sType == " + \ + s.sTypeName + " &&\n" + if s.extType == "device": + out += " gpu.CheckPhysicalDeviceExtensionIncluded(" + \ + s.extNameStr + ")) {\n" + elif s.extType == "instance": + out += " inst.CheckExtensionEnabled(" + \ + s.extNameStr + ")) {\n" + + else: + out += " if (structure->sType == " + \ + s.sTypeName + ") {\n" + + out += " " + s.name + "* props = " + \ + "("+s.name+"*)structure;\n" + out += " Dump" + s.name + \ + "(p, \"" + s.name + "\", *props);\n" + out += " }\n" + out += AddGuardFooter(s) + out += " p.AddNewline();\n" + out += " place = structure->pNext;\n" + out += " }\n" + out += "}\n" + return out + + +def isPow2(num): + return num != 0 and ((num & (num - 1)) == 0) + + +def StrToInt(s): + try: + return int(s) + except ValueError: + return int(s, 16) + + +class VulkanEnum: + class Option: + + def __init__(self, name, value, bitpos, comment): + self.name = name + self.comment = comment + self.multiValue = None + + if value is not None: + + self.multiValue = not isPow2(StrToInt(value)) + + if value == 0 or value is None: + value = 1 << int(bitpos) + + self.value = value + + def values(self): + return { + 'optName': self.name, + 'optValue': self.value, + 'optComment': self.comment, + 'optMultiValue': self.multiValue, + } + + def __init__(self, rootNode, extensions): + self.name = rootNode.get('name') + self.type = rootNode.get('type') + self.options = [] + self.ext = None + for child in rootNode: + childName = child.get('name') + childValue = child.get('value') + childBitpos = child.get('bitpos') + childComment = child.get('comment') + childExtends = child.get('extends') + childOffset = child.get('offset') + childExtNum = child.get('extnumber') + + if childName is None: + continue + if (childValue is None and childBitpos is None and childOffset is None): + continue + + if childExtends is not None and childExtNum is not None and childOffset is not None: + enumNegative = False + extNum = int(childExtNum) + extOffset = int(childOffset) + extBase = 1000000000 + extBlockSize = 1000 + childValue = extBase + (extNum - 1) * extBlockSize + extOffset + if ('dir' in child.keys()): + childValue = -childValue + duplicate = False + for o in self.options: + if o.values()['optName'] == childName: + duplicate = True + if duplicate: + continue + + self.options.append(VulkanEnum.Option( + childName, childValue, childBitpos, childComment)) + + for ext in extensions: + if self.name in ext.enumValues: + self.ext = ext + childName, childValue = ext.enumValues[self.name] + self.options.append(VulkanEnum.Option( + childName, childValue, None, None)) + + +class VulkanBitmask: + + def __init__(self, rootNode, extensions): + self.name = rootNode.get('name') + self.type = rootNode.get('type') + self.ext = None + + # Read each value that the enum contains + self.options = [] + for child in rootNode: + childName = child.get('name') + childValue = child.get('value') + childBitpos = child.get('bitpos') + childComment = child.get('comment') + if childName is None or (childValue is None and childBitpos is None): + continue + + self.options.append(VulkanEnum.Option( + childName, childValue, childBitpos, childComment)) + + for ext in extensions: + if self.name in ext.enumValues: + self.ext = ext + childName, childValue = ext.enumValues[self.name] + self.options.append(VulkanEnum.Option( + childName, childValue, None, None)) + + +class VulkanFlags: + + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.type = rootNode.get('type') + self.enum = rootNode.get('requires') + + +class VulkanVariable: + def __init__(self, rootNode, constants, parentName): + self.name = rootNode.find('name').text + # Typename, dereferenced and converted to a useable C++ token + self.typeID = rootNode.find('type').text + self.baseType = self.typeID + self.childType = None + self.arrayLength = None + + self.text = '' + for node in rootNode.itertext(): + comment = rootNode.find('comment') + if comment is not None and comment.text == node: + continue + self.text += node + + typeMatch = re.search('.+?(?=' + self.name + ')', self.text) + self.type = typeMatch.string[typeMatch.start():typeMatch.end()] + self.type = ' '.join(self.type.split()) + bracketMatch = re.search('(?<=\\[)[a-zA-Z0-9_]+(?=\\])', self.text) + if bracketMatch is not None: + matchText = bracketMatch.string[bracketMatch.start( + ):bracketMatch.end()] + self.childType = self.type + self.type += '[' + matchText + ']' + if matchText in constants: + self.arrayLength = constants[matchText] + else: + self.arrayLength = matchText + + self.lengthMember = False + lengthString = rootNode.get('len') + lengths = [] + if lengthString is not None: + lengths = re.split(',', lengthString) + lengths = list(filter(('null-terminated').__ne__, lengths)) + assert(len(lengths) <= 1) + if self.arrayLength is None and len(lengths) > 0: + self.childType = '*'.join(self.type.split('*')[0:-1]) + self.arrayLength = lengths[0] + self.lengthMember = True + if self.arrayLength is not None and self.arrayLength.startswith('latexmath'): + code = self.arrayLength[10:len(self.arrayLength)] + code = re.sub('\\[', '', code) + code = re.sub('\\]', '', code) + code = re.sub('\\\\(lceil|rceil)', '', code) + code = re.sub('{|}', '', code) + code = re.sub('\\\\mathit', '', code) + code = re.sub('\\\\over', '/', code) + code = re.sub('\\\\textrm', '', code) + self.arrayLength = code + + # Dereference if necessary and handle members of variables + if self.arrayLength is not None: + self.arrayLength = re.sub('::', '->', self.arrayLength) + sections = self.arrayLength.split('->') + if sections[-1][0] == 'p' and sections[0][1].isupper(): + self.arrayLength = '*' + self.arrayLength + + +class VulkanStructure: + def __init__(self, name, rootNode, constants, extTypes): + self.name = name + self.members = [] + self.guard = None + self.sTypeName = None + self.extNameStr = None + self.extType = None + for node in rootNode.findall('member'): + if(node.get('values') is not None): + self.sTypeName = node.get('values') + self.members.append(VulkanVariable( + node, constants, self.name)) + + for k, e in extTypes.items(): + if k == self.name: + if e.guard is not None: + self.guard = e.guard + if e.extNameStr is not None: + self.extNameStr = e.extNameStr + if e.type is not None: + self.extType = e.type + + +class VulkanExtension: + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.number = int(rootNode.get('number')) + self.type = rootNode.get('type') + self.dependency = rootNode.get('requires') + self.guard = GetFeatureProtect(rootNode) + self.supported = rootNode.get('supported') + self.extNameStr = None + self.vktypes = [] + self.vkfuncs = [] + self.constants = {} + self.enumValues = {} + + for req in rootNode.findall('require'): + for ty in req.findall('type'): + self.vktypes.append(ty.get('name')) + + for func in req.findall('command'): + self.vkfuncs.append(func.get('name')) + + for enum in req.findall('enum'): + base = enum.get('extends') + name = enum.get('name') + value = enum.get('value') + bitpos = enum.get('bitpos') + offset = enum.get('offset') + # gets the VK_XXX_EXTENSION_NAME string + if value == "\"" + self.name + "\"": + self.extNameStr = name + + if value is None and bitpos is not None: + value = 1 << int(bitpos) + + if offset is not None: + offset = int(offset) + if base is not None and offset is not None: + enumValue = 1000000000 + 1000*(self.number - 1) + offset + if enum.get('dir') == '-': + enumValue = -enumValue + self.enumValues[base] = (name, enumValue) + else: + self.constants[name] = value |
