aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/kvt_genvk.py213
-rw-r--r--scripts/vulkaninfo_generator.py855
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