Update for Vulkan-Docs 1.1.120

This commit is contained in:
Jon Leech 2019-08-17 15:58:46 -07:00 committed by Jon Leech
parent 23b2e8e64b
commit 4ee33d2fbd
22 changed files with 598 additions and 346 deletions

View file

@ -18,17 +18,20 @@ from __future__ import unicode_literals
import io
import os
import re
import pdb
import re
import sys
try:
from pathlib import Path
except ImportError:
from pathlib2 import Path
def write( *args, **kwargs ):
file = kwargs.pop('file',sys.stdout)
end = kwargs.pop('end','\n')
from spec_tools.util import getElemName, getElemType
def write(*args, **kwargs):
file = kwargs.pop('file', sys.stdout)
end = kwargs.pop('end', '\n')
file.write(' '.join(str(arg) for arg in args))
file.write(end)
@ -83,9 +86,10 @@ def regSortExtensionNumberKey(feature):
# then by version number (for features)
# then by extension number (for extensions)
def regSortFeatures(featureList):
featureList.sort(key = regSortExtensionNumberKey)
featureList.sort(key = regSortFeatureVersionKey)
featureList.sort(key = regSortCategoryKey)
featureList.sort(key=regSortExtensionNumberKey)
featureList.sort(key=regSortFeatureVersionKey)
featureList.sort(key=regSortCategoryKey)
# GeneratorOptions - base class for options used during header production
# These options are target language independent, and used by
@ -125,18 +129,18 @@ class GeneratorOptions:
"""Represents options during header production from an API registry"""
def __init__(self,
conventions = None,
filename = None,
directory = '.',
apiname = None,
profile = None,
versions = '.*',
emitversions = '.*',
defaultExtensions = None,
addExtensions = None,
removeExtensions = None,
emitExtensions = None,
sortProcedure = regSortFeatures):
conventions=None,
filename=None,
directory='.',
apiname=None,
profile=None,
versions='.*',
emitversions='.*',
defaultExtensions=None,
addExtensions=None,
removeExtensions=None,
emitExtensions=None,
sortProcedure=regSortFeatures):
self.conventions = conventions
self.filename = filename
self.directory = directory
@ -205,19 +209,19 @@ class OutputGenerator:
# categoryToPath - map XML 'category' to include file directory name
categoryToPath = {
'bitmask' : 'flags',
'enum' : 'enums',
'funcpointer' : 'funcpointers',
'handle' : 'handles',
'define' : 'defines',
'basetype' : 'basetypes',
'bitmask': 'flags',
'enum': 'enums',
'funcpointer': 'funcpointers',
'handle': 'handles',
'define': 'defines',
'basetype': 'basetypes',
}
# Constructor
def __init__(self,
errFile = sys.stderr,
warnFile = sys.stderr,
diagFile = sys.stdout):
errFile=sys.stderr,
warnFile=sys.stderr,
diagFile=sys.stdout):
self.outFile = None
self.errFile = errFile
self.warnFile = warnFile
@ -227,7 +231,7 @@ class OutputGenerator:
self.genOpts = None
self.registry = None
# Used for extension enum value generation
self.extBase = 1000000000
self.extBase = 1000000000
self.extBlockSize = 1000
self.madeDirs = {}
@ -295,21 +299,21 @@ class OutputGenerator:
bitpos = int(value, 0)
numVal = 1 << bitpos
value = '0x%08x' % numVal
if( bitpos >= 32 ):
if bitpos >= 32:
value = value + 'ULL'
self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
return [numVal, value]
if 'offset' in elem.keys():
# Obtain values in the mapping from the attributes
enumNegative = False
offset = int(elem.get('offset'),0)
extnumber = int(elem.get('extnumber'),0)
offset = int(elem.get('offset'), 0)
extnumber = int(elem.get('extnumber'), 0)
extends = elem.get('extends')
if 'dir' in elem.keys():
enumNegative = True
self.logMsg('diag', 'Enum', name, 'offset =', offset,
'extnumber =', extnumber, 'extends =', extends,
'enumNegative =', enumNegative)
'extnumber =', extnumber, 'extends =', extends,
'enumNegative =', enumNegative)
# Now determine the actual enumerant value, as defined
# in the "Layers and Extensions" appendix of the spec.
numVal = self.extBase + (extnumber - 1) * self.extBlockSize + offset
@ -346,7 +350,7 @@ class OutputGenerator:
# happens when defining the same enum conditionally in
# several extension blocks.
if (strVal2 == strVal or (numVal is not None and
numVal == numVal2)):
numVal == numVal2)):
True
# self.logMsg('info', 'checkDuplicateEnums: Duplicate enum (' + name +
# ') found with the same value:' + strVal)
@ -364,14 +368,14 @@ class OutputGenerator:
try:
self.logMsg('warn', 'Two enums found with the same value: '
+ name + ' = ' + name2.get('name') + ' = ' + strVal)
+ name + ' = ' + name2.get('name') + ' = ' + strVal)
except:
pdb.set_trace()
# Track this enum to detect followon duplicates
nameMap[name] = [ elem, numVal, strVal ]
nameMap[name] = [elem, numVal, strVal]
if numVal is not None:
valueMap[numVal] = [ elem, numVal, strVal ]
valueMap[numVal] = [elem, numVal, strVal]
# Add this enum to the list
stripped.append(elem)
@ -385,7 +389,7 @@ class OutputGenerator:
groupElem = groupinfo.elem
if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
return self.buildEnumCDecl_Bitmask( groupinfo, groupName)
return self.buildEnumCDecl_Bitmask(groupinfo, groupName)
else:
return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
@ -406,7 +410,7 @@ class OutputGenerator:
# Should catch exceptions here for more complex constructs. Not yet.
(_, strVal) = self.enumToValue(elem, True)
name = elem.get('name')
body += "static const " + flagTypeName + " " + name + " = " + strVal + ";\n"
body += "static const {} {} = {};\n".format(flagTypeName, name, strVal)
# Postfix
@ -418,17 +422,17 @@ 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-9a-z_])([A-Z0-9])', r'\1_\2', groupName).upper()
expandPrefix = expandName
expandSuffix = ''
expandSuffixMatch = re.search(r'[A-Z][A-Z]+$',groupName)
expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName)
if expandSuffixMatch:
expandSuffix = '_' + expandSuffixMatch.group()
# Strip off the suffix from the prefix
expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
# Prefix
body = "typedef enum " + groupName + " {\n"
body = ["typedef enum %s {" % groupName]
# @@ Should use the type="bitmask" attribute instead
isEnum = ('FLAG_BITS' not in expandPrefix)
@ -450,22 +454,22 @@ class OutputGenerator:
# 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 = ""
aliasText = []
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)
name = elem.get('name')
# Extension enumerants are only included if they are required
if self.isEnumRequired(elem):
decl = " " + name + " = " + strVal + ",\n"
decl = " {} = {},".format(name, strVal)
if numVal is not None:
body += decl
body.append(decl)
else:
aliasText += decl
aliasText.append(decl)
# Don't track min/max for non-numbers (numVal is None)
if isEnum and numVal is not None and elem.get('extends') is None:
@ -480,20 +484,21 @@ class OutputGenerator:
maxValue = numVal
# Now append the non-numeric enumerant values
body += aliasText
body.extend(aliasText)
# Generate min/max value tokens and a range-padding enum. Need some
# additional padding to generate correct names...
if isEnum and expand:
body += " " + expandPrefix + "_BEGIN_RANGE" + expandSuffix + " = " + minName + ",\n"
body += " " + expandPrefix + "_END_RANGE" + expandSuffix + " = " + maxName + ",\n"
body += " " + expandPrefix + "_RANGE_SIZE" + expandSuffix + " = (" + maxName + " - " + minName + " + 1),\n"
body.extend((" {}_BEGIN_RANGE{} = {},".format(expandPrefix, expandSuffix, minName),
" {}_END_RANGE{} = {},".format(
expandPrefix, expandSuffix, maxName),
" {}_RANGE_SIZE{} = ({} - {} + 1),".format(expandPrefix, expandSuffix, maxName, minName)))
# Always generate this to make sure the enumerated type is 32 bits
body += " " + expandPrefix + "_MAX_ENUM" + expandSuffix + " = 0x7FFFFFFF\n"
body.append(" {}_MAX_ENUM{} = 0x7FFFFFFF".format(
expandPrefix, expandSuffix))
# Postfix
body += "} " + groupName + ";"
body.append("} %s;" % groupName)
# Determine appropriate section for this declaration
if groupElem.get('type') == 'bitmask':
@ -501,7 +506,7 @@ class OutputGenerator:
else:
section = 'group'
return (section, body)
return (section, '\n'.join(body))
def makeDir(self, path):
self.logMsg('diag', 'OutputGenerator::makeDir(' + path + ')')
@ -514,6 +519,10 @@ class OutputGenerator:
def beginFile(self, genOpts):
self.genOpts = genOpts
self.should_insert_may_alias_macro = \
self.genOpts.conventions.should_insert_may_alias_macro(self.genOpts)
self.conventions = genOpts.conventions
# Open specified output file. Not done in constructor since a
# Generator can be used without writing to a file.
@ -603,13 +612,14 @@ class OutputGenerator:
# aligncol - if non-zero, attempt to align the nested <name> element
# at this column
def makeCParamDecl(self, param, aligncol):
paramdecl = ' ' + noneStr(param.text)
indent = ' '
paramdecl = indent + noneStr(param.text)
for elem in param:
text = noneStr(elem.text)
tail = noneStr(elem.tail)
if self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
# OpenXR-specific macro insertion
if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
# OpenXR-specific macro insertion - but not in apiinc for the spec
tail = self.genOpts.conventions.make_voidpointer_alias(tail)
if elem.tag == 'name' and aligncol > 0:
self.logMsg('diag', 'Aligning parameter', elem.text, 'to column', self.genOpts.alignFuncParam)
@ -619,17 +629,22 @@ class OutputGenerator:
# This works around a problem where very long type names -
# longer than the alignment column - would run into the tail
# text.
paramdecl = paramdecl.ljust(aligncol-1) + ' '
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 aligncol == 0:
# Squeeze out multiple spaces other than the identation
paramdecl = indent + ' '.join(paramdecl.split())
return paramdecl
# getCParamTypeLength - return the length of the type field is an indented, formatted
# declaration for a <param> or <member> block (e.g. function parameter
# or structure/union member).
# getCParamTypeLength - return the length of the type field in an
# indented, formatted declaration for a <param> or <member> block (e.g.
# function parameter or structure/union member). This relies on the
# presence of the <name> tag; if not present, return zero.
# param - Element (<param> or <member>) to identify
def getCParamTypeLength(self, param):
newLen = 0
paramdecl = ' ' + noneStr(param.text)
for elem in param:
text = noneStr(elem.text)
@ -646,17 +661,106 @@ class OutputGenerator:
return newLen
def getMaxCParamTypeLength(self, info):
"""Return the length of the longest type field for a member/parameter.
info - TypeInfo or CommandInfo.
"""
lengths = (self.getCParamTypeLength(member)
for member in info.getMembers())
return max(lengths)
def getHandleParent(self, typename):
"""Get the parent of a handle object."""
info = self.registry.typedict.get(typename)
if info is None:
return None
elem = info.elem
if elem is not None:
return elem.get('parent')
return None
def iterateHandleAncestors(self, typename):
"""Iterate through the ancestors of a handle type."""
current = self.getHandleParent(typename)
while current is not None:
yield current
current = self.getHandleParent(current)
def getHandleAncestors(self, typename):
"""Get the ancestors of a handle object."""
return list(self.iterateHandleAncestors(typename))
def getTypeCategory(self, typename):
"""Get the category of a type."""
info = self.registry.typedict.get(typename)
if info is None:
return None
elem = info.elem
if elem is not None:
return elem.get('category')
return None
def isStructAlwaysValid(self, structname):
"""Try to do check if a structure is always considered valid (i.e. there's no rules to its acceptance)."""
# A conventions object is required for this call.
if not self.conventions:
raise RuntimeError("To use isStructAlwaysValid, be sure your options include a Conventions object.")
if self.conventions.type_always_valid(structname):
return True
category = self.getTypeCategory(structname)
if self.conventions.category_requires_validation(category):
return False
info = self.registry.typedict.get(structname)
assert(info is not None)
members = info.getMembers()
for member in members:
member_name = getElemName(member)
if member_name in (self.conventions.structtype_member_name,
self.conventions.nextpointer_member_name):
return False
if member.get('noautovalidity'):
return False
member_type = getElemType(member)
if member_type in ('void', 'char') or self.paramIsArray(member) or self.paramIsPointer(member):
return False
if self.conventions.type_always_valid(member_type):
continue
member_category = self.getTypeCategory(member_type)
if self.conventions.category_requires_validation(member_category):
return False
if member_category in ('struct', 'union'):
if self.isStructAlwaysValid(member_type) is False:
return False
return True
# isEnumRequired(elem) - return True if this <enum> element is
# required, False otherwise
# elem - <enum> element to test
def isEnumRequired(self, elem):
required = elem.get('required') is not None
self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
'->', required)
'->', required)
return required
#@@@ This code is overridden by equivalent code now run in
#@@@ Registry.generateFeature
# @@@ This code is overridden by equivalent code now run in
# @@@ Registry.generateFeature
required = False
@ -707,6 +811,12 @@ class OutputGenerator:
else:
pdecl += text + tail
tdecl += text + tail
if self.genOpts.alignFuncParam == 0:
# Squeeze out multiple spaces - there is no indentation
pdecl = ' '.join(pdecl.split())
tdecl = ' '.join(tdecl.split())
# Now add the parameter declaration list, which is identical
# for prototypes and typedefs. Concatenate all the text from
# a <param> node without the tags. No tree walking required
@ -732,7 +842,7 @@ class OutputGenerator:
else:
paramdecl += 'void'
paramdecl += ");"
return [ pdecl + indentdecl, tdecl + paramdecl ]
return [pdecl + indentdecl, tdecl + paramdecl]
def newline(self):
write('', file=self.outFile)