aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorCharles Giessen <charles@lunarg.com>2019-08-13 11:16:59 -0600
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>2019-10-04 09:14:44 -0600
commit623d1cc06173a7e209affe6030311abc464beb74 (patch)
tree68c33ef0491ab8d5515e5a9a3019bb1680f53124 /scripts
parent7513420a385869903b907d2d42e3ee93f93fa551 (diff)
downloadusermoji-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')
-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