diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/kvt_genvk.py | 213 | ||||
| -rw-r--r-- | scripts/vulkaninfo_generator.py | 855 |
2 files changed, 985 insertions, 83 deletions
diff --git a/scripts/kvt_genvk.py b/scripts/kvt_genvk.py index 1d2f2550..ce021a7f 100644 --- a/scripts/kvt_genvk.py +++ b/scripts/kvt_genvk.py @@ -14,16 +14,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -import argparse, cProfile, pdb, string, sys, time, os +import argparse +import cProfile +import pdb +import string +import sys +import time +import os # Simple timer functions startTime = None + def startTimer(timeit): global startTime if timeit: startTime = time.process_time() + def endTimer(timeit, msg): global startTime if timeit: @@ -32,7 +40,9 @@ def endTimer(timeit, msg): startTime = None # Turn a list of strings into a regexp string matching exactly those strings -def makeREstring(list, default = None): + + +def makeREstring(list, default=None): if len(list) > 0 or default is None: return '^(' + '|'.join(list) + ')$' else: @@ -43,6 +53,8 @@ def makeREstring(list, default = None): # parameters: # # args is an parsed argument object; see below for the fields that are used. + + def makeGenOpts(args): global genOpts genOpts = {} @@ -70,14 +82,14 @@ def makeGenOpts(args): # Descriptive names for various regexp patterns used to select # versions and extensions - allFeatures = allExtensions = '.*' - noFeatures = noExtensions = None + allFeatures = allExtensions = '.*' + noFeatures = noExtensions = None # Turn lists of names/patterns into matching regular expressions - addExtensionsPat = makeREstring(extensions, None) - removeExtensionsPat = makeREstring(removeExtensions, None) - emitExtensionsPat = makeREstring(emitExtensions, allExtensions) - featuresPat = makeREstring(features, allFeatures) + addExtensionsPat = makeREstring(extensions, None) + removeExtensionsPat = makeREstring(removeExtensions, None) + emitExtensionsPat = makeREstring(emitExtensions, allExtensions) + featuresPat = makeREstring(features, allFeatures) # Copyright text prefixing all headers (list of strings). prefixStrings = [ @@ -116,78 +128,103 @@ def makeGenOpts(args): # Helper file generator options for typemap_helper.h genOpts['vk_typemap_helper.h'] = [ - HelperFileOutputGenerator, - HelperFileOutputGeneratorOptions( - conventions = conventions, - filename = 'vk_typemap_helper.h', - directory = directory, - apiname = 'vulkan', - profile = None, - versions = featuresPat, - emitversions = featuresPat, - defaultExtensions = 'vulkan', - addExtensions = addExtensionsPat, - removeExtensions = removeExtensionsPat, - emitExtensions = emitExtensionsPat, - prefixText = prefixStrings + vkPrefixStrings, - protectFeature = False, - apicall = 'VKAPI_ATTR ', - apientry = 'VKAPI_CALL ', - apientryp = 'VKAPI_PTR *', - alignFuncParam = 48, - expandEnumerants = False, - helper_file_type = 'typemap_helper_header') - ] + HelperFileOutputGenerator, + HelperFileOutputGeneratorOptions( + conventions=conventions, + filename='vk_typemap_helper.h', + directory=directory, + apiname='vulkan', + profile=None, + versions=featuresPat, + emitversions=featuresPat, + defaultExtensions='vulkan', + addExtensions=addExtensionsPat, + removeExtensions=removeExtensionsPat, + emitExtensions=emitExtensionsPat, + prefixText=prefixStrings + vkPrefixStrings, + protectFeature=False, + apicall='VKAPI_ATTR ', + apientry='VKAPI_CALL ', + apientryp='VKAPI_PTR *', + alignFuncParam=48, + expandEnumerants=False, + helper_file_type='typemap_helper_header') + ] # Options for mock ICD header genOpts['mock_icd.h'] = [ - MockICDOutputGenerator, - MockICDGeneratorOptions( - conventions = conventions, - filename = 'mock_icd.h', - directory = directory, - apiname = 'vulkan', - profile = None, - versions = featuresPat, - emitversions = featuresPat, - defaultExtensions = 'vulkan', - addExtensions = addExtensionsPat, - removeExtensions = removeExtensionsPat, - emitExtensions = emitExtensionsPat, - prefixText = prefixStrings + vkPrefixStrings, - protectFeature = False, - apicall = 'VKAPI_ATTR ', - apientry = 'VKAPI_CALL ', - apientryp = 'VKAPI_PTR *', - alignFuncParam = 48, - expandEnumerants = False, - helper_file_type = 'mock_icd_header') - ] + MockICDOutputGenerator, + MockICDGeneratorOptions( + conventions=conventions, + filename='mock_icd.h', + directory=directory, + apiname='vulkan', + profile=None, + versions=featuresPat, + emitversions=featuresPat, + defaultExtensions='vulkan', + addExtensions=addExtensionsPat, + removeExtensions=removeExtensionsPat, + emitExtensions=emitExtensionsPat, + prefixText=prefixStrings + vkPrefixStrings, + protectFeature=False, + apicall='VKAPI_ATTR ', + apientry='VKAPI_CALL ', + apientryp='VKAPI_PTR *', + alignFuncParam=48, + expandEnumerants=False, + helper_file_type='mock_icd_header') + ] # Options for mock ICD cpp genOpts['mock_icd.cpp'] = [ - MockICDOutputGenerator, - MockICDGeneratorOptions( - conventions = conventions, - filename = 'mock_icd.cpp', - directory = directory, - apiname = 'vulkan', - profile = None, - versions = featuresPat, - emitversions = featuresPat, - defaultExtensions = 'vulkan', - addExtensions = addExtensionsPat, - removeExtensions = removeExtensionsPat, - emitExtensions = emitExtensionsPat, - prefixText = prefixStrings + vkPrefixStrings, - protectFeature = False, - apicall = 'VKAPI_ATTR ', - apientry = 'VKAPI_CALL ', - apientryp = 'VKAPI_PTR *', - alignFuncParam = 48, - expandEnumerants = False, - helper_file_type = 'mock_icd_source') - ] + MockICDOutputGenerator, + MockICDGeneratorOptions( + conventions=conventions, + filename='mock_icd.cpp', + directory=directory, + apiname='vulkan', + profile=None, + versions=featuresPat, + emitversions=featuresPat, + defaultExtensions='vulkan', + addExtensions=addExtensionsPat, + removeExtensions=removeExtensionsPat, + emitExtensions=emitExtensionsPat, + prefixText=prefixStrings + vkPrefixStrings, + protectFeature=False, + apicall='VKAPI_ATTR ', + apientry='VKAPI_CALL ', + apientryp='VKAPI_PTR *', + alignFuncParam=48, + expandEnumerants=False, + helper_file_type='mock_icd_source') + ] + + # Options for vulkaninfo.hpp + genOpts['vulkaninfo.hpp'] = [ + VulkanInfoGenerator, + VulkanInfoGeneratorOptions( + conventions=conventions, + filename='vulkaninfo.hpp', + directory=directory, + apiname='vulkan', + profile=None, + versions=featuresPat, + emitversions=featuresPat, + defaultExtensions='vulkan', + addExtensions=addExtensionsPat, + removeExtensions=removeExtensionsPat, + emitExtensions=emitExtensionsPat, + prefixText=prefixStrings + vkPrefixStrings, + protectFeature=False, + apicall='VKAPI_ATTR ', + apientry='VKAPI_CALL ', + apientryp='VKAPI_PTR *', + alignFuncParam=48, + expandEnumerants=False) + ] + # Generate a target based on the options in the matching genOpts{} object. # This is encapsulated in a function so it can be profiled and/or timed. @@ -210,12 +247,18 @@ def genTarget(args): if not args.quiet: write('* Building', options.filename, file=sys.stderr) - write('* options.versions =', options.versions, file=sys.stderr) - write('* options.emitversions =', options.emitversions, file=sys.stderr) - write('* options.defaultExtensions =', options.defaultExtensions, file=sys.stderr) - write('* options.addExtensions =', options.addExtensions, file=sys.stderr) - write('* options.removeExtensions =', options.removeExtensions, file=sys.stderr) - write('* options.emitExtensions =', options.emitExtensions, file=sys.stderr) + write('* options.versions =', + options.versions, file=sys.stderr) + write('* options.emitversions =', + options.emitversions, file=sys.stderr) + write('* options.defaultExtensions =', + options.defaultExtensions, file=sys.stderr) + write('* options.addExtensions =', + options.addExtensions, file=sys.stderr) + write('* options.removeExtensions =', + options.removeExtensions, file=sys.stderr) + write('* options.emitExtensions =', + options.emitExtensions, file=sys.stderr) startTimer(args.time) gen = createGenerator(errFile=errWarn, @@ -231,6 +274,7 @@ def genTarget(args): write('No generator options for unknown target:', args.target, file=sys.stderr) + # -feature name # -extension name # For both, "name" may be a single name, or a space-separated list @@ -305,8 +349,10 @@ if __name__ == '__main__': # Generator Modifications from mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator from vulkan_tools_helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions + from vulkaninfo_generator import VulkanInfoGenerator, VulkanInfoGeneratorOptions # Temporary workaround for vkconventions python2 compatibility - import abc; abc.ABC = abc.ABCMeta('ABC', (object,), {}) + import abc + abc.ABC = abc.ABCMeta('ABC', (object,), {}) from vkconventions import VulkanConventions # This splits arguments which are space-separated lists @@ -332,7 +378,7 @@ if __name__ == '__main__': if (args.dump): write('* Dumping registry to regdump.txt', file=sys.stderr) - reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8')) + reg.dumpReg(filehandle=open('regdump.txt', 'w', encoding='utf-8')) # create error/warning & diagnostic files if (args.errfile): @@ -348,7 +394,8 @@ if __name__ == '__main__': if (args.debug): pdb.run('genTarget(args)') elif (args.profile): - import cProfile, pstats + import cProfile + import pstats cProfile.run('genTarget(args)', 'profile.txt') p = pstats.Stats('profile.txt') p.strip_dirs().sort_stats('time').print_stats(50) 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 |
