early-access version 1866

This commit is contained in:
pineappleEA
2021-07-09 23:54:15 +02:00
parent 335eeff822
commit 7d21887d40
469 changed files with 201995 additions and 78488 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python3 -i
#
# Copyright (c) 2013-2020 The Khronos Group Inc.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
@@ -32,6 +32,8 @@ class CGeneratorOptions(GeneratorOptions):
genEnumBeginEndRange=False,
genAliasMacro=False,
aliasMacro='',
misracstyle=False,
misracppstyle=False,
**kwargs
):
"""Constructor.
@@ -68,7 +70,10 @@ class CGeneratorOptions(GeneratorOptions):
be generated for enumerated types
- genAliasMacro - True if the OpenXR alias macro should be generated
for aliased types (unclear what other circumstances this is useful)
- aliasMacro - alias macro to inject when genAliasMacro is True"""
- aliasMacro - alias macro to inject when genAliasMacro is True
- misracstyle - generate MISRA C-friendly headers
- misracppstyle - generate MISRA C++-friendly headers"""
GeneratorOptions.__init__(self, **kwargs)
self.prefixText = prefixText
@@ -116,6 +121,12 @@ class CGeneratorOptions(GeneratorOptions):
self.aliasMacro = aliasMacro
"""alias macro to inject when genAliasMacro is True"""
self.misracstyle = misracstyle
"""generate MISRA C-friendly headers"""
self.misracppstyle = misracppstyle
"""generate MISRA C++-friendly headers"""
self.codeGenerator = True
"""True if this generator makes compilable code"""
@@ -380,13 +391,11 @@ class COutputGenerator(OutputGenerator):
self.appendSection(section, "\n" + body)
def genEnum(self, enuminfo, name, alias):
"""Generate enumerants.
"""Generate the C declaration for a constant (a single <enum> value)."""
<enum> tags may specify their values in several ways, but are usually
just integers."""
OutputGenerator.genEnum(self, enuminfo, name, alias)
(_, strVal) = self.enumToValue(enuminfo.elem, False)
body = '#define ' + name.ljust(33) + ' ' + strVal
body = self.buildConstantCDecl(enuminfo, name, alias)
self.appendSection('enum', body)
def genCmd(self, cmdinfo, name, alias):
@@ -403,3 +412,9 @@ class COutputGenerator(OutputGenerator):
self.appendSection('command', prefix + decls[0] + '\n')
if self.genOpts.genFuncPointers:
self.appendSection('commandPointer', decls[1])
def misracstyle(self):
return self.genOpts.misracstyle;
def misracppstyle(self):
return self.genOpts.misracppstyle;

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python3 -i
#
# Copyright (c) 2013-2020 The Khronos Group Inc.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python3 -i
#
# Copyright (c) 2013-2020 The Khronos Group Inc.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
"""Base class for source/header/doc generators, as well as some utility functions."""
@@ -118,6 +118,7 @@ class GeneratorOptions:
addExtensions=None,
removeExtensions=None,
emitExtensions=None,
emitSpirv=None,
reparentEnums=True,
sortProcedure=regSortFeatures):
"""Constructor.
@@ -148,6 +149,9 @@ class GeneratorOptions:
- emitExtensions - regex matching names of extensions to actually emit
interfaces for (though all requested versions are considered when
deciding which interfaces to generate).
to None.
- emitSpirv - regex matching names of extensions and capabilities
to actually emit interfaces for.
- reparentEnums - move <enum> elements which extend an enumerated
type from <feature> or <extension> elements to the target <enums>
element. This is required for almost all purposes, but the
@@ -209,6 +213,10 @@ class GeneratorOptions:
interfaces for (though all requested versions are considered when
deciding which interfaces to generate)."""
self.emitSpirv = self.emptyRegex(emitSpirv)
"""regex matching names of extensions and capabilities
to actually emit interfaces for."""
self.reparentEnums = reparentEnums
"""boolean specifying whether to remove <enum> elements from
<feature> or <extension> when extending an <enums> type."""
@@ -298,7 +306,7 @@ class OutputGenerator:
raise UserWarning(
'*** FATAL ERROR in Generator.logMsg: unknown level:' + level)
def enumToValue(self, elem, needsNum):
def enumToValue(self, elem, needsNum, bitwidth = 32, forceSuffix = False):
"""Parse and convert an `<enum>` tag into a value.
Returns a list:
@@ -334,6 +342,11 @@ class OutputGenerator:
# t = enuminfo.elem.get('type')
# if t is not None and t != '' and t != 'i' and t != 's':
# value += enuminfo.type
if forceSuffix:
if bitwidth == 64:
value = value + 'ULL'
else:
value = value + 'U'
self.logMsg('diag', 'Enum', name, '-> value [', numVal, ',', value, ']')
return [numVal, value]
if 'bitpos' in elem.keys():
@@ -341,8 +354,10 @@ class OutputGenerator:
bitpos = int(value, 0)
numVal = 1 << bitpos
value = '0x%08x' % numVal
if bitpos >= 32:
value = value + 'ULL'
if bitwidth == 64:
value = value + 'ULL'
elif forceSuffix:
value = value + 'U'
self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
return [numVal, value]
if 'offset' in elem.keys():
@@ -370,7 +385,7 @@ class OutputGenerator:
return [None, None]
def checkDuplicateEnums(self, enums):
"""Sanity check enumerated values.
"""Check enumerated values for duplicates.
- enums - list of `<enum>` Elements
@@ -425,6 +440,12 @@ class OutputGenerator:
# Return the list
return stripped
def misracstyle(self):
return False;
def misracppstyle(self):
return False;
def buildEnumCDecl(self, expand, groupinfo, groupName):
"""Generate the C declaration for an enum"""
groupElem = groupinfo.elem
@@ -432,11 +453,11 @@ class OutputGenerator:
# Determine the required bit width for the enum group.
# 32 is the default, which generates C enum types for the values.
bitwidth = 32
# If the constFlagBits preference is set, 64 is the default for bitmasks
if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
bitwidth = 64
# Check for an explicitly defined bitwidth, which will override any defaults.
if groupElem.get('bitwidth'):
try:
@@ -444,56 +465,107 @@ class OutputGenerator:
except ValueError as ve:
self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for ', groupName, ' - must be an integer value\n')
exit(1)
# Bitmask types support 64-bit flags, so have different handling
usebitmask = False
usedefine = False
# Bitmask flags can be generated as either "static const uint{32,64}_t" values,
# or as 32-bit C enums. 64-bit types must use uint64_t values.
if groupElem.get('type') == 'bitmask':
if bitwidth > 32 or self.misracppstyle():
usebitmask = True
if self.misracstyle():
usedefine = True
if usedefine or usebitmask:
# Validate the bitwidth and generate values appropriately
# Bitmask flags up to 64-bit are generated as static const uint64_t values
# Bitmask flags up to 32-bit are generated as C enum values
if bitwidth > 64:
self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for bitmask type ', groupName, ' - must be less than or equal to 64\n')
exit(1)
elif bitwidth > 32:
return self.buildEnumCDecl_Bitmask(groupinfo, groupName)
else:
return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
return self.buildEnumCDecl_BitmaskOrDefine(groupinfo, groupName, bitwidth, usedefine)
else:
# Validate the bitwidth and generate values appropriately
# Enum group types up to 32-bit are generated as C enum values
if bitwidth > 32:
self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for enum type ', groupName, ' - must be less than or equal to 32\n')
exit(1)
else:
return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
def buildEnumCDecl_Bitmask(self, groupinfo, groupName):
def buildEnumCDecl_BitmaskOrDefine(self, groupinfo, groupName, bitwidth, usedefine):
"""Generate the C declaration for an "enum" that is actually a
set of flag bits"""
groupElem = groupinfo.elem
flagTypeName = groupinfo.flagType.elem.get('name')
flagTypeName = groupElem.get('name')
# Prefix
body = "// Flag bits for " + flagTypeName + "\n"
if bitwidth == 64:
body += "typedef VkFlags64 %s;\n" % flagTypeName;
else:
body += "typedef VkFlags %s;\n" % flagTypeName;
# Maximum allowable value for a flag (unsigned 64-bit integer)
maxValidValue = 2**(64) - 1
minValidValue = 0
# Get a list of nested 'enum' tags.
enums = groupElem.findall('enum')
# Check for and report duplicates, and return a list with them
# removed.
enums = self.checkDuplicateEnums(enums)
# Accumulate non-numeric enumerant values separately and append
# them following the numeric values, to allow for aliases.
# NOTE: this doesn't do a topological sort yet, so aliases of
# aliases can still get in the wrong order.
aliasText = ''
# Loop over the nested 'enum' tags.
for elem in groupElem.findall('enum'):
for elem in enums:
# Convert the value to an integer and use that to track min/max.
# Values of form -(number) are accepted but nothing more complex.
# Should catch exceptions here for more complex constructs. Not yet.
(numVal, strVal) = self.enumToValue(elem, True)
(numVal, strVal) = self.enumToValue(elem, True, bitwidth, True)
name = elem.get('name')
# Range check for the enum value
if numVal is not None and (numVal > maxValidValue or numVal < minValidValue):
self.logMsg('error', 'Allowable range for flag types in C is [', minValidValue, ',', maxValidValue, '], but', name, 'flag has a value outside of this (', strVal, ')\n')
exit(1)
body += "static const {} {} = {};\n".format(flagTypeName, name, strVal)
decl = self.genRequirements(name, mustBeFound = False)
if self.isEnumRequired(elem):
protect = elem.get('protect')
if protect is not None:
body += '#ifdef {}\n'.format(protect)
if usedefine:
decl += "#define {} {}\n".format(name, strVal)
elif self.misracppstyle():
decl += "static constexpr {} {} {{{}}};\n".format(flagTypeName, name, strVal)
else:
# Some C compilers only allow initializing a 'static const' variable with a literal value.
# So initializing an alias from another 'static const' value would fail to compile.
# Work around this by chasing the aliases to get the actual value.
while numVal is None:
alias = self.registry.tree.find("enums/enum[@name='" + strVal + "']")
(numVal, strVal) = self.enumToValue(alias, True)
decl += "static const {} {} = {};\n".format(flagTypeName, name, strVal)
if numVal is not None:
body += decl
else:
aliasText += decl
if protect is not None:
body += '#endif\n'
# Now append the non-numeric enumerant values
body += aliasText
# Postfix
@@ -505,7 +577,7 @@ class OutputGenerator:
# Break the group name into prefix and suffix portions for range
# enum generation
expandName = re.sub(r'([0-9a-z_])([A-Z0-9])', r'\1_\2', groupName).upper()
expandName = re.sub(r'([0-9]+|[a-z_])([A-Z0-9])', r'\1_\2', groupName).upper()
expandPrefix = expandName
expandSuffix = ''
expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName)
@@ -519,11 +591,11 @@ class OutputGenerator:
# @@ Should use the type="bitmask" attribute instead
isEnum = ('FLAG_BITS' not in expandPrefix)
# Allowable range for a C enum - which is that of a signed 32-bit integer
maxValidValue = 2**(32 - 1) - 1
minValidValue = (maxValidValue * -1) - 1
# Get a list of nested 'enum' tags.
enums = groupElem.findall('enum')
@@ -553,7 +625,22 @@ class OutputGenerator:
# Extension enumerants are only included if they are required
if self.isEnumRequired(elem):
decl = " {} = {},".format(name, strVal)
decl = ''
protect = elem.get('protect')
if protect is not None:
decl += '#ifdef {}\n'.format(protect)
# Indent requirements comment, if there is one
requirements = self.genRequirements(name, mustBeFound = False)
if requirements != '':
requirements = ' ' + requirements
decl += requirements
decl += ' {} = {},'.format(name, strVal)
if protect is not None:
decl += '\n#endif'
if numVal is not None:
body.append(decl)
else:
@@ -563,7 +650,6 @@ class OutputGenerator:
if numVal is not None and (numVal > maxValidValue or numVal < minValidValue):
self.logMsg('error', 'Allowable range for C enum types is [', minValidValue, ',', maxValidValue, '], but', name, 'has a value outside of this (', strVal, ')\n')
exit(1)
# Don't track min/max for non-numbers (numVal is None)
if isEnum and numVal is not None and elem.get('extends') is None:
@@ -605,6 +691,47 @@ class OutputGenerator:
return (section, '\n'.join(body))
def buildConstantCDecl(self, enuminfo, name, alias):
"""Generate the C declaration for a constant (a single <enum>
value).
<enum> tags may specify their values in several ways, but are
usually just integers or floating-point numbers."""
(_, strVal) = self.enumToValue(enuminfo.elem, False)
if self.misracppstyle() and enuminfo.elem.get('type') and not alias:
# Generate e.g.: static constexpr uint32_t x = ~static_cast<uint32_t>(1U);
# This appeases MISRA "underlying type" rules.
typeStr = enuminfo.elem.get('type');
invert = '~' in strVal
number = strVal.strip("()~UL")
if typeStr != "float":
number += 'U'
strVal = "~" if invert else ""
strVal += "static_cast<" + typeStr + ">(" + number + ")"
body = 'static constexpr ' + typeStr.ljust(9) + name.ljust(33) + ' {' + strVal + '};'
elif enuminfo.elem.get('type') and not alias:
# Generate e.g.: #define x (~0ULL)
typeStr = enuminfo.elem.get('type');
invert = '~' in strVal
paren = '(' in strVal
number = strVal.strip("()~UL")
if typeStr != "float":
if typeStr == "uint64_t":
number += 'ULL'
else:
number += 'U'
strVal = "~" if invert else ""
strVal += number
if paren:
strVal = "(" + strVal + ")";
body = '#define ' + name.ljust(33) + ' ' + strVal;
else:
body = '#define ' + name.ljust(33) + ' ' + strVal
return body
def makeDir(self, path):
"""Create a directory, if not already done.
@@ -683,6 +810,20 @@ class OutputGenerator:
self.featureName = None
self.featureExtraProtect = None
def genRequirements(self, name, mustBeFound = True):
"""Generate text showing what core versions and extensions introduce
an API. This exists in the base Generator class because it's used by
the shared enumerant-generating interfaces (buildEnumCDecl, etc.).
Here it returns an empty string for most generators, but can be
overridden by e.g. DocGenerator.
- name - name of the API
- mustBeFound - If True, when requirements for 'name' cannot be
determined, a warning comment is generated.
"""
return ''
def validateFeature(self, featureType, featureName):
"""Validate we're generating something only inside a `<feature>` tag"""
if self.featureName is None:
@@ -738,6 +879,14 @@ class OutputGenerator:
Extend to generate as desired in your derived class."""
self.validateFeature('command', cmdinfo)
def genSpirv(self, spirv, spirvinfo, alias):
"""Generate interface for a spirv element.
- spirvinfo - SpirvInfo for a command
Extend to generate as desired in your derived class."""
return
def makeProtoName(self, name, tail):
"""Turn a `<proto>` `<name>` into C-language prototype
and typedef declarations for that name.
@@ -759,7 +908,9 @@ class OutputGenerator:
- aligncol - if non-zero, attempt to align the nested `<name>` element
at this column"""
indent = ' '
paramdecl = indent + noneStr(param.text)
paramdecl = indent
prefix = noneStr(param.text)
for elem in param:
text = noneStr(elem.text)
tail = noneStr(elem.tail)
@@ -778,7 +929,16 @@ class OutputGenerator:
paramdecl = paramdecl.ljust(aligncol - 1) + ' '
newLen = len(paramdecl)
self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
paramdecl += text + tail
if (self.misracppstyle() and prefix.find('const ') != -1):
# Change pointer type order from e.g. "const void *" to "void const *".
# If the string starts with 'const', reorder it to be after the first type.
paramdecl += prefix.replace('const ', '') + text + ' const' + tail
else:
paramdecl += prefix + text + tail
# Clear prefix for subsequent iterations
prefix = ''
if aligncol == 0:
# Squeeze out multiple spaces other than the indentation
paramdecl = indent + ' '.join(paramdecl.split())
@@ -985,8 +1145,28 @@ class OutputGenerator:
# Non-indented parameters
paramdecl = '('
if n > 0:
paramnames = (''.join(t for t in p.itertext())
for p in params)
paramnames = []
if self.misracppstyle():
for p in params:
param = ''
firstIter = True;
for t in p.itertext():
if (firstIter):
prefix = t
firstIter = False
else:
# Change pointer type order from e.g. "const void *" to "void const *".
# If the string starts with 'const', reorder it to be after the first type.
if (prefix.find('const ') != -1):
param += prefix.replace('const ', '') + t + ' const '
else:
param += prefix + t
# Clear prefix for subsequent iterations
prefix = ''
paramnames.append(param);
else:
paramnames = (''.join(t for t in p.itertext())
for p in params)
paramdecl += ', '.join(paramnames)
else:
paramdecl += 'void'

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python3
#
# Copyright (c) 2013-2020 The Khronos Group Inc.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
@@ -17,6 +17,7 @@ from extensionmetadocgenerator import (ExtensionMetaDocGeneratorOptions,
ExtensionMetaDocOutputGenerator)
from interfacedocgenerator import InterfaceDocGenerator
from generator import write
from spirvcapgenerator import SpirvCapabilityOutputGenerator
from hostsyncgenerator import HostSynchronizationOutputGenerator
from pygenerator import PyOutputGenerator
from reflib import logDiag, logWarn, setLogFile
@@ -73,6 +74,9 @@ def makeGenOpts(args):
# Extensions to emit (list of extensions)
emitExtensions = args.emitExtensions
# SPIR-V capabilities / features to emit (list of extensions & capabilities)
emitSpirv = args.emitSpirv
# Features to include (list of features)
features = args.feature
@@ -85,21 +89,28 @@ def makeGenOpts(args):
# Path to generated files, particularly api.py
genpath = args.genpath
# Generate MISRA C-friendly headers
misracstyle = args.misracstyle;
# Generate MISRA C++-friendly headers
misracppstyle = args.misracppstyle;
# Descriptive names for various regexp patterns used to select
# versions and extensions
allFeatures = allExtensions = r'.*'
allSpirv = allFeatures = allExtensions = r'.*'
# Turn lists of names/patterns into matching regular expressions
addExtensionsPat = makeREstring(extensions, None)
removeExtensionsPat = makeREstring(removeExtensions, None)
emitExtensionsPat = makeREstring(emitExtensions, allExtensions)
emitSpirvPat = makeREstring(emitSpirv, allSpirv)
featuresPat = makeREstring(features, allFeatures)
# Copyright text prefixing all headers (list of strings).
# The SPDX formatting below works around constraints of the 'reuse' tool
prefixStrings = [
'/*',
'** Copyright (c) 2015-2020 The Khronos Group Inc.',
'** Copyright 2015-2021 The Khronos Group Inc.',
'**',
'** SPDX' + '-License-Identifier: Apache-2.0',
'*/',
@@ -249,6 +260,25 @@ def makeGenOpts(args):
reparentEnums = False)
]
genOpts['spirvcapinc'] = [
SpirvCapabilityOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = 'vulkan',
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
emitSpirv = emitSpirvPat,
reparentEnums = False)
]
# Platform extensions, in their own header files
# Each element of the platforms[] array defines information for
# generating a single platform:
@@ -269,14 +299,25 @@ def makeGenOpts(args):
# Extensions required and suppressed for beta "platform". This can
# probably eventually be derived from the requires= attributes of
# the extension blocks.
betaRequireExtensions = [ 'VK_KHR_ray_tracing', 'VK_KHR_deferred_host_operations', 'VK_KHR_pipeline_library' ]
betaSuppressExtensions = [ 'VK_NV_ray_tracing' ]
betaRequireExtensions = [
'VK_KHR_portability_subset',
'VK_KHR_video_queue',
'VK_KHR_video_decode_queue',
'VK_KHR_video_encode_queue',
'VK_EXT_video_decode_h264',
'VK_EXT_video_decode_h265',
'VK_EXT_video_encode_h264',
]
betaSuppressExtensions = []
platforms = [
[ 'vulkan_android.h', [ 'VK_KHR_android_surface',
'VK_ANDROID_external_memory_android_hardware_buffer'
], commonSuppressExtensions ],
[ 'vulkan_fuchsia.h', [ 'VK_FUCHSIA_imagepipe_surface'], commonSuppressExtensions ],
[ 'vulkan_fuchsia.h', [ 'VK_FUCHSIA_imagepipe_surface',
'VK_FUCHSIA_external_memory',
'VK_FUCHSIA_external_semaphore' ], commonSuppressExtensions ],
[ 'vulkan_ggp.h', [ 'VK_GGP_stream_descriptor_surface',
'VK_GGP_frame_token' ], commonSuppressExtensions ],
[ 'vulkan_ios.h', [ 'VK_MVK_ios_surface' ], commonSuppressExtensions ],
@@ -294,8 +335,10 @@ def makeGenOpts(args):
] ],
[ 'vulkan_xcb.h', [ 'VK_KHR_xcb_surface' ], commonSuppressExtensions ],
[ 'vulkan_xlib.h', [ 'VK_KHR_xlib_surface' ], commonSuppressExtensions ],
[ 'vulkan_directfb.h', [ 'VK_EXT_directfb_surface' ], commonSuppressExtensions ],
[ 'vulkan_xlib_xrandr.h', [ 'VK_EXT_acquire_xlib_display' ], commonSuppressExtensions ],
[ 'vulkan_metal.h', [ 'VK_EXT_metal_surface' ], commonSuppressExtensions ],
[ 'vulkan_screen.h', [ 'VK_QNX_screen_surface' ], commonSuppressExtensions ],
[ 'vulkan_beta.h', betaRequireExtensions, betaSuppressExtensions ],
]
@@ -331,7 +374,9 @@ def makeGenOpts(args):
apicall = 'VKAPI_ATTR ',
apientry = 'VKAPI_CALL ',
apientryp = 'VKAPI_PTR *',
alignFuncParam = 48)
alignFuncParam = 48,
misracstyle = misracstyle,
misracppstyle = misracppstyle)
genOpts[headername] = [ COutputGenerator, opts ]
@@ -370,7 +415,9 @@ def makeGenOpts(args):
apicall = 'VKAPI_ATTR ',
apientry = 'VKAPI_CALL ',
apientryp = 'VKAPI_PTR *',
alignFuncParam = 48)
alignFuncParam = 48,
misracstyle = misracstyle,
misracppstyle = misracppstyle)
]
# Unused - vulkan10.h target.
@@ -402,7 +449,9 @@ def makeGenOpts(args):
apicall = 'VKAPI_ATTR ',
apientry = 'VKAPI_CALL ',
apientryp = 'VKAPI_PTR *',
alignFuncParam = 48)
alignFuncParam = 48,
misracstyle = misracstyle,
misracppstyle = misracppstyle)
]
# Unused - vulkan11.h target.
@@ -434,7 +483,9 @@ def makeGenOpts(args):
apicall = 'VKAPI_ATTR ',
apientry = 'VKAPI_CALL ',
apientryp = 'VKAPI_PTR *',
alignFuncParam = 48)
alignFuncParam = 48,
misracstyle = misracstyle,
misracppstyle = misracppstyle)
]
genOpts['alias.h'] = [
@@ -481,6 +532,8 @@ def genTarget(args):
# Create generator options with parameters specified on command line
makeGenOpts(args)
# pdb.set_trace()
# Select a generator matching the requested target
if args.target in genOpts:
createGenerator = genOpts[args.target][0]
@@ -522,6 +575,9 @@ if __name__ == '__main__':
parser.add_argument('-emitExtensions', action='append',
default=[],
help='Specify an extension or extensions to emit in targets')
parser.add_argument('-emitSpirv', action='append',
default=[],
help='Specify a SPIR-V extension or capability to emit in targets')
parser.add_argument('-feature', action='append',
default=[],
help='Specify a core API feature name or names to add to targets')
@@ -557,6 +613,10 @@ if __name__ == '__main__':
help='Suppress script output during normal execution.')
parser.add_argument('-verbose', action='store_false', dest='quiet', default=True,
help='Enable script output during normal execution.')
parser.add_argument('-misracstyle', dest='misracstyle', action='store_true',
help='generate MISRA C-friendly headers')
parser.add_argument('-misracppstyle', dest='misracppstyle', action='store_true',
help='generate MISRA C++-friendly headers')
args = parser.parse_args()

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python3 -i
#
# Copyright 2013-2020 The Khronos Group Inc.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
@@ -12,7 +12,7 @@ import sys
import xml.etree.ElementTree as etree
from collections import defaultdict, namedtuple
from generator import OutputGenerator, GeneratorOptions, write
import pdb
def apiNameMatch(str, supported):
"""Return whether a required api name matches a pattern specified for an
@@ -253,6 +253,12 @@ class FeatureInfo(BaseInfo):
self.number = 0
self.supported = elem.get('supported')
class SpirvInfo(BaseInfo):
"""Registry information about an API <spirvextensions>
or <spirvcapability>."""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
class Registry:
"""Object representing an API registry, loaded from an XML file."""
@@ -299,6 +305,12 @@ class Registry:
self.extdict = {}
"dictionary of FeatureInfo objects for `<extension>` elements keyed by extension name"
self.spirvextdict = {}
"dictionary of FeatureInfo objects for `<spirvextension>` elements keyed by spirv extension name"
self.spirvcapdict = {}
"dictionary of FeatureInfo objects for `<spirvcapability>` elements keyed by spirv capability name"
self.emitFeatures = False
"""True to actually emit features for a version / extension,
or False to just treat them as emitted"""
@@ -344,10 +356,10 @@ class Registry:
Intended for internal use only.
- elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>` Element
- info - corresponding {Type|Group|Enum|Cmd|Feature}Info object
- infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension'
- dictionary - self.{type|group|enum|cmd|api|ext}dict
- elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>`/`<spirvextension>`/`<spirvcapability>` Element
- info - corresponding {Type|Group|Enum|Cmd|Feature|Spirv}Info object
- infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' / 'spirvextension' / 'spirvcapability'
- dictionary - self.{type|group|enum|cmd|api|ext|spirvext|spirvcap}dict
If the Element has an 'api' attribute, the dictionary key is the
tuple (name,api). If not, the key is the name. 'name' is an
@@ -591,6 +603,15 @@ class Registry:
for parent in self.validextensionstructs:
self.validextensionstructs[parent].sort()
# Parse out all spirv tags in dictionaries
# Use addElementInfo to catch duplicates
for spirv in self.reg.findall('spirvextensions/spirvextension'):
spirvInfo = SpirvInfo(spirv)
self.addElementInfo(spirv, spirvInfo, 'spirvextension', self.spirvextdict)
for spirv in self.reg.findall('spirvcapabilities/spirvcapability'):
spirvInfo = SpirvInfo(spirv)
self.addElementInfo(spirv, spirvInfo, 'spirvcapability', self.spirvcapdict)
def dumpReg(self, maxlen=120, filehandle=sys.stdout):
"""Dump all the dictionaries constructed from the Registry object.
@@ -623,6 +644,13 @@ class Registry:
for key in self.extdict:
write(' Extension', key, '->',
etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle)
write('// SPIR-V', file=filehandle)
for key in self.spirvextdict:
write(' SPIR-V Extension', key, '->',
etree.tostring(self.spirvextdict[key].elem)[0:maxlen], file=filehandle)
for key in self.spirvcapdict:
write(' SPIR-V Capability', key, '->',
etree.tostring(self.spirvcapdict[key].elem)[0:maxlen], file=filehandle)
def markTypeRequired(self, typename, required):
"""Require (along with its dependencies) or remove (but not its dependencies) a type.
@@ -1126,6 +1154,19 @@ class Registry:
for c in features.findall('command'):
self.generateFeature(c.get('name'), 'command', self.cmddict)
def generateSpirv(self, spirv, dictionary):
if spirv is None:
self.gen.logMsg('diag', 'No entry found for element', name,
'returning!')
return
name = spirv.elem.get('name')
# No known alias for spirv elements
alias = None
if spirv.emit:
genProc = self.gen.genSpirv
genProc(spirv, name, alias)
def apiGen(self):
"""Generate interface for specified versions using the current
generator and generator options"""
@@ -1145,6 +1186,7 @@ class Registry:
regAddExtensions = re.compile(self.genOpts.addExtensions)
regRemoveExtensions = re.compile(self.genOpts.removeExtensions)
regEmitExtensions = re.compile(self.genOpts.emitExtensions)
regEmitSpirv = re.compile(self.genOpts.emitSpirv)
# Get all matching API feature names & add to list of FeatureInfo
# Note we used to select on feature version attributes, not names.
@@ -1202,10 +1244,16 @@ class Registry:
# the regexp specified in the generator options. This allows
# forcing extensions into an interface even if they're not
# tagged appropriately in the registry.
# However we still respect the 'supported' attribute.
if regAddExtensions.match(extName) is not None:
self.gen.logMsg('diag', 'Including extension',
extName, '(matches explicitly requested extensions to add)')
include = True
if not apiNameMatch(self.genOpts.apiname, ei.elem.get('supported')):
self.gen.logMsg('diag', 'NOT including extension',
extName, '(matches explicitly requested, but does not match the \'supported\' attribute)')
include = False
else:
self.gen.logMsg('diag', 'Including extension',
extName, '(matches explicitly requested extensions to add)')
include = True
# Remove extensions if the name matches the regexp specified
# in generator options. This allows forcing removal of
# extensions from an interface even if they're tagged that
@@ -1233,6 +1281,20 @@ class Registry:
self.gen.logMsg('diag', 'NOT including extension',
extName, '(does not match api attribute or explicitly requested extensions)')
# Add all spirv elements to list
# generators decide to emit them all or not
# Currently no filtering as no client of these elements needs filtering
spirvexts = []
for key in self.spirvextdict:
si = self.spirvextdict[key]
si.emit = (regEmitSpirv.match(key) is not None)
spirvexts.append(si)
spirvcaps = []
for key in self.spirvcapdict:
si = self.spirvcapdict[key]
si.emit = (regEmitSpirv.match(key) is not None)
spirvcaps.append(si)
# Sort the features list, if a sort procedure is defined
if self.genOpts.sortProcedure:
self.genOpts.sortProcedure(features)
@@ -1271,6 +1333,11 @@ class Registry:
self.gen.beginFeature(f.elem, emit)
self.generateRequiredInterface(f.elem)
self.gen.endFeature()
# Generate spirv elements
for s in spirvexts:
self.generateSpirv(s, self.spirvextdict)
for s in spirvcaps:
self.generateSpirv(s, self.spirvcapdict)
self.gen.endFile()
def apiReset(self):

View File

@@ -1,6 +1,6 @@
"""Utility functions not closely tied to other spec_tools types."""
# Copyright (c) 2018-2019 Collabora, Ltd.
# Copyright (c) 2013-2020 The Khronos Group Inc.
# Copyright 2018-2019 Collabora, Ltd.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python3 -i
#
# Copyright (c) 2013-2020 The Khronos Group Inc.
# Copyright 2013-2021 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
@@ -87,6 +87,7 @@ class VulkanConventions(ConventionsBase):
def generate_structure_type_from_name(self, structname):
"""Generate a structure type name, like VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO"""
structure_type_parts = []
# Tokenize into "words"
for elem in MAIN_RE.findall(structname):
@@ -95,7 +96,18 @@ class VulkanConventions(ConventionsBase):
structure_type_parts.append('VK_STRUCTURE_TYPE')
else:
structure_type_parts.append(word.upper())
return '_'.join(structure_type_parts)
name = '_'.join(structure_type_parts)
# The simple-minded rules need modification for some structure names
subpats = [
[ r'_H_(26[45])_', r'_H\1_' ],
[ r'_VULKAN_([0-9])([0-9])_', r'_VULKAN_\1_\2_' ],
[ r'_DIRECT_FB_', r'_DIRECTFB_' ],
]
for subpat in subpats:
name = re.sub(subpat[0], subpat[1], name)
return name
@property
def warning_comment(self):