gfxstream: simplify codegen am: 4f8febda59
Original change: https://android-review.googlesource.com/c/platform/hardware/google/gfxstream/+/3270517
Change-Id: I9301db0006a9ee6ba12b3efff98962bc189a7b0d
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/apiconventions.py b/codegen/vulkan/vulkan-docs-next/scripts/apiconventions.py
deleted file mode 100644
index d170dd4..0000000
--- a/codegen/vulkan/vulkan-docs-next/scripts/apiconventions.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2021-2023 The Khronos Group Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-# Generic alias for working group-specific API conventions interface.
-
-# This import should be changed at the repository / working group level to
-# specify the correct API's conventions.
-
-
-import os
-
-defaultAPI = 'vulkan'
-
-VulkanAPI = os.getenv('VULKAN_API', default=defaultAPI)
-
-if VulkanAPI == 'vulkansc':
- from vkconventions import VulkanSCConventions as APIConventions
-else:
- from vkconventions import VulkanConventions as APIConventions
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cereal/common/vulkantypes.py b/codegen/vulkan/vulkan-docs-next/scripts/cereal/common/vulkantypes.py
index 8f2fff2..79d7dad 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cereal/common/vulkantypes.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cereal/common/vulkantypes.py
@@ -661,15 +661,12 @@
def parseFilterFuncExpr(expr):
res = parse_func_expr(parse_sexp(expr))
- print("parseFilterFuncExpr: parsed %s" % res)
return res
def parseLetBodyExpr(expr):
res = parse_func_expr(parse_sexp(expr))
- print("parseLetBodyExpr: parsed %s" % res)
return res
-
def makeVulkanTypeFromXMLTag(typeInfo, parentName: str, tag: Element) -> VulkanType:
res = VulkanType()
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cereal/counting.py b/codegen/vulkan/vulkan-docs-next/scripts/cereal/counting.py
index b6d628a..8df2570 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cereal/counting.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cereal/counting.py
@@ -418,9 +418,6 @@
self.beginFilterGuard(vulkanType)
self.doAllocSpace(vulkanType)
- if vulkanType.filterVar != None:
- print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
-
if vulkanType.isHandleType() and self.mapHandles:
self.genHandleMappingCall(vulkanType, access, lenAccess)
else:
@@ -457,8 +454,6 @@
if vulkanType.isHandleType() and self.mapHandles:
access = self.exprAccessor(vulkanType)
- if vulkanType.filterVar != None:
- print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
self.genHandleMappingCall(
vulkanType.getForAddressAccess(), access, "1")
elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cereal/marshaling.py b/codegen/vulkan/vulkan-docs-next/scripts/cereal/marshaling.py
index 0593fb3..a7d6394 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cereal/marshaling.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cereal/marshaling.py
@@ -540,9 +540,6 @@
self.beginFilterGuard(vulkanType)
self.doAllocSpace(vulkanType)
- if vulkanType.filterVar != None:
- print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
-
if vulkanType.isHandleType() and self.mapHandles:
self.genHandleMappingCall(vulkanType, access, lenAccess)
else:
@@ -576,8 +573,6 @@
if vulkanType.isHandleType() and self.mapHandles:
access = self.exprAccessor(vulkanType)
- if vulkanType.filterVar != None:
- print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
self.genHandleMappingCall(
vulkanType.getForAddressAccess(), access, "1")
elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cereal/reservedmarshaling.py b/codegen/vulkan/vulkan-docs-next/scripts/cereal/reservedmarshaling.py
index 492077e..4f15663 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cereal/reservedmarshaling.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cereal/reservedmarshaling.py
@@ -638,9 +638,6 @@
self.beginFilterGuard(vulkanType)
self.doAllocSpace(vulkanType)
- if vulkanType.filterVar != None:
- print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
-
if vulkanType.isHandleType() and self.mapHandles:
self.genHandleMappingCall(
vulkanType, access, lenAccess, lenAccessGuard)
@@ -675,8 +672,6 @@
if vulkanType.isHandleType() and self.mapHandles:
access = self.exprAccessor(vulkanType)
- if vulkanType.filterVar != None:
- print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar))
self.genHandleMappingCall(
vulkanType.getForAddressAccess(), access, "1", None)
elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName):
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py b/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
index 7d650ff..8a3eadc 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cerealgenerator.py
@@ -241,7 +241,6 @@
def envGetOrDefault(key, default=None):
if key in os.environ:
return os.environ[key]
- print("envGetOrDefault: notfound: %s" % key)
return default
# ---- methods overriding base class ----
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/cgenerator.py b/codegen/vulkan/vulkan-docs-next/scripts/cgenerator.py
index ef8d681..44a2ba4 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/cgenerator.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/cgenerator.py
@@ -1,6 +1,7 @@
#!/usr/bin/python3 -i
#
# Copyright 2013-2023 The Khronos Group Inc.
+# Copyright 2023-2024 Google Inc.
#
# SPDX-License-Identifier: Apache-2.0
@@ -8,7 +9,6 @@
import re
from generator import (GeneratorOptions,
- MissingGeneratorOptionsConventionsError,
MissingGeneratorOptionsError, MissingRegistryError,
OutputGenerator, noneStr, regSortFeatures, write)
@@ -20,25 +20,9 @@
def __init__(self,
prefixText='',
- genFuncPointers=True,
- protectFile=True,
- protectFeature=True,
- protectProto=None,
- protectProtoStr=None,
- protectExtensionProto=None,
- protectExtensionProtoStr=None,
- apicall='',
apientry='',
apientryp='',
- indentFuncProto=True,
- indentFuncPointer=False,
alignFuncParam=0,
- genEnumBeginEndRange=False,
- genAliasMacro=False,
- genStructExtendsComment=False,
- aliasMacro='',
- misracstyle=False,
- misracppstyle=False,
**kwargs
):
"""Constructor.
@@ -46,115 +30,27 @@
- prefixText - list of strings to prefix generated header with
(usually a copyright statement + calling convention macros)
- - protectFile - True if multiple inclusion protection should be
- generated (based on the filename) around the entire header
- - protectFeature - True if #ifndef..#endif protection should be
- generated around a feature interface in the header file
- - genFuncPointers - True if function pointer typedefs should be
- generated
- - protectProto - If conditional protection should be generated
- around prototype declarations, set to either '#ifdef'
- to require opt-in (#ifdef protectProtoStr) or '#ifndef'
- to require opt-out (#ifndef protectProtoStr). Otherwise
- set to None.
- - protectProtoStr - #ifdef/#ifndef symbol to use around prototype
- declarations, if protectProto is set
- - protectExtensionProto - If conditional protection should be generated
- around extension prototype declarations, set to either '#ifdef'
- to require opt-in (#ifdef protectExtensionProtoStr) or '#ifndef'
- to require opt-out (#ifndef protectExtensionProtoStr). Otherwise
- set to None
- - protectExtensionProtoStr - #ifdef/#ifndef symbol to use around
- extension prototype declarations, if protectExtensionProto is set
- - apicall - string to use for the function declaration prefix,
- such as APICALL on Windows
- apientry - string to use for the calling convention macro,
in typedefs, such as APIENTRY
- apientryp - string to use for the calling convention macro
in function pointer typedefs, such as APIENTRYP
- - indentFuncProto - True if prototype declarations should put each
- parameter on a separate line
- - indentFuncPointer - True if typedefed function pointers should put each
- parameter on a separate line
- alignFuncParam - if nonzero and parameters are being put on a
- separate line, align parameter names at the specified column
- - genEnumBeginEndRange - True if BEGIN_RANGE / END_RANGE macros should
- 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)
- - genStructExtendsComment - True if comments showing the structures
- whose pNext chain a structure extends are included before its
- definition
- - aliasMacro - alias macro to inject when genAliasMacro is True
- - misracstyle - generate MISRA C-friendly headers
- - misracppstyle - generate MISRA C++-friendly headers"""
+ separate line, align parameter names at the specified column"""
GeneratorOptions.__init__(self, **kwargs)
self.prefixText = prefixText
"""list of strings to prefix generated header with (usually a copyright statement + calling convention macros)."""
- self.genFuncPointers = genFuncPointers
- """True if function pointer typedefs should be generated"""
-
- self.protectFile = protectFile
- """True if multiple inclusion protection should be generated (based on the filename) around the entire header."""
-
- self.protectFeature = protectFeature
- """True if #ifndef..#endif protection should be generated around a feature interface in the header file."""
-
- self.protectProto = protectProto
- """If conditional protection should be generated around prototype declarations, set to either '#ifdef' to require opt-in (#ifdef protectProtoStr) or '#ifndef' to require opt-out (#ifndef protectProtoStr). Otherwise set to None."""
-
- self.protectProtoStr = protectProtoStr
- """#ifdef/#ifndef symbol to use around prototype declarations, if protectProto is set"""
-
- self.protectExtensionProto = protectExtensionProto
- """If conditional protection should be generated around extension prototype declarations, set to either '#ifdef' to require opt-in (#ifdef protectExtensionProtoStr) or '#ifndef' to require opt-out (#ifndef protectExtensionProtoStr). Otherwise set to None."""
-
- self.protectExtensionProtoStr = protectExtensionProtoStr
- """#ifdef/#ifndef symbol to use around extension prototype declarations, if protectExtensionProto is set"""
-
- self.apicall = apicall
- """string to use for the function declaration prefix, such as APICALL on Windows."""
-
self.apientry = apientry
"""string to use for the calling convention macro, in typedefs, such as APIENTRY."""
self.apientryp = apientryp
"""string to use for the calling convention macro in function pointer typedefs, such as APIENTRYP."""
- self.indentFuncProto = indentFuncProto
- """True if prototype declarations should put each parameter on a separate line"""
-
- self.indentFuncPointer = indentFuncPointer
- """True if typedefed function pointers should put each parameter on a separate line"""
-
self.alignFuncParam = alignFuncParam
"""if nonzero and parameters are being put on a separate line, align parameter names at the specified column"""
- self.genEnumBeginEndRange = genEnumBeginEndRange
- """True if BEGIN_RANGE / END_RANGE macros should be generated for enumerated types"""
-
- self.genAliasMacro = genAliasMacro
- """True if the OpenXR alias macro should be generated for aliased types (unclear what other circumstances this is useful)"""
-
- self.genStructExtendsComment = genStructExtendsComment
- """True if comments showing the structures whose pNext chain a structure extends are included before its definition"""
-
- 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"""
-
-
class COutputGenerator(OutputGenerator):
"""Generates C-language API interfaces."""
@@ -168,21 +64,11 @@
# Internal state - accumulators for different inner block text
self.sections = {section: [] for section in self.ALL_SECTIONS}
self.feature_not_empty = False
- self.may_alias = None
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- # C-specific
- #
- # Multiple inclusion protection & C++ wrappers.
- if self.genOpts.protectFile and self.genOpts.filename:
- headerSym = re.sub(r'\.h', '_h_',
- os.path.basename(self.genOpts.filename)).upper()
- write('#ifndef', headerSym, file=self.outFile)
- write('#define', headerSym, '1', file=self.outFile)
- self.newline()
# User-supplied prefix text, if any (list of strings)
if genOpts.prefixText:
@@ -205,9 +91,6 @@
write('#ifdef __cplusplus', file=self.outFile)
write('}', file=self.outFile)
write('#endif', file=self.outFile)
- if self.genOpts.protectFile and self.genOpts.filename:
- self.newline()
- write('#endif', file=self.outFile)
# Finish processing in superclass
OutputGenerator.endFile(self)
@@ -221,18 +104,6 @@
self.sections = {section: [] for section in self.ALL_SECTIONS}
self.feature_not_empty = False
- def _endProtectComment(self, protect_str, protect_directive='#ifdef'):
- if protect_directive is None or protect_str is None:
- raise RuntimeError('Should not call in here without something to protect')
-
- # Do not put comments after #endif closing blocks if this is not set
- if not self.genOpts.conventions.protectProtoComment:
- return ''
- elif 'ifdef' in protect_directive:
- return f' /* {protect_str} */'
- else:
- return f' /* !{protect_str} */'
-
def endFeature(self):
"Actually write the interface to the output file."
# C-specific
@@ -240,63 +111,24 @@
if self.feature_not_empty:
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- if self.genOpts.conventions is None:
- raise MissingGeneratorOptionsConventionsError()
- is_core = self.featureName and self.featureName.startswith(self.conventions.api_prefix + 'VERSION_')
- if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
- self.newline()
- if self.genOpts.protectFeature:
- write('#ifndef', self.featureName, file=self.outFile)
+ is_core = self.featureName and self.featureName.startswith('VK_VERSION_')
+ self.newline()
- # If type declarations are needed by other features based on
- # this one, it may be necessary to suppress the ExtraProtect,
- # or move it below the 'for section...' loop.
- if self.featureExtraProtect is not None:
- write('#ifdef', self.featureExtraProtect, file=self.outFile)
+ # Generate warning of possible use in IDEs
+ write(f'// {self.featureName} is a preprocessor guard. Do not pass it to API calls.', file=self.outFile)
+ write('#define', self.featureName, '1', file=self.outFile)
+ for section in self.TYPE_SECTIONS:
+ contents = self.sections[section]
+ if contents:
+ write('\n'.join(contents), file=self.outFile)
+
+ if self.sections['commandPointer']:
+ write('\n'.join(self.sections['commandPointer']), file=self.outFile)
self.newline()
- # Generate warning of possible use in IDEs
- write(f'// {self.featureName} is a preprocessor guard. Do not pass it to API calls.', file=self.outFile)
- write('#define', self.featureName, '1', file=self.outFile)
- for section in self.TYPE_SECTIONS:
- contents = self.sections[section]
- if contents:
- write('\n'.join(contents), file=self.outFile)
+ if self.sections['command']:
+ write('\n'.join(self.sections['command']), end='', file=self.outFile)
- if self.genOpts.genFuncPointers and self.sections['commandPointer']:
- write('\n'.join(self.sections['commandPointer']), file=self.outFile)
- self.newline()
-
- if self.sections['command']:
- if self.genOpts.protectProto:
- write(self.genOpts.protectProto,
- self.genOpts.protectProtoStr, file=self.outFile)
- if self.genOpts.protectExtensionProto and not is_core:
- write(self.genOpts.protectExtensionProto,
- self.genOpts.protectExtensionProtoStr, file=self.outFile)
- write('\n'.join(self.sections['command']), end='', file=self.outFile)
- if self.genOpts.protectExtensionProto and not is_core:
- write('#endif' +
- self._endProtectComment(protect_directive=self.genOpts.protectExtensionProto,
- protect_str=self.genOpts.protectExtensionProtoStr),
- file=self.outFile)
- if self.genOpts.protectProto:
- write('#endif' +
- self._endProtectComment(protect_directive=self.genOpts.protectProto,
- protect_str=self.genOpts.protectProtoStr),
- file=self.outFile)
- else:
- self.newline()
-
- if self.featureExtraProtect is not None:
- write('#endif' +
- self._endProtectComment(protect_str=self.featureExtraProtect),
- file=self.outFile)
-
- if self.genOpts.protectFeature:
- write('#endif' +
- self._endProtectComment(protect_str=self.featureName),
- file=self.outFile)
# Finish processing in superclass
OutputGenerator.endFeature(self)
@@ -304,7 +136,6 @@
"Append a definition to the specified section"
if section is None:
- self.logMsg('error', 'Missing section in appendSection (probably a <type> element missing its \'category\' attribute. Text:', text)
exit(1)
self.sections[section].append(text)
@@ -334,22 +165,15 @@
else:
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- # OpenXR: this section was not under 'else:' previously, just fell through
- if alias:
- # If the type is an alias, just emit a typedef declaration
- body = 'typedef ' + alias + ' ' + name + ';\n'
- else:
- # Replace <apientry /> tags with an APIENTRY-style string
- # (from self.genOpts). Copy other text through unchanged.
- # If the resulting text is an empty string, do not emit it.
- body = noneStr(typeElem.text)
- for elem in typeElem:
- if elem.tag == 'apientry':
- body += self.genOpts.apientry + noneStr(elem.tail)
- else:
- body += noneStr(elem.text) + noneStr(elem.tail)
- if category == 'define' and self.misracppstyle():
- body = body.replace("(uint32_t)", "static_cast<uint32_t>")
+ # Replace <apientry /> tags with an APIENTRY-style string
+ # (from self.genOpts). Copy other text through unchanged.
+ # If the resulting text is an empty string, do not emit it.
+ body = noneStr(typeElem.text)
+ for elem in typeElem:
+ if elem.tag == 'apientry':
+ body += self.genOpts.apientry + noneStr(elem.tail)
+ else:
+ body += noneStr(elem.text) + noneStr(elem.tail)
if body:
# Add extra newline after multi-line entries.
if '\n' in body[0:-1]:
@@ -380,25 +204,6 @@
return (protect_if_str, protect_end_str)
- def typeMayAlias(self, typeName):
- if not self.may_alias:
- if self.registry is None:
- raise MissingRegistryError()
- # First time we have asked if a type may alias.
- # So, populate the set of all names of types that may.
-
- # Everyone with an explicit mayalias="true"
- self.may_alias = set(typeName
- for typeName, data in self.registry.typedict.items()
- if data.elem.get('mayalias') == 'true')
-
- # Every type mentioned in some other type's parentstruct attribute.
- polymorphic_bases = (otherType.elem.get('parentstruct')
- for otherType in self.registry.typedict.values())
- self.may_alias.update(set(x for x in polymorphic_bases
- if x is not None))
- return typeName in self.may_alias
-
def genStruct(self, typeinfo, typeName, alias):
"""Generate struct (e.g. C "struct" type).
@@ -426,18 +231,8 @@
if protect_begin:
body += protect_begin
- if self.genOpts.genStructExtendsComment:
- structextends = typeElem.get('structextends')
- body += '// ' + typeName + ' extends ' + structextends + '\n' if structextends else ''
-
body += 'typedef ' + typeElem.get('category')
- # This is an OpenXR-specific alternative where aliasing refers
- # to an inheritance hierarchy of types rather than C-level type
- # aliases.
- if self.genOpts.genAliasMacro and self.typeMayAlias(typeName):
- body += ' ' + self.genOpts.aliasMacro
-
body += ' ' + typeName + ' {\n'
targetLen = self.getMaxCParamTypeLength(typeinfo)
@@ -472,11 +267,6 @@
# for the alias.
body = 'typedef ' + alias + ' ' + groupName + ';\n'
self.appendSection(section, body)
- else:
- if self.genOpts is None:
- raise MissingGeneratorOptionsError()
- (section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName)
- self.appendSection(section, '\n' + body)
def genEnum(self, enuminfo, name, alias):
"""Generate the C declaration for a constant (a single <enum> value).
@@ -493,21 +283,10 @@
"Command generation"
OutputGenerator.genCmd(self, cmdinfo, name, alias)
- # if alias:
- # prefix = '// ' + name + ' is an alias of command ' + alias + '\n'
- # else:
- # prefix = ''
if self.genOpts is None:
raise MissingGeneratorOptionsError()
prefix = ''
decls = self.makeCDecls(cmdinfo.elem)
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;
+ self.appendSection('commandPointer', decls[1])
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/generator.py b/codegen/vulkan/vulkan-docs-next/scripts/generator.py
index 107cffa..51ae8cf 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/generator.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/generator.py
@@ -1,6 +1,7 @@
#!/usr/bin/python3 -i
#
# Copyright 2013-2023 The Khronos Group Inc.
+# Copyright 2023-2024 Google Inc.
#
# SPDX-License-Identifier: Apache-2.0
"""Base class for source/header/doc generators, as well as some utility functions."""
@@ -9,7 +10,6 @@
import io
import os
-import pdb
import re
import shutil
import sys
@@ -19,8 +19,40 @@
except ImportError:
from pathlib2 import Path # type: ignore
-from spec_tools.util import getElemName, getElemType
+CATEGORIES_REQUIRING_VALIDATION = set(('handle',
+ 'enum',
+ 'bitmask',
+ 'basetype',
+ None))
+# These are basic C types pulled in via openxr_platform_defines.h
+TYPES_KNOWN_ALWAYS_VALID = set(('char',
+ 'float',
+ 'int8_t', 'uint8_t',
+ 'int16_t', 'uint16_t',
+ 'int32_t', 'uint32_t',
+ 'int64_t', 'uint64_t',
+ 'size_t',
+ 'intptr_t', 'uintptr_t',
+ 'int',
+ ))
+
+def getElemName(elem, default=None):
+ """Get the name associated with an element, either a name child or name attribute."""
+ name_elem = elem.find('name')
+ if name_elem is not None:
+ return name_elem.text
+ # Fallback if there is no child.
+ return elem.get('name', default)
+
+
+def getElemType(elem, default=None):
+ """Get the type associated with an element, either a type child or type attribute."""
+ type_elem = elem.find('type')
+ if type_elem is not None:
+ return type_elem.text
+ # Fallback if there is no child.
+ return elem.get('type', default)
def write(*args, **kwargs):
file = kwargs.pop('file', sys.stdout)
@@ -28,6 +60,23 @@
file.write(' '.join(str(arg) for arg in args))
file.write(end)
+def category_requires_validation(category):
+ """Return True if the given type 'category' always requires validation.
+
+ Defaults to a reasonable implementation.
+
+ May override."""
+ return category in CATEGORIES_REQUIRING_VALIDATION
+
+def type_always_valid(typename):
+ """Return True if the given type name is always valid (never requires validation).
+
+ This is for things like integers.
+
+ Defaults to a reasonable implementation.
+
+ May override."""
+ return typename in TYPES_KNOWN_ALWAYS_VALID
def noneStr(s):
"""Return string argument, or "" if argument is None.
@@ -38,18 +87,6 @@
return s
return ""
-
-def enquote(s):
- """Return string argument with surrounding quotes,
- for serialization into Python code."""
- if s:
- if isinstance(s, str):
- return f"'{s}'"
- else:
- return s
- return None
-
-
def regSortCategoryKey(feature):
"""Sort key for regSortFeatures.
Sorts by category of the feature name string:
@@ -130,17 +167,6 @@
full_msg += ': ' + msg
super().__init__(full_msg)
-
-class MissingGeneratorOptionsConventionsError(RuntimeError):
- """Error raised when a Generator tries to do something that requires a Conventions object but it is None."""
-
- def __init__(self, msg=None):
- full_msg = 'Missing Conventions object self.genOpts.conventions'
- if msg:
- full_msg += ': ' + msg
- super().__init__(full_msg)
-
-
class GeneratorOptions:
"""Base class for options used during header/documentation production.
@@ -148,71 +174,34 @@
Registry.apiGen() and by base OutputGenerator objects."""
def __init__(self,
- conventions=None,
filename=None,
directory='.',
- genpath=None,
- apiname=None,
- mergeApiNames=None,
- profile=None,
versions='.*',
emitversions='.*',
- defaultExtensions=None,
addExtensions=None,
- removeExtensions=None,
emitExtensions=None,
- emitSpirv=None,
- emitFormats=None,
- reparentEnums=True,
sortProcedure=regSortFeatures,
- requireCommandAliases=False,
- requireDepends=True,
):
"""Constructor.
Arguments:
- - conventions - may be mandatory for some generators:
an object that implements ConventionsBase
- filename - basename of file to generate, or None to write to stdout.
- directory - directory in which to generate filename
- - genpath - path to previously generated files, such as apimap.py
- - apiname - string matching `<api>` 'apiname' attribute, e.g. 'gl'.
- - mergeApiNames - If not None, a comma separated list of API names
- to merge into the API specified by 'apiname'
- - profile - string specifying API profile , e.g. 'core', or None.
- versions - regex matching API versions to process interfaces for.
Normally `'.*'` or `'[0-9][.][0-9]'` to match all defined versions.
- emitversions - regex matching API versions to actually emit
interfaces for (though all requested versions are considered
when deciding which interfaces to generate). For GL 4.3 glext.h,
this might be `'1[.][2-5]|[2-4][.][0-9]'`.
- - defaultExtensions - If not None, a string which must in its
- entirety match the pattern in the "supported" attribute of
- the `<extension>`. Defaults to None. Usually the same as apiname.
- addExtensions - regex matching names of additional extensions
to include. Defaults to None.
- - removeExtensions - regex matching names of extensions to
- remove (after defaultExtensions and addExtensions). Defaults
- to None.
- emitExtensions - regex matching names of extensions to actually emit
interfaces for (though all requested versions are considered when
deciding which interfaces to generate). Defaults to None.
- - emitSpirv - regex matching names of extensions and capabilities
- to actually emit interfaces for.
- - emitFormats - regex matching names of formats 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
- InterfaceGenerator relies on the list of interfaces in the <feature>
- or <extension> being complete. Defaults to True.
- sortProcedure - takes a list of FeatureInfo objects and sorts
them in place to a preferred order in the generated output.
- - requireCommandAliases - if True, treat command aliases
- as required dependencies.
- - requireDepends - whether to follow API dependencies when emitting
- APIs.
Default is
- core API versions
@@ -222,28 +211,13 @@
The regex patterns can be None or empty, in which case they match
nothing."""
- self.conventions = conventions
- """may be mandatory for some generators:
- an object that implements ConventionsBase"""
self.filename = filename
"basename of file to generate, or None to write to stdout."
- self.genpath = genpath
- """path to previously generated files, such as apimap.py"""
-
self.directory = directory
"directory in which to generate filename"
- self.apiname = apiname
- "string matching `<api>` 'apiname' attribute, e.g. 'gl'."
-
- self.mergeApiNames = mergeApiNames
- "comma separated list of API names to merge into the API specified by 'apiname'"
-
- self.profile = profile
- "string specifying API profile , e.g. 'core', or None."
-
self.versions = self.emptyRegex(versions)
"""regex matching API versions to process interfaces for.
Normally `'.*'` or `'[0-9][.][0-9]'` to match all defined versions."""
@@ -254,56 +228,24 @@
when deciding which interfaces to generate). For GL 4.3 glext.h,
this might be `'1[.][2-5]|[2-4][.][0-9]'`."""
- self.defaultExtensions = defaultExtensions
- """If not None, a string which must in its
- entirety match the pattern in the "supported" attribute of
- the `<extension>`. Defaults to None. Usually the same as apiname."""
-
self.addExtensions = self.emptyRegex(addExtensions)
"""regex matching names of additional extensions
to include. Defaults to None."""
- self.removeExtensions = self.emptyRegex(removeExtensions)
- """regex matching names of extensions to
- remove (after defaultExtensions and addExtensions). Defaults
- to None."""
-
self.emitExtensions = self.emptyRegex(emitExtensions)
"""regex matching names of extensions to actually emit
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.emitFormats = self.emptyRegex(emitFormats)
- """regex matching names of formats
- to actually emit interfaces for."""
-
- self.reparentEnums = reparentEnums
- """boolean specifying whether to remove <enum> elements from
- <feature> or <extension> when extending an <enums> type."""
-
self.sortProcedure = sortProcedure
"""takes a list of FeatureInfo objects and sorts
them in place to a preferred order in the generated output.
Default is core API versions, ARB/KHR/OES extensions, all
other extensions, alphabetically within each group."""
- self.codeGenerator = False
- """True if this generator makes compilable code"""
-
self.registry = None
"""Populated later with the registry object."""
- self.requireCommandAliases = requireCommandAliases
- """True if alias= attributes of <command> tags are transitively
- required."""
-
- self.requireDepends = requireDepends
- """True if dependencies of API tags are transitively required."""
-
def emptyRegex(self, pat):
"""Substitute a regular expression which matches no version
or extension names for None or the empty string."""
@@ -331,17 +273,6 @@
'basetype': 'basetypes',
}
- def breakName(self, name, msg):
- """Break into debugger if this is a special name"""
-
- # List of string names to break on
- bad = (
- )
-
- if name in bad and True:
- print('breakName {}: {}'.format(name, msg))
- pdb.set_trace()
-
def __init__(self, errFile=sys.stderr, warnFile=sys.stderr, diagFile=sys.stdout):
"""Constructor
@@ -376,35 +307,6 @@
# derived generators.
self.apidict = None
- # File suffix for generated files, set in beginFile below.
- self.file_suffix = ''
-
- def logMsg(self, level, *args):
- """Write a message of different categories to different
- destinations.
-
- - `level`
- - 'diag' (diagnostic, voluminous)
- - 'warn' (warning)
- - 'error' (fatal error - raises exception after logging)
-
- - `*args` - print()-style arguments to direct to corresponding log"""
- if level == 'error':
- strfile = io.StringIO()
- write('ERROR:', *args, file=strfile)
- if self.errFile is not None:
- write(strfile.getvalue(), file=self.errFile)
- raise UserWarning(strfile.getvalue())
- elif level == 'warn':
- if self.warnFile is not None:
- write('WARNING:', *args, file=self.warnFile)
- elif level == 'diag':
- if self.diagFile is not None:
- write('DIAG:', *args, file=self.diagFile)
- else:
- raise UserWarning(
- '*** FATAL ERROR in Generator.logMsg: unknown level:' + level)
-
def enumToValue(self, elem, needsNum, bitwidth = 32,
forceSuffix = False, parent_for_alias_dereference=None):
"""Parse and convert an `<enum>` tag into a value.
@@ -439,8 +341,6 @@
declared first when emitting this enum."""
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- if self.genOpts.conventions is None:
- raise MissingGeneratorOptionsConventionsError()
name = elem.get('name')
numVal = None
@@ -459,7 +359,6 @@
value = value + 'ULL'
else:
value = value + 'U'
- self.logMsg('diag', 'Enum', name, '-> value [', numVal, ',', value, ']')
return [numVal, value]
if 'bitpos' in elem.keys():
value = elem.get('bitpos')
@@ -470,7 +369,6 @@
value = value + 'ULL'
elif forceSuffix:
value = value + 'U'
- self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
return [numVal, value]
if 'offset' in elem.keys():
# Obtain values in the mapping from the attributes
@@ -480,9 +378,6 @@
extends = elem.get('extends')
if 'dir' in elem.keys():
enumNegative = True
- self.logMsg('diag', 'Enum', name, 'offset =', offset,
- '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
@@ -490,7 +385,6 @@
numVal *= -1
value = '%d' % numVal
# More logic needed!
- self.logMsg('diag', 'Enum', name, '-> offset [', numVal, ',', value, ']')
return [numVal, value]
if 'alias' in elem.keys():
alias_of = elem.get('alias')
@@ -504,321 +398,6 @@
raise RuntimeError("Could not find the aliased enum value")
return [None, None]
- def checkDuplicateEnums(self, enums):
- """Check enumerated values for duplicates.
-
- - enums - list of `<enum>` Elements
-
- returns the list with duplicates stripped"""
- # Dictionaries indexed by name and numeric value.
- # Entries are [ Element, numVal, strVal ] matching name or value
-
- nameMap = {}
- valueMap = {}
-
- stripped = []
- for elem in enums:
- name = elem.get('name')
- (numVal, strVal) = self.enumToValue(elem, True)
-
- if name in nameMap:
- # Duplicate name found; check values
- (name2, numVal2, strVal2) = nameMap[name]
-
- # Duplicate enum values for the same name are benign. This
- # happens when defining the same enum conditionally in
- # several extension blocks.
- if (strVal2 == strVal or (numVal is not None
- and numVal == numVal2)):
- True
- # self.logMsg('info', 'checkDuplicateEnums: Duplicate enum (' + name +
- # ') found with the same value:' + strVal)
- else:
- self.logMsg('warn', 'checkDuplicateEnums: Duplicate enum (' + name
- + ') found with different values:' + strVal
- + ' and ' + strVal2)
-
- # Do not add the duplicate to the returned list
- continue
- elif numVal in valueMap:
- # Duplicate value found (such as an alias); report it, but
- # still add this enum to the list.
- (name2, numVal2, strVal2) = valueMap[numVal]
-
- msg = 'Two enums found with the same value: {} = {} = {}'.format(
- name, name2.get('name'), strVal)
- self.logMsg('error', msg)
-
- # Track this enum to detect followon duplicates
- nameMap[name] = [elem, numVal, strVal]
- if numVal is not None:
- valueMap[numVal] = [elem, numVal, strVal]
-
- # Add this enum to the list
- stripped.append(elem)
-
- # 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"""
- if self.genOpts is None:
- raise MissingGeneratorOptionsError()
- if self.genOpts.conventions is None:
- raise MissingGeneratorOptionsConventionsError()
-
- groupElem = groupinfo.elem
-
- # 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:
- bitwidth = int(groupElem.get('bitwidth'))
- 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)
-
- 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
- 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)
- else:
- return self.buildEnumCDecl_BitmaskOrDefine(groupinfo, groupName, bitwidth, usedefine)
- else:
- # Validate the bitwidth and generate values appropriately
- 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_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 = 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 does not 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 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, 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)
-
- 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 + "']")
- if alias is not None:
- (numVal, strVal) = self.enumToValue(alias, True, bitwidth, True)
- else:
- self.logMsg('error', 'No such alias {} for enum {}'.format(strVal, name))
- 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
-
- return ("bitmask", body)
-
- def buildEnumCDecl_Enum(self, expand, groupinfo, groupName):
- """Generate the C declaration for an enumerated type"""
- groupElem = groupinfo.elem
-
- # Break the group name into prefix and suffix portions for range
- # enum generation
- 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)
- if expandSuffixMatch:
- expandSuffix = '_' + expandSuffixMatch.group()
- # Strip off the suffix from the prefix
- expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
-
- # Prefix
- body = ["typedef enum %s {" % groupName]
-
- # @@ 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')
-
- # Check for and report duplicates, and return a list with them
- # removed.
- enums = self.checkDuplicateEnums(enums)
-
- # Loop over the nested 'enum' tags. Keep track of the minimum and
- # maximum numeric values, if they can be determined; but only for
- # core API enumerants, not extension enumerants. This is inferred
- # by looking for 'extends' attributes.
- minName = None
-
- # Accumulate non-numeric enumerant values separately and append
- # them following the numeric values, to allow for aliases.
- # NOTE: this does not do a topological sort yet, so aliases of
- # aliases can still get in the wrong order.
- aliasText = []
-
- maxName = None
- minValue = None
- maxValue = None
- 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)
- name = elem.get('name')
-
- # Extension enumerants are only included if they are required
- if self.isEnumRequired(elem):
- 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:
- aliasText.append(decl)
-
- # Range check for the enum value
- 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)
-
- # Do not track min/max for non-numbers (numVal is None)
- if isEnum and numVal is not None and elem.get('extends') is None:
- if minName is None:
- minName = maxName = name
- minValue = maxValue = numVal
- elif minValue is None or numVal < minValue:
- minName = name
- minValue = numVal
- elif maxValue is None or numVal > maxValue:
- maxName = name
- maxValue = numVal
-
- # Now append the non-numeric enumerant values
- body.extend(aliasText)
-
- # Generate min/max value tokens - legacy use case.
- if isEnum and expand:
- body.extend((f' {expandPrefix}_BEGIN_RANGE{expandSuffix} = {minName},',
- f' {expandPrefix}_END_RANGE{expandSuffix} = {maxName},',
- f' {expandPrefix}_RANGE_SIZE{expandSuffix} = ({maxName} - {minName} + 1),'))
-
- # Generate a range-padding value to ensure the enum is 32 bits, but
- # only in code generators, so it does not appear in documentation
- if (self.genOpts.codeGenerator or
- self.conventions.generate_max_enum_in_docs):
- body.append(f' {expandPrefix}_MAX_ENUM{expandSuffix} = 0x7FFFFFFF')
-
- # Postfix
- body.append("} %s;" % groupName)
-
- # Determine appropriate section for this declaration
- if groupElem.get('type') == 'bitmask':
- section = 'bitmask'
- else:
- section = 'group'
-
- return (section, '\n'.join(body))
-
def buildConstantCDecl(self, enuminfo, name, alias):
"""Generate the C declaration for a constant (a single <enum>
value).
@@ -828,18 +407,7 @@
(_, 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:
+ if enuminfo.elem.get('type') and not alias:
# Generate e.g.: #define x (~0ULL)
typeStr = enuminfo.elem.get('type');
invert = '~' in strVal
@@ -860,18 +428,6 @@
return body
- def makeDir(self, path):
- """Create a directory, if not already done.
-
- Generally called from derived generators creating hierarchies."""
- self.logMsg('diag', 'OutputGenerator::makeDir(' + path + ')')
- if path not in self.madeDirs:
- # This can get race conditions with multiple writers, see
- # https://stackoverflow.com/questions/273192/
- if not os.path.exists(path):
- os.makedirs(path)
- self.madeDirs[path] = None
-
def beginFile(self, genOpts):
"""Start a new interface file
@@ -880,24 +436,6 @@
self.genOpts = genOpts
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- if self.genOpts.conventions is None:
- raise MissingGeneratorOptionsConventionsError()
- self.should_insert_may_alias_macro = \
- self.genOpts.conventions.should_insert_may_alias_macro(self.genOpts)
- self.file_suffix = self.genOpts.conventions.file_suffix
-
- # Try to import the API dictionary, apimap.py, if it exists. Nothing
- # in apimap.py cannot be extracted directly from the XML, and in the
- # future we should do that.
- if self.genOpts.genpath is not None:
- try:
- sys.path.insert(0, self.genOpts.genpath)
- import apimap
- self.apidict = apimap
- except ImportError:
- self.apidict = None
-
- self.conventions = genOpts.conventions
# Open a temporary file for accumulating output.
if self.genOpts.filename is not None:
@@ -939,8 +477,6 @@
self.emit = emit
self.featureName = interface.get('name')
self.featureType = interface.get('type')
- # If there is an additional 'protect' attribute in the feature, save it
- self.featureExtraProtect = interface.get('protect')
def endFeature(self):
"""Finish an interface file, closing it when done.
@@ -948,21 +484,6 @@
Derived classes responsible for emitting feature"""
self.featureName = None
self.featureType = 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 is 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 are generating something only inside a `<feature>` tag"""
@@ -1019,46 +540,6 @@
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 genFormat(self, format, formatinfo, alias):
- """Generate interface for a format element.
-
- - formatinfo - FormatInfo
-
- Extend to generate as desired in your derived class."""
- return
-
- def genSyncStage(self, stageinfo):
- """Generate interface for a sync stage element.
-
- - stageinfo - SyncStageInfo
-
- Extend to generate as desired in your derived class."""
- return
-
- def genSyncAccess(self, accessinfo):
- """Generate interface for a sync stage element.
-
- - accessinfo - AccessInfo
-
- Extend to generate as desired in your derived class."""
- return
-
- def genSyncPipeline(self, pipelineinfo):
- """Generate interface for a sync stage element.
-
- - pipelineinfo - SyncPipelineInfo
-
- 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.
@@ -1085,8 +566,6 @@
at this column"""
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- if self.genOpts.conventions is None:
- raise MissingGeneratorOptionsConventionsError()
indent = ' '
paramdecl = indent
prefix = noneStr(param.text)
@@ -1095,11 +574,7 @@
text = noneStr(elem.text)
tail = noneStr(elem.tail)
- 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)
# Align at specified column, if possible
paramdecl = paramdecl.rstrip()
oldLen = len(paramdecl)
@@ -1108,14 +583,8 @@
# text.
paramdecl = paramdecl.ljust(aligncol - 1) + ' '
newLen = len(paramdecl)
- self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
- 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
+ paramdecl += prefix + text + tail
# Clear prefix for subsequent iterations
prefix = ''
@@ -1135,8 +604,6 @@
- param - Element (`<param>` or `<member>`) to identify"""
if self.genOpts is None:
raise MissingGeneratorOptionsError()
- if self.genOpts.conventions is None:
- raise MissingGeneratorOptionsConventionsError()
# Allow for missing <name> tag
newLen = 0
@@ -1145,52 +612,21 @@
text = noneStr(elem.text)
tail = noneStr(elem.tail)
- if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
- # OpenXR-specific macro insertion
- tail = self.genOpts.conventions.make_voidpointer_alias(tail)
if elem.tag == 'name':
# Align at specified column, if possible
newLen = len(paramdecl.rstrip())
- self.logMsg('diag', 'Identifying length of', elem.text, 'as', newLen)
paramdecl += text + tail
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."""
- if self.registry is None:
- raise MissingRegistryError()
-
- 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."""
if self.registry is None:
@@ -1208,28 +644,22 @@
def isStructAlwaysValid(self, structname):
"""Try to do check if a structure is always considered valid (i.e. there is 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.registry is None:
raise MissingRegistryError()
- if self.conventions.type_always_valid(structname):
+ if type_always_valid(structname):
return True
category = self.getTypeCategory(structname)
- if self.conventions.category_requires_validation(category):
+ if category_requires_validation(category):
return False
info = self.registry.typedict.get(structname)
- if info is None:
- self.logMsg('error', f'isStructAlwaysValid({structname}) - structure not found in typedict')
-
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):
+ if member_name in ('sType', 'pNext'):
return False
if member.get('noautovalidity'):
@@ -1240,12 +670,12 @@
if member_type in ('void', 'char') or self.paramIsArray(member) or self.paramIsPointer(member):
return False
- if self.conventions.type_always_valid(member_type):
+ if type_always_valid(member_type):
continue
member_category = self.getTypeCategory(member_type)
- if self.conventions.category_requires_validation(member_category):
+ if category_requires_validation(member_category):
return False
if member_category in ('struct', 'union'):
@@ -1275,8 +705,6 @@
- elem - `<enum>` element to test"""
required = elem.get('required') is not None
- self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
- '->', required)
return required
# @@@ This code is overridden by equivalent code now run in
@@ -1288,7 +716,7 @@
if extname is not None:
# 'supported' attribute was injected when the <enum> element was
# moved into the <enums> group in Registry.parseTree()
- if self.genOpts.defaultExtensions == elem.get('supported'):
+ if 'vulkan' == elem.get('supported'):
required = True
elif re.match(self.genOpts.addExtensions, extname) is not None:
required = True
@@ -1309,7 +737,7 @@
proto = cmd.find('proto')
params = cmd.findall('param')
# Begin accumulating prototype and typedef strings
- pdecl = self.genOpts.apicall
+ pdecl = 'VKAPI_ATTR '
tdecl = 'typedef '
# Insert the function return type/name.
@@ -1359,27 +787,8 @@
paramdecl = '('
if n > 0:
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)
+ paramnames = (''.join(t for t in p.itertext())
+ for p in params)
paramdecl += ', '.join(paramnames)
else:
paramdecl += 'void'
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/genvk.py b/codegen/vulkan/vulkan-docs-next/scripts/genvk.py
index eb231f6..b8b24c9 100755
--- a/codegen/vulkan/vulkan-docs-next/scripts/genvk.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/genvk.py
@@ -1,16 +1,14 @@
#!/usr/bin/python3
#
# Copyright 2013-2023 The Khronos Group Inc.
+# Copyright 2023-2024 Google Inc.
#
# SPDX-License-Identifier: Apache-2.0
import argparse
import os
-import pdb
import re
import sys
-import copy
-import time
import xml.etree.ElementTree as etree
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
@@ -19,28 +17,12 @@
from generator import write
from reg import Registry
-from apiconventions import APIConventions
# gfxstream + cereal modules
from cerealgenerator import CerealGenerator
-# Simple timer functions
-startTime = None
from typing import Optional
-def startTimer(timeit):
- global startTime
- if timeit:
- startTime = time.process_time()
-
-
-def endTimer(timeit, msg):
- global startTime
- if timeit and startTime is not None:
- endTime = time.process_time()
- startTime = None
-
-
def makeREstring(strings, default=None, strings_are_regex=False):
"""Turn a list of strings into a regexp string matching exactly those strings."""
if strings or default is None:
@@ -59,53 +41,17 @@
global genOpts
genOpts = {}
- # Default class of extensions to include, or None
- defaultExtensions = args.defaultExtensions
-
- # Additional extensions to include (list of extensions)
- extensions = args.extension
-
- # Extensions to remove (list of extensions)
- removeExtensions = args.removeExtensions
-
- # Extensions to emit (list of extensions)
- emitExtensions = args.emitExtensions
-
- # SPIR-V capabilities / features to emit (list of extensions & capabilities)
- emitSpirv = args.emitSpirv
-
- # Vulkan Formats to emit
- emitFormats = args.emitFormats
-
- # Features to include (list of features)
- features = args.feature
-
- # Whether to disable inclusion protect in headers
- protect = args.protect
-
# Output target directory
directory = args.directory
- # Path to generated files, particularly apimap.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
- allFormats = allSpirv = allFeatures = allExtensions = r'.*'
+ allFormats = 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)
- emitFormatsPat = makeREstring(emitFormats, allFormats)
- featuresPat = makeREstring(features, allFeatures)
+ emitExtensionsPat = makeREstring([], allExtensions)
+ emitFormatsPat = makeREstring([], allFormats)
+ featuresPat = makeREstring([], allFeatures)
# Copyright text prefixing all headers (list of strings).
# The SPDX formatting below works around constraints of the 'reuse' tool
@@ -127,200 +73,15 @@
''
]
- vulkanLayer = args.vulkanLayer
-
- # Defaults for generating re-inclusion protection wrappers (or not)
- protectFile = protect
-
- # An API style conventions object
- conventions = APIConventions()
-
- if args.apiname is not None:
- defaultAPIName = args.apiname
- else:
- defaultAPIName = conventions.xml_api_name
-
- # APIs to merge
- mergeApiNames = args.mergeApiNames
-
- isCTS = args.isCTS
-
- # Platform extensions, in their own header files
- # Each element of the platforms[] array defines information for
- # generating a single platform:
- # [0] is the generated header file name
- # [1] is the set of platform extensions to generate
- # [2] is additional extensions whose interfaces should be considered,
- # but suppressed in the output, to avoid duplicate definitions of
- # dependent types like VkDisplayKHR and VkSurfaceKHR which come from
- # non-platform extensions.
-
- # Track all platform extensions, for exclusion from vulkan_core.h
- allPlatformExtensions = []
-
- # Extensions suppressed for all WSI platforms (WSI extensions required
- # by all platforms)
- commonSuppressExtensions = [ 'VK_KHR_display', 'VK_KHR_swapchain' ]
-
- # Extensions required and suppressed for beta "platform". This can
- # probably eventually be derived from the requires= attributes of
- # the extension blocks.
- betaRequireExtensions = [
- 'VK_KHR_portability_subset',
- 'VK_KHR_video_encode_queue',
- 'VK_EXT_video_encode_h264',
- 'VK_EXT_video_encode_h265',
- 'VK_NV_displacement_micromap',
- 'VK_AMDX_shader_enqueue',
- ]
-
- betaSuppressExtensions = [
- 'VK_KHR_video_queue',
- 'VK_EXT_opacity_micromap',
- 'VK_KHR_pipeline_library',
- ]
-
- platforms = [
- [ 'vulkan_android.h', [ 'VK_KHR_android_surface',
- 'VK_ANDROID_external_memory_android_hardware_buffer',
- 'VK_ANDROID_external_format_resolve'
- ], commonSuppressExtensions +
- [ 'VK_KHR_format_feature_flags2',
- ] ],
- [ 'vulkan_fuchsia.h', [ 'VK_FUCHSIA_imagepipe_surface',
- 'VK_FUCHSIA_external_memory',
- 'VK_FUCHSIA_external_semaphore',
- 'VK_FUCHSIA_buffer_collection' ], commonSuppressExtensions ],
- [ 'vulkan_ggp.h', [ 'VK_GGP_stream_descriptor_surface',
- 'VK_GGP_frame_token' ], commonSuppressExtensions ],
- [ 'vulkan_ios.h', [ 'VK_MVK_ios_surface' ], commonSuppressExtensions ],
- [ 'vulkan_macos.h', [ 'VK_MVK_macos_surface' ], commonSuppressExtensions ],
- [ 'vulkan_vi.h', [ 'VK_NN_vi_surface' ], commonSuppressExtensions ],
- [ 'vulkan_wayland.h', [ 'VK_KHR_wayland_surface' ], commonSuppressExtensions ],
- [ 'vulkan_win32.h', [ 'VK_.*_win32(|_.*)', 'VK_.*_winrt(|_.*)', 'VK_EXT_full_screen_exclusive' ],
- commonSuppressExtensions +
- [ 'VK_KHR_external_semaphore',
- 'VK_KHR_external_memory_capabilities',
- 'VK_KHR_external_fence',
- 'VK_KHR_external_fence_capabilities',
- 'VK_KHR_get_surface_capabilities2',
- 'VK_NV_external_memory_capabilities',
- ] ],
- [ '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',
- 'VK_EXT_metal_objects' ], commonSuppressExtensions ],
- [ 'vulkan_screen.h', [ 'VK_QNX_screen_surface',
- 'VK_QNX_external_memory_screen_buffer' ], commonSuppressExtensions ],
- [ 'vulkan_sci.h', [ 'VK_NV_external_sci_sync',
- 'VK_NV_external_sci_sync2',
- 'VK_NV_external_memory_sci_buf'], commonSuppressExtensions ],
- [ 'vulkan_beta.h', betaRequireExtensions, betaSuppressExtensions ],
- ]
-
- for platform in platforms:
- headername = platform[0]
-
- allPlatformExtensions += platform[1]
-
- addPlatformExtensionsRE = makeREstring(
- platform[1] + platform[2], strings_are_regex=True)
- emitPlatformExtensionsRE = makeREstring(
- platform[1], strings_are_regex=True)
-
- opts = CGeneratorOptions(
- conventions = conventions,
- filename = headername,
- directory = directory,
- genpath = None,
- apiname = defaultAPIName,
- mergeApiNames = mergeApiNames,
- profile = None,
- versions = featuresPat,
- emitversions = None,
- defaultExtensions = None,
- addExtensions = addPlatformExtensionsRE,
- removeExtensions = None,
- emitExtensions = emitPlatformExtensionsRE,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
-
- genOpts[headername] = [ COutputGenerator, opts ]
-
- # Header for core API + extensions.
- # To generate just the core API,
- # change to 'defaultExtensions = None' below.
- #
- # By default this adds all enabled, non-platform extensions.
- # It removes all platform extensions (from the platform headers options
- # constructed above) as well as any explicitly specified removals.
-
- removeExtensionsPat = makeREstring(
- allPlatformExtensions + removeExtensions, None, strings_are_regex=True)
-
- genOpts['vulkan_core.h'] = [
- COutputGenerator,
- CGeneratorOptions(
- conventions = conventions,
- filename = 'vulkan_core.h',
- directory = directory,
- genpath = None,
- apiname = defaultAPIName,
- mergeApiNames = mergeApiNames,
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = defaultExtensions,
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
- ]
-
- # Serializer for spec
genOpts['cereal'] = [
CerealGenerator,
CGeneratorOptions(
- conventions = conventions,
directory = directory,
- apiname = 'vulkan',
- profile = None,
versions = featuresPat,
emitversions = featuresPat,
- defaultExtensions = defaultExtensions,
addExtensions = None,
- removeExtensions = None,
emitExtensions = emitExtensionsPat,
prefixText = prefixStrings + vkPrefixStrings,
- genFuncPointers = True,
- protectFile = protectFile,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
apientry = 'VKAPI_CALL ',
apientryp = 'VKAPI_PTR *',
alignFuncParam = 48)
@@ -337,32 +98,18 @@
genOpts['vulkan_gfxstream.h'] = [
COutputGenerator,
CGeneratorOptions(
- conventions = conventions,
filename = 'vulkan_gfxstream.h',
directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
versions = featuresPat,
emitversions = None,
- defaultExtensions = None,
addExtensions = makeREstring(['VK_GOOGLE_gfxstream'], None),
- removeExtensions = None,
emitExtensions = makeREstring(['VK_GOOGLE_gfxstream'], None),
prefixText = prefixStrings + vkPrefixStrings + gfxstreamPrefixStrings,
- genFuncPointers = True,
# Use #pragma once in the prefixText instead, so that we can put the copyright comments
# at the beginning of the file.
- protectFile = False,
- protectFeature = False,
- protectProto = '#ifndef',
- protectProtoStr = 'VK_NO_PROTOTYPES',
- apicall = 'VKAPI_ATTR ',
apientry = 'VKAPI_CALL ',
apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- misracstyle = misracstyle,
- misracppstyle = misracppstyle)
+ alignFuncParam = 48)
]
def genTarget(args):
@@ -375,7 +122,6 @@
- target - target to generate
- directory - directory to generate it in
- - protect - True if re-inclusion wrappers should be created
- extensions - list of additional extensions to include in generated interfaces"""
# Create generator options with parameters specified on command line
@@ -400,92 +146,22 @@
# of names, or a regular expression.
if __name__ == '__main__':
parser = argparse.ArgumentParser()
-
- parser.add_argument('-apiname', action='store',
- default=None,
- help='Specify API to generate (defaults to repository-specific conventions object value)')
- parser.add_argument('-mergeApiNames', action='store',
- default=None,
- help='Specify a comma separated list of APIs to merge into the target API')
- parser.add_argument('-defaultExtensions', action='store',
- default=APIConventions().xml_api_name,
- help='Specify a single class of extensions to add to targets')
- parser.add_argument('-extension', action='append',
- default=[],
- help='Specify an extension or extensions to add to targets')
- parser.add_argument('-removeExtensions', action='append',
- default=[],
- help='Specify an extension or extensions to remove from targets')
- 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('-emitFormats', action='append',
- default=[],
- help='Specify Vulkan Formats to emit in targets')
- parser.add_argument('-feature', action='append',
- default=[],
- help='Specify a core API feature name or names to add to targets')
- parser.add_argument('-debug', action='store_true',
- help='Enable debugging')
- parser.add_argument('-dump', action='store_true',
- help='Enable dump to stderr')
- parser.add_argument('-diagfile', action='store',
- default=None,
- help='Write diagnostics to specified file')
- parser.add_argument('-errfile', action='store',
- default=None,
- help='Write errors and warnings to specified file instead of stderr')
- parser.add_argument('-noprotect', dest='protect', action='store_false',
- help='Disable inclusion protection in output headers')
- parser.add_argument('-profile', action='store_true',
- help='Enable profiling')
parser.add_argument('-registry', action='store',
default='vk.xml',
help='Use specified registry file instead of vk.xml')
parser.add_argument('-registryGfxstream', action='store',
default=None,
help='Use specified gfxstream registry file')
- parser.add_argument('-time', action='store_true',
- help='Enable timing')
- parser.add_argument('-genpath', action='store', default='gen',
- help='Path to generated files')
parser.add_argument('-o', action='store', dest='directory',
default='.',
help='Create target and related files in specified directory')
parser.add_argument('target', metavar='target', nargs='?',
help='Specify target')
- parser.add_argument('-quiet', action='store_true', default=True,
- 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('--vulkanLayer', action='store_true', dest='vulkanLayer',
- help='Enable scripts to generate VK specific vulkan_json_data.hpp for json_gen_layer.')
- 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')
- parser.add_argument('--iscts', action='store_true', dest='isCTS',
- help='Specify if this should generate CTS compatible code')
args = parser.parse_args()
- # This splits arguments which are space-separated lists
- args.feature = [name for arg in args.feature for name in arg.split()]
- args.extension = [name for arg in args.extension for name in arg.split()]
-
- # create error/warning & diagnostic files
- if args.errfile:
- errWarn = open(args.errfile, 'w', encoding='utf-8')
- else:
- errWarn = sys.stderr
-
- if args.diagfile:
- diag = open(args.diagfile, 'w', encoding='utf-8')
- else:
- diag = None
+ errWarn = sys.stderr
+ diag = None
# Create the API generator & generator options
(gen, options) = genTarget(args)
@@ -495,9 +171,7 @@
reg = Registry(gen, options)
# Parse the specified registry XML into an ElementTree object
- startTimer(args.time)
tree = etree.parse(args.registry)
- endTimer(args.time, '* Time to make ElementTree =')
# Merge the gfxstream registry with the official Vulkan registry if the
# target is the cereal generator
@@ -530,7 +204,6 @@
if name not in originalEntryDict.keys():
treeEntries.append(entry)
continue
- print(f'Entry {entriesName}:{name}')
originalEntry = originalEntryDict[name]
@@ -553,17 +226,5 @@
originalEntry.append(child)
# Load the XML tree into the registry object
- startTimer(args.time)
reg.loadElementTree(tree)
- endTimer(args.time, '* Time to parse ElementTree =')
-
- if args.dump:
- reg.dumpReg(filehandle=open('regdump.txt', 'w', encoding='utf-8'))
-
- # Finally, use the output generator to create the requested target
- if args.debug:
- pdb.run('reg.apiGen()')
- else:
- startTimer(args.time)
- reg.apiGen()
- endTimer(args.time, '* Time to generate ' + args.target + ' =')
+ reg.apiGen()
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/reg.py b/codegen/vulkan/vulkan-docs-next/scripts/reg.py
index 4b5a80f..803825b 100644
--- a/codegen/vulkan/vulkan-docs-next/scripts/reg.py
+++ b/codegen/vulkan/vulkan-docs-next/scripts/reg.py
@@ -1,6 +1,7 @@
#!/usr/bin/python3 -i
#
# Copyright 2013-2023 The Khronos Group Inc.
+# Copyright 2023-2024 Google Inc.
#
# SPDX-License-Identifier: Apache-2.0
@@ -13,7 +14,6 @@
from collections import defaultdict, deque, namedtuple
from generator import GeneratorOptions, OutputGenerator, noneStr, write
-from apiconventions import APIConventions
def apiNameMatch(str, supported):
"""Return whether a required api name matches a pattern specified for an
@@ -30,43 +30,8 @@
# Fallthrough case - either str is None or the test failed
return False
-def matchAPIProfile(api, profile, elem):
+def matchAPIProfile(api, elem):
"""Return whether an API and profile
- being generated matches an element's profile
-
- - api - string naming the API to match
- - profile - string naming the profile to match
- - elem - Element which (may) have 'api' and 'profile'
- attributes to match to.
-
- If a tag is not present in the Element, the corresponding API
- or profile always matches.
-
- Otherwise, the tag must exactly match the API or profile.
-
- Thus, if 'profile' = core:
-
- - `<remove>` with no attribute will match
- - `<remove profile="core">` will match
- - `<remove profile="compatibility">` will not match
-
- Possible match conditions:
-
- ```
- Requested Element
- Profile Profile
- --------- --------
- None None Always matches
- 'string' None Always matches
- None 'string' Does not match. Cannot generate multiple APIs
- or profiles, so if an API/profile constraint
- is present, it must be asked for explicitly.
- 'string' 'string' Strings must match
- ```
-
- ** In the future, we will allow regexes for the attributes,
- not just strings, so that `api="^(gl|gles2)"` will match. Even
- this is not really quite enough, we might prefer something
like `"gl(core)|gles1(common-lite)"`."""
# Match 'api', if present
elem_api = elem.get('api')
@@ -77,120 +42,8 @@
elif api != elem_api:
# Requested API does not match attribute
return False
- elem_profile = elem.get('profile')
- if elem_profile:
- if profile is None:
- raise UserWarning("No profile requested, but 'profile' attribute is present with value '"
- + elem_profile + "'")
- elif profile != elem_profile:
- # Requested profile does not match attribute
- return False
return True
-
-def mergeAPIs(tree, fromApiNames, toApiName):
- """Merge multiple APIs using the precedence order specified in apiNames.
- Also deletes <remove> elements.
-
- tree - Element at the root of the hierarchy to merge.
- apiNames - list of strings of API names."""
-
- stack = deque()
- stack.append(tree)
-
- while len(stack) > 0:
- parent = stack.pop()
-
- for child in parent.findall('*'):
- if child.tag == 'remove':
- # Remove <remove> elements
- parent.remove(child)
- else:
- stack.append(child)
-
- supportedList = child.get('supported')
- if supportedList:
- supportedList = supportedList.split(',')
- for apiName in [toApiName] + fromApiNames:
- if apiName in supportedList:
- child.set('supported', toApiName)
-
- if child.get('api'):
- definitionName = None
- definitionVariants = []
-
- # Keep only one definition with the same name if there are multiple definitions
- if child.tag in ['type']:
- if child.get('name') is not None:
- definitionName = child.get('name')
- definitionVariants = parent.findall(f"{child.tag}[@name='{definitionName}']")
- else:
- definitionName = child.find('name').text
- definitionVariants = parent.findall(f"{child.tag}/name[.='{definitionName}']/..")
- elif child.tag in ['member', 'param']:
- definitionName = child.find('name').text
- definitionVariants = parent.findall(f"{child.tag}/name[.='{definitionName}']/..")
- elif child.tag in ['enum', 'feature']:
- definitionName = child.get('name')
- definitionVariants = parent.findall(f"{child.tag}[@name='{definitionName}']")
- elif child.tag in ['require']:
- definitionName = child.get('feature')
- definitionVariants = parent.findall(f"{child.tag}[@feature='{definitionName}']")
- elif child.tag in ['command']:
- definitionName = child.find('proto/name').text
- definitionVariants = parent.findall(f"{child.tag}/proto/name[.='{definitionName}']/../..")
-
- if definitionName:
- bestMatchApi = None
- requires = None
- for apiName in [toApiName] + fromApiNames:
- for variant in definitionVariants:
- # Keep any requires attributes from the target API
- if variant.get('requires') and variant.get('api') == apiName:
- requires = variant.get('requires')
- # Find the best matching definition
- if apiName in variant.get('api').split(',') and bestMatchApi is None:
- bestMatchApi = variant.get('api')
-
- if bestMatchApi:
- for variant in definitionVariants:
- if variant.get('api') != bestMatchApi:
- # Only keep best matching definition
- parent.remove(variant)
- else:
- # Add requires attribute from the target API if it is not overridden
- if requires is not None and variant.get('requires') is None:
- variant.set('requires', requires)
- variant.set('api', toApiName)
-
-
-def stripNonmatchingAPIs(tree, apiName, actuallyDelete = True):
- """Remove tree Elements with 'api' attributes matching apiName.
-
- tree - Element at the root of the hierarchy to strip. Only its
- children can actually be removed, not the tree itself.
- apiName - string which much match a command-separated component of
- the 'api' attribute.
- actuallyDelete - only delete matching elements if True."""
-
- stack = deque()
- stack.append(tree)
-
- while len(stack) > 0:
- parent = stack.pop()
-
- for child in parent.findall('*'):
- api = child.get('api')
-
- if apiNameMatch(apiName, api):
- # Add child to the queue
- stack.append(child)
- elif not apiNameMatch(apiName, api):
- # Child does not match requested api. Remove it.
- if actuallyDelete:
- parent.remove(child)
-
-
class BaseInfo:
"""Base class for information about a registry feature
(type/group/enum/command/API/extension).
@@ -361,43 +214,6 @@
self.supported = elem.get('supported', 'disabled')
-class SpirvInfo(BaseInfo):
- """Registry information about an API <spirvextensions>
- or <spirvcapability>."""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
-
-class FormatInfo(BaseInfo):
- """Registry information about an API <format>."""
-
- def __init__(self, elem, condition):
- BaseInfo.__init__(self, elem)
- # Need to save the condition here when it is known
- self.condition = condition
-
-class SyncStageInfo(BaseInfo):
- """Registry information about <syncstage>."""
-
- def __init__(self, elem, condition):
- BaseInfo.__init__(self, elem)
- # Need to save the condition here when it is known
- self.condition = condition
-
-class SyncAccessInfo(BaseInfo):
- """Registry information about <syncaccess>."""
-
- def __init__(self, elem, condition):
- BaseInfo.__init__(self, elem)
- # Need to save the condition here when it is known
- self.condition = condition
-
-class SyncPipelineInfo(BaseInfo):
- """Registry information about <syncpipeline>."""
-
- def __init__(self, elem):
- BaseInfo.__init__(self, elem)
-
class Registry:
"""Object representing an API registry, loaded from an XML file."""
@@ -412,7 +228,7 @@
if genOpts is None:
# If no generator is provided, we may still need the XML API name
# (for example, in genRef.py).
- self.genOpts = GeneratorOptions(apiname = APIConventions().xml_api_name)
+ self.genOpts = GeneratorOptions(apiname = 'vulkan')
else:
self.genOpts = genOpts
"Options controlling features to write and how to format them"
@@ -445,44 +261,10 @@
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.formatsdict = {}
- "dictionary of FeatureInfo objects for `<format>` elements keyed by VkFormat name"
-
- self.syncstagedict = {}
- "dictionary of Sync*Info objects for `<syncstage>` elements keyed by VkPipelineStageFlagBits2 name"
-
- self.syncaccessdict = {}
- "dictionary of Sync*Info objects for `<syncaccess>` elements keyed by VkAccessFlagBits2 name"
-
- self.syncpipelinedict = {}
- "dictionary of Sync*Info objects for `<syncpipeline>` elements keyed by pipeline type name"
-
self.emitFeatures = False
"""True to actually emit features for a version / extension,
or False to just treat them as emitted"""
- self.breakPat = None
- "regexp pattern to break on when generating names"
- # self.breakPat = re.compile('VkFenceImportFlagBits.*')
-
- self.requiredextensions = [] # Hack - can remove it after validity generator goes away
-
- # ** Global types for automatic source generation **
- # Length Member data
- self.commandextensiontuple = namedtuple('commandextensiontuple',
- ['command', # The name of the command being modified
- 'value', # The value to append to the command
- 'extension']) # The name of the extension that added it
- self.validextensionstructs = defaultdict(list)
- self.commandextensionsuccesses = []
- self.commandextensionerrors = []
-
self.filename = None
def loadElementTree(self, tree):
@@ -515,13 +297,10 @@
The dictionary key is the element 'name' attribute."""
- # self.gen.logMsg('diag', 'Adding ElementInfo.required =',
- # info.required, 'name =', elem.get('name'))
key = elem.get('name')
if key in dictionary:
if not dictionary[key].compareElem(info, infoName):
- self.gen.logMsg('warn', 'Attempt to redefine', key,
- '(this should not happen)')
+ return
else:
dictionary[key] = info
@@ -534,20 +313,14 @@
- fname - name of type / enum / command
- dictionary - self.{type|enum|cmd}dict"""
- key = (fname, self.genOpts.apiname)
+ key = (fname, 'vulkan')
if key in dictionary:
- # self.gen.logMsg('diag', 'Found API-specific element for feature', fname)
return dictionary[key]
if fname in dictionary:
- # self.gen.logMsg('diag', 'Found generic element for feature', fname)
return dictionary[fname]
return None
- def breakOnName(self, regexp):
- """Specify a feature name regexp to break on when generating features."""
- self.breakPat = re.compile(regexp)
-
def parseTree(self):
"""Parse the registry Element, once created"""
# This must be the Element for the root <registry>
@@ -555,26 +328,6 @@
raise RuntimeError("Tree not initialized!")
self.reg = self.tree.getroot()
- # Preprocess the tree in one of the following ways:
- # - either merge a set of APIs to another API based on their 'api' attributes
- # - or remove all elements with non-matching 'api' attributes
- # The preprocessing happens through a breath-first tree traversal.
- # This is a blunt hammer, but eliminates the need to track and test
- # the apis deeper in processing to select the correct elements and
- # avoid duplicates.
- # Schema validation should prevent duplicate elements with
- # overlapping api attributes, or where one element has an api
- # attribute and the other does not.
-
- if self.genOpts.mergeApiNames:
- mergeAPIs(self.reg, self.genOpts.mergeApiNames.split(','), self.genOpts.apiname)
- else:
- stripNonmatchingAPIs(self.reg, self.genOpts.apiname, actuallyDelete = True)
-
- # Create dictionary of registry types from toplevel <types> tags
- # and add 'name' attribute to each <type> tag (where missing)
- # based on its <name> element.
- #
# There is usually one <types> block; more are OK
# Required <type> attributes: 'name' or nested <name> tag contents
self.typedict = {}
@@ -654,16 +407,9 @@
# Replace the dictionary entry for the CmdInfo element
self.cmddict[name] = ci
- # @ newString = etree.tostring(base, encoding="unicode").replace(aliasValue, aliasName)
- # @elem.append(etree.fromstring(replacement))
- else:
- self.gen.logMsg('warn', 'No matching <command> found for command',
- cmd.get('name'), 'alias', alias)
-
# Create dictionaries of API and extension interfaces
# from toplevel <api> and <extension> tags.
self.apidict = {}
- format_condition = dict()
for feature in self.reg.findall('feature'):
featureInfo = FeatureInfo(feature)
self.addElementInfo(feature, featureInfo, 'feature', self.apidict)
@@ -687,36 +433,19 @@
addEnumInfo = False
groupName = enum.get('extends')
if groupName is not None:
- # self.gen.logMsg('diag', 'Found extension enum',
- # enum.get('name'))
# Add version number attribute to the <enum> element
enum.set('version', featureInfo.version)
# Look up the GroupInfo with matching groupName
if groupName in self.groupdict:
- # self.gen.logMsg('diag', 'Matching group',
- # groupName, 'found, adding element...')
gi = self.groupdict[groupName]
gi.elem.append(copy.deepcopy(enum))
- else:
- self.gen.logMsg('warn', 'NO matching group',
- groupName, 'for enum', enum.get('name'), 'found.')
- if groupName == "VkFormat":
- format_name = enum.get('name')
- if enum.get('alias'):
- format_name = enum.get('alias')
- format_condition[format_name] = featureInfo.name
addEnumInfo = True
elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
- # self.gen.logMsg('diag', 'Adding extension constant "enum"',
- # enum.get('name'))
addEnumInfo = True
if addEnumInfo:
enumInfo = EnumInfo(enum)
self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
- sync_pipeline_stage_condition = dict()
- sync_access_condition = dict()
-
self.extensions = self.reg.findall('extensions/extension')
self.extdict = {}
for feature in self.extensions:
@@ -734,8 +463,6 @@
addEnumInfo = False
groupName = enum.get('extends')
if groupName is not None:
- # self.gen.logMsg('diag', 'Found extension enum',
- # enum.get('name'))
# Add <extension> block's extension number attribute to
# the <enum> element unless specified explicitly, such
@@ -748,139 +475,22 @@
enum.set('supported', noneStr(featureInfo.supported))
# Look up the GroupInfo with matching groupName
if groupName in self.groupdict:
- # self.gen.logMsg('diag', 'Matching group',
- # groupName, 'found, adding element...')
gi = self.groupdict[groupName]
gi.elem.append(copy.deepcopy(enum))
- else:
- self.gen.logMsg('warn', 'NO matching group',
- groupName, 'for enum', enum.get('name'), 'found.')
- # This is Vulkan-specific
- if groupName == "VkFormat":
- format_name = enum.get('name')
- if enum.get('alias'):
- format_name = enum.get('alias')
- if format_name in format_condition:
- format_condition[format_name] += "," + featureInfo.name
- else:
- format_condition[format_name] = featureInfo.name
- elif groupName == "VkPipelineStageFlagBits2":
- stage_flag = enum.get('name')
- if enum.get('alias'):
- stage_flag = enum.get('alias')
- featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name
- if stage_flag in sync_pipeline_stage_condition:
- sync_pipeline_stage_condition[stage_flag] += "," + featureName
- else:
- sync_pipeline_stage_condition[stage_flag] = featureName
- elif groupName == "VkAccessFlagBits2":
- access_flag = enum.get('name')
- if enum.get('alias'):
- access_flag = enum.get('alias')
- featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name
- if access_flag in sync_access_condition:
- sync_access_condition[access_flag] += "," + featureName
- else:
- sync_access_condition[access_flag] = featureName
addEnumInfo = True
elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
- # self.gen.logMsg('diag', 'Adding extension constant "enum"',
- # enum.get('name'))
addEnumInfo = True
if addEnumInfo:
enumInfo = EnumInfo(enum)
self.addElementInfo(enum, enumInfo, 'enum', self.enumdict)
- # 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)
-
- for format in self.reg.findall('formats/format'):
- condition = None
- format_name = format.get('name')
- if format_name in format_condition:
- condition = format_condition[format_name]
- formatInfo = FormatInfo(format, condition)
- self.addElementInfo(format, formatInfo, 'format', self.formatsdict)
-
- for stage in self.reg.findall('sync/syncstage'):
- condition = None
- stage_flag = stage.get('name')
- if stage_flag in sync_pipeline_stage_condition:
- condition = sync_pipeline_stage_condition[stage_flag]
- syncInfo = SyncStageInfo(stage, condition)
- self.addElementInfo(stage, syncInfo, 'syncstage', self.syncstagedict)
-
- for access in self.reg.findall('sync/syncaccess'):
- condition = None
- access_flag = access.get('name')
- if access_flag in sync_access_condition:
- condition = sync_access_condition[access_flag]
- syncInfo = SyncAccessInfo(access, condition)
- self.addElementInfo(access, syncInfo, 'syncaccess', self.syncaccessdict)
-
- for pipeline in self.reg.findall('sync/syncpipeline'):
- syncInfo = SyncPipelineInfo(pipeline)
- self.addElementInfo(pipeline, syncInfo, 'syncpipeline', self.syncpipelinedict)
-
- def dumpReg(self, maxlen=120, filehandle=sys.stdout):
- """Dump all the dictionaries constructed from the Registry object.
-
- Diagnostic to dump the dictionaries to specified file handle (default stdout).
- Truncates type / enum / command elements to maxlen characters (default 120)"""
- write('***************************************', file=filehandle)
- write(' ** Dumping Registry contents **', file=filehandle)
- write('***************************************', file=filehandle)
- write('// Types', file=filehandle)
- for name in self.typedict:
- tobj = self.typedict[name]
- write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle)
- write('// Groups', file=filehandle)
- for name in self.groupdict:
- gobj = self.groupdict[name]
- write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle)
- write('// Enums', file=filehandle)
- for name in self.enumdict:
- eobj = self.enumdict[name]
- write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle)
- write('// Commands', file=filehandle)
- for name in self.cmddict:
- cobj = self.cmddict[name]
- write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle)
- write('// APIs', file=filehandle)
- for key in self.apidict:
- write(' API Version ', key, '->',
- etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle)
- write('// Extensions', file=filehandle)
- 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)
- write('// VkFormat', file=filehandle)
- for key in self.formatsdict:
- write(' VkFormat', key, '->',
- etree.tostring(self.formatsdict[key].elem)[0:maxlen], file=filehandle)
-
def markTypeRequired(self, typename, required):
"""Require (along with its dependencies) or remove (but not its dependencies) a type.
- typename - name of type
- required - boolean (to tag features as required or not)
"""
- self.gen.logMsg('diag', 'tagging type:', typename, '-> required =', required)
-
# Get TypeInfo object for <type> tag corresponding to typename
typeinfo = self.lookupElementInfo(typename, self.typedict)
if typeinfo is not None:
@@ -891,43 +501,31 @@
for attrib_name in ['requires', 'alias']:
depname = typeinfo.elem.get(attrib_name)
if depname:
- self.gen.logMsg('diag', 'Generating dependent type',
- depname, 'for', attrib_name, 'type', typename)
# Do not recurse on self-referential structures.
if typename != depname:
self.markTypeRequired(depname, required)
- else:
- self.gen.logMsg('diag', 'type', typename, 'is self-referential')
# Tag types used in defining this type (e.g. in nested
# <type> tags)
# Look for <type> in entire <command> tree,
# not just immediate children
for subtype in typeinfo.elem.findall('.//type'):
- self.gen.logMsg('diag', 'markRequired: type requires dependent <type>', subtype.text)
if typename != subtype.text:
self.markTypeRequired(subtype.text, required)
- else:
- self.gen.logMsg('diag', 'type', typename, 'is self-referential')
# Tag enums used in defining this type, for example in
# <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
for subenum in typeinfo.elem.findall('.//enum'):
- self.gen.logMsg('diag', 'markRequired: type requires dependent <enum>', subenum.text)
self.markEnumRequired(subenum.text, required)
# Tag type dependency in 'bitvalues' attributes as
# required. This ensures that the bit values for a flag
# are emitted
depType = typeinfo.elem.get('bitvalues')
if depType:
- self.gen.logMsg('diag', 'Generating bitflag type',
- depType, 'for type', typename)
self.markTypeRequired(depType, required)
group = self.lookupElementInfo(depType, self.groupdict)
if group is not None:
group.flagType = typeinfo
typeinfo.required = required
- elif '.h' not in typename:
- self.gen.logMsg('warn', 'type:', typename, 'IS NOT DEFINED')
def markEnumRequired(self, enumname, required):
"""Mark an enum as required or not.
@@ -935,7 +533,6 @@
- enumname - name of enum
- required - boolean (to tag features as required or not)"""
- self.gen.logMsg('diag', 'markEnumRequired: tagging enum:', enumname, '-> required =', required)
enum = self.lookupElementInfo(enumname, self.enumdict)
if enum is not None:
# If the enum is part of a group, and is being removed, then
@@ -945,7 +542,6 @@
if not required:
groupName = enum.elem.get('extends')
if groupName is not None:
- self.gen.logMsg('diag', f'markEnumRequired: Removing extending enum {enum.elem.get("name")}')
# Look up the Info with matching groupName
if groupName in self.groupdict:
@@ -954,23 +550,12 @@
if gienum is not None:
# Remove copy of this enum from the group
gi.elem.remove(gienum)
- else:
- self.gen.logMsg('warn', 'markEnumRequired: Cannot remove enum',
- enumname, 'not found in group',
- groupName)
- else:
- self.gen.logMsg('warn', 'markEnumRequired: Cannot remove enum',
- enumname, 'from nonexistent group',
- groupName)
else:
# This enum is not an extending enum.
# The XML tree must be searched for all <enums> that
# might have it, so we know the parent to delete from.
enumName = enum.elem.get('name')
-
- self.gen.logMsg('diag', f'markEnumRequired: Removing non-extending enum {enumName}')
-
count = 0
for enums in self.reg.findall('enums'):
for thisEnum in enums.findall('enum'):
@@ -979,45 +564,20 @@
count = count + 1
enums.remove(thisEnum)
- if count == 0:
- self.gen.logMsg('warn', f'markEnumRequired: {enumName}) not found in any <enums> tag')
-
enum.required = required
# Tag enum dependencies in 'alias' attribute as required
depname = enum.elem.get('alias')
if depname:
- self.gen.logMsg('diag', 'markEnumRequired: Generating dependent enum',
- depname, 'for alias', enumname, 'required =', enum.required)
self.markEnumRequired(depname, required)
- else:
- self.gen.logMsg('warn', f'markEnumRequired: {enumname} IS NOT DEFINED')
def markCmdRequired(self, cmdname, required):
"""Mark a command as required or not.
- cmdname - name of command
- required - boolean (to tag features as required or not)"""
- self.gen.logMsg('diag', 'tagging command:', cmdname, '-> required =', required)
cmd = self.lookupElementInfo(cmdname, self.cmddict)
if cmd is not None:
cmd.required = required
-
- # Tag command dependencies in 'alias' attribute as required
- #
- # This is usually not done, because command 'aliases' are not
- # actual C language aliases like type and enum aliases. Instead
- # they are just duplicates of the function signature of the
- # alias. This means that there is no dependency of a command
- # alias on what it aliases. One exception is validity includes,
- # where the spec markup needs the promoted-to validity include
- # even if only the promoted-from command is being built.
- if self.genOpts.requireCommandAliases:
- depname = cmd.elem.get('alias')
- if depname:
- self.gen.logMsg('diag', 'Generating dependent command',
- depname, 'for alias', cmdname)
- self.markCmdRequired(depname, required)
-
# Tag all parameter types of this command as required.
# This does not remove types of commands in a <remove>
# tag, because many other commands may use the same type.
@@ -1027,10 +587,7 @@
# Look for <type> in entire <command> tree,
# not just immediate children
for type_elem in cmd.elem.findall('.//type'):
- self.gen.logMsg('diag', 'markRequired: command implicitly requires dependent type', type_elem.text)
self.markTypeRequired(type_elem.text, required)
- else:
- self.gen.logMsg('warn', 'command:', cmdname, 'IS NOT DEFINED')
def markRequired(self, featurename, feature, required):
"""Require or remove features specified in the Element.
@@ -1038,8 +595,6 @@
- featurename - name of the feature
- feature - Element for `<require>` or `<remove>` tag
- required - boolean (to tag features as required or not)"""
- self.gen.logMsg('diag', 'markRequired (feature = <too long to print>, required =', required, ')')
-
# Loop over types, enums, and commands in the tag
# @@ It would be possible to respect 'api' and 'profile' attributes
# in individual features, but that is not done yet.
@@ -1051,68 +606,14 @@
for cmdElem in feature.findall('command'):
self.markCmdRequired(cmdElem.get('name'), required)
- # Extensions may need to extend existing commands or other items in the future.
- # So, look for extend tags.
- for extendElem in feature.findall('extend'):
- extendType = extendElem.get('type')
- if extendType == 'command':
- commandName = extendElem.get('name')
- successExtends = extendElem.get('successcodes')
- if successExtends is not None:
- for success in successExtends.split(','):
- self.commandextensionsuccesses.append(self.commandextensiontuple(command=commandName,
- value=success,
- extension=featurename))
- errorExtends = extendElem.get('errorcodes')
- if errorExtends is not None:
- for error in errorExtends.split(','):
- self.commandextensionerrors.append(self.commandextensiontuple(command=commandName,
- value=error,
- extension=featurename))
- else:
- self.gen.logMsg('warn', 'extend type:', extendType, 'IS NOT SUPPORTED')
-
- def getAlias(self, elem, dict):
- """Check for an alias in the same require block.
-
- - elem - Element to check for an alias"""
-
- # Try to find an alias
- alias = elem.get('alias')
- if alias is None:
- name = elem.get('name')
- typeinfo = self.lookupElementInfo(name, dict)
- if not typeinfo:
- self.gen.logMsg('error', name, 'is not a known name')
- alias = typeinfo.elem.get('alias')
-
- return alias
-
- def checkForCorrectionAliases(self, alias, require, tag):
- """Check for an alias in the same require block.
-
- - alias - String name of the alias
- - require - `<require>` block from the registry
- - tag - tag to look for in the require block"""
-
- # For the time being, the code below is bypassed. It has the effect
- # of excluding "spelling aliases" created to comply with the style
- # guide, but this leaves references out of the specification and
- # causes broken internal links.
- #
- # if alias and require.findall(tag + "[@name='" + alias + "']"):
- # return True
-
- return False
-
- def fillFeatureDictionary(self, interface, featurename, api, profile):
+ def fillFeatureDictionary(self, interface, featurename, api):
"""Capture added interfaces for a `<version>` or `<extension>`.
- interface - Element for `<version>` or `<extension>`, containing
`<require>` and `<remove>` tags
- featurename - name of the feature
- api - string specifying API name being generated
- - profile - string specifying API profile being generated"""
+ """
# Explicitly initialize known types - errors for unhandled categories
self.gen.featureDictionary[featurename] = {
@@ -1129,71 +630,7 @@
"funcpointer": {},
}
- # <require> marks things that are required by this version/profile
- for require in interface.findall('require'):
- if matchAPIProfile(api, profile, require):
-
- # Determine the required extension or version needed for a require block
- # Assumes that only one of these is specified
- # 'extension', and therefore 'required_key', may be a boolean
- # expression of extension names.
- # 'required_key' is used only as a dictionary key at
- # present, and passed through to the script generators, so
- # they must be prepared to parse that boolean expression.
- required_key = require.get('depends')
-
- # Loop over types, enums, and commands in the tag
- for typeElem in require.findall('type'):
- typename = typeElem.get('name')
- typeinfo = self.lookupElementInfo(typename, self.typedict)
-
- if typeinfo:
- # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
- alias = self.getAlias(typeElem, self.typedict)
- if not self.checkForCorrectionAliases(alias, require, 'type'):
- # Resolve the type info to the actual type, so we get an accurate read for 'structextends'
- while alias:
- typeinfo = self.lookupElementInfo(alias, self.typedict)
- alias = typeinfo.elem.get('alias')
-
- typecat = typeinfo.elem.get('category')
- typeextends = typeinfo.elem.get('structextends')
- if not required_key in self.gen.featureDictionary[featurename][typecat]:
- self.gen.featureDictionary[featurename][typecat][required_key] = {}
- if not typeextends in self.gen.featureDictionary[featurename][typecat][required_key]:
- self.gen.featureDictionary[featurename][typecat][required_key][typeextends] = []
- self.gen.featureDictionary[featurename][typecat][required_key][typeextends].append(typename)
- else:
- self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
-
-
- for enumElem in require.findall('enum'):
- enumname = enumElem.get('name')
- typeinfo = self.lookupElementInfo(enumname, self.enumdict)
-
- # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
- alias = self.getAlias(enumElem, self.enumdict)
- if not self.checkForCorrectionAliases(alias, require, 'enum'):
- enumextends = enumElem.get('extends')
- if not required_key in self.gen.featureDictionary[featurename]['enumconstant']:
- self.gen.featureDictionary[featurename]['enumconstant'][required_key] = {}
- if not enumextends in self.gen.featureDictionary[featurename]['enumconstant'][required_key]:
- self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends] = []
- self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends].append(enumname)
- else:
- self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
-
- for cmdElem in require.findall('command'):
- # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible.
- alias = self.getAlias(cmdElem, self.cmddict)
- if not self.checkForCorrectionAliases(alias, require, 'command'):
- if not required_key in self.gen.featureDictionary[featurename]['command']:
- self.gen.featureDictionary[featurename]['command'][required_key] = []
- self.gen.featureDictionary[featurename]['command'][required_key].append(cmdElem.get('name'))
- else:
- self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename))
-
- def requireFeatures(self, interface, featurename, api, profile):
+ def requireFeatures(self, interface, featurename, api):
"""Process `<require>` tags for a `<version>` or `<extension>`.
- interface - Element for `<version>` or `<extension>`, containing
@@ -1204,43 +641,9 @@
# <require> marks things that are required by this version/profile
for feature in interface.findall('require'):
- if matchAPIProfile(api, profile, feature):
+ if matchAPIProfile(api, feature):
self.markRequired(featurename, feature, True)
- def removeFeatures(self, interface, featurename, api, profile):
- """Process `<remove>` tags for a `<version>` or `<extension>`.
-
- - interface - Element for `<version>` or `<extension>`, containing
- `<remove>` tags
- - featurename - name of the feature
- - api - string specifying API name being generated
- - profile - string specifying API profile being generated"""
-
- # <remove> marks things that are removed by this version/profile
- for feature in interface.findall('remove'):
- if matchAPIProfile(api, profile, feature):
- self.markRequired(featurename, feature, False)
-
- def assignAdditionalValidity(self, interface, api, profile):
- # Loop over all usage inside all <require> tags.
- for feature in interface.findall('require'):
- if matchAPIProfile(api, profile, feature):
- for v in feature.findall('usage'):
- if v.get('command'):
- self.cmddict[v.get('command')].additionalValidity.append(copy.deepcopy(v))
- if v.get('struct'):
- self.typedict[v.get('struct')].additionalValidity.append(copy.deepcopy(v))
-
- def removeAdditionalValidity(self, interface, api, profile):
- # Loop over all usage inside all <remove> tags.
- for feature in interface.findall('remove'):
- if matchAPIProfile(api, profile, feature):
- for v in feature.findall('usage'):
- if v.get('command'):
- self.cmddict[v.get('command')].removedValidity.append(copy.deepcopy(v))
- if v.get('struct'):
- self.typedict[v.get('struct')].removedValidity.append(copy.deepcopy(v))
-
def generateFeature(self, fname, ftype, dictionary, explicit=False):
"""Generate a single type / enum group / enum / command,
and all its dependencies as needed.
@@ -1252,34 +655,21 @@
XML <require> tag, False if it is a dependency of an explicit
requirement."""
- self.gen.logMsg('diag', 'generateFeature: generating', ftype, fname)
-
- if not (explicit or self.genOpts.requireDepends):
- self.gen.logMsg('diag', 'generateFeature: NOT generating', ftype, fname, 'because generator does not require dependencies')
- return
-
f = self.lookupElementInfo(fname, dictionary)
if f is None:
- # No such feature. This is an error, but reported earlier
- self.gen.logMsg('diag', 'No entry found for feature', fname,
- 'returning!')
+ return
+
+ if not f.required:
return
# If feature is not required, or has already been declared, return
- if not f.required:
- self.gen.logMsg('diag', 'Skipping', ftype, fname, '(not required)')
- return
if f.declared:
- self.gen.logMsg('diag', 'Skipping', ftype, fname, '(already declared)')
return
# Always mark feature declared, as though actually emitted
f.declared = True
# Determine if this is an alias, and of what, if so
alias = f.elem.get('alias')
- if alias:
- self.gen.logMsg('diag', fname, 'is an alias of', alias)
-
# Pull in dependent declaration(s) of the feature.
# For types, there may be one type in the 'requires' attribute of
# the element, one in the 'alias' attribute, and many in
@@ -1297,8 +687,6 @@
self.generateFeature(alias, 'type', self.typedict)
requires = f.elem.get('requires')
if requires:
- self.gen.logMsg('diag', 'Generating required dependent type',
- requires)
self.generateFeature(requires, 'type', self.typedict)
# Generate types used in defining this type (e.g. in nested
@@ -1306,34 +694,23 @@
# Look for <type> in entire <command> tree,
# not just immediate children
for subtype in f.elem.findall('.//type'):
- self.gen.logMsg('diag', 'Generating required dependent <type>',
- subtype.text)
self.generateFeature(subtype.text, 'type', self.typedict)
# Generate enums used in defining this type, for example in
# <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member>
for subtype in f.elem.findall('.//enum'):
- self.gen.logMsg('diag', 'Generating required dependent <enum>',
- subtype.text)
self.generateFeature(subtype.text, 'enum', self.enumdict)
# If the type is an enum group, look up the corresponding
# group in the group dictionary and generate that instead.
if f.elem.get('category') == 'enum':
- self.gen.logMsg('diag', 'Type', fname, 'is an enum group, so generate that instead')
group = self.lookupElementInfo(fname, self.groupdict)
if alias is not None:
- # An alias of another group name.
- # Pass to genGroup with 'alias' parameter = aliased name
- self.gen.logMsg('diag', 'Generating alias', fname,
- 'for enumerated type', alias)
# Now, pass the *aliased* GroupInfo to the genGroup, but
# with an additional parameter which is the alias name.
genProc = self.gen.genGroup
f = self.lookupElementInfo(alias, self.groupdict)
elif group is None:
- self.gen.logMsg('warn', 'Skipping enum type', fname,
- ': No matching enumerant group')
return
else:
genProc = self.gen.genGroup
@@ -1351,9 +728,6 @@
# @ too.
enums = group.elem.findall('enum')
-
- self.gen.logMsg('diag', 'generateFeature: checking enums for group', fname)
-
# Check for required enums, including aliases
# LATER - Check for, report, and remove duplicates?
enumAliases = []
@@ -1368,7 +742,7 @@
# 'supported' attribute was injected when the <enum> element was
# moved into the <enums> group in Registry.parseTree()
supported_list = elem.get('supported').split(",")
- if self.genOpts.defaultExtensions in supported_list:
+ if 'vulkan' in supported_list:
required = True
elif re.match(self.genOpts.addExtensions, extname) is not None:
required = True
@@ -1377,7 +751,6 @@
else:
required = True
- self.gen.logMsg('diag', '* required =', required, 'for', name)
if required:
# Mark this element as required (in the element, not the EnumInfo)
elem.set('required', 'true')
@@ -1389,7 +762,6 @@
name = elem.get('name')
if name in enumAliases:
elem.set('required', 'true')
- self.gen.logMsg('diag', '* also need to require alias', name)
if f is None:
raise RuntimeError("Should not get here")
if f.elem.get('category') == 'bitmask':
@@ -1402,8 +774,6 @@
genProc = self.gen.genCmd
for type_elem in f.elem.findall('.//type'):
depname = type_elem.text
- self.gen.logMsg('diag', 'Generating required parameter type',
- depname)
self.generateFeature(depname, 'type', self.typedict)
elif ftype == 'enum':
# Generate enum dependencies in 'alias' attribute
@@ -1413,17 +783,11 @@
# Actually generate the type only if emitting declarations
if self.emitFeatures:
- self.gen.logMsg('diag', 'Emitting', ftype, 'decl for', fname)
if genProc is None:
raise RuntimeError("genProc is None when we should be emitting")
genProc(f, fname, alias)
- else:
- self.gen.logMsg('diag', 'Skipping', ftype, fname,
- '(should not be emitted)')
if followupFeature:
- self.gen.logMsg('diag', 'Generating required bitvalues <enum>',
- followupFeature)
self.generateFeature(followupFeature, "type", self.typedict)
def generateRequiredInterface(self, interface):
@@ -1445,122 +809,10 @@
for c in features.findall('command'):
self.generateFeature(c.get('name'), 'command', self.cmddict, explicit=True)
- 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 stripUnsupportedAPIs(self, dictionary, attribute, supportedDictionary):
- """Strip unsupported APIs from attributes of APIs.
- dictionary - *Info dictionary of APIs to be updated
- attribute - attribute name to look for in each API
- supportedDictionary - dictionary in which to look for supported
- API elements in the attribute"""
-
- for key in dictionary:
- eleminfo = dictionary[key]
- attribstring = eleminfo.elem.get(attribute)
- if attribstring is not None:
- apis = []
- stripped = False
- for api in attribstring.split(','):
- ##print('Checking API {} referenced by {}'.format(api, key))
- if api in supportedDictionary and supportedDictionary[api].required:
- apis.append(api)
- else:
- stripped = True
- ##print('\t**STRIPPING API {} from {}'.format(api, key))
-
- # Update the attribute after stripping stuff.
- # Could sort apis before joining, but it is not a clear win
- if stripped:
- eleminfo.elem.set(attribute, ','.join(apis))
-
- def stripUnsupportedAPIsFromList(self, dictionary, supportedDictionary):
- """Strip unsupported APIs from attributes of APIs.
- dictionary - dictionary of list of structure name strings
- supportedDictionary - dictionary in which to look for supported
- API elements in the attribute"""
-
- for key in dictionary:
- attribstring = dictionary[key]
- if attribstring is not None:
- apis = []
- stripped = False
- for api in attribstring:
- ##print('Checking API {} referenced by {}'.format(api, key))
- if supportedDictionary[api].required:
- apis.append(api)
- else:
- stripped = True
- ##print('\t**STRIPPING API {} from {}'.format(api, key))
-
- # Update the attribute after stripping stuff.
- # Could sort apis before joining, but it is not a clear win
- if stripped:
- dictionary[key] = apis
-
- def generateFormat(self, format, dictionary):
- if format is None:
- self.gen.logMsg('diag', 'No entry found for format element',
- 'returning!')
- return
-
- name = format.elem.get('name')
- # No known alias for VkFormat elements
- alias = None
- if format.emit:
- genProc = self.gen.genFormat
- genProc(format, name, alias)
-
- def generateSyncStage(self, sync):
- genProc = self.gen.genSyncStage
- genProc(sync)
-
- def generateSyncAccess(self, sync):
- genProc = self.gen.genSyncAccess
- genProc(sync)
-
- def generateSyncPipeline(self, sync):
- genProc = self.gen.genSyncPipeline
- genProc(sync)
-
- def tagValidExtensionStructs(self):
- """Construct a "validextensionstructs" list for parent structures
- based on "structextends" tags in child structures.
- Only do this for structures tagged as required."""
-
- for typeinfo in self.typedict.values():
- type_elem = typeinfo.elem
- if typeinfo.required and type_elem.get('category') == 'struct':
- struct_extends = type_elem.get('structextends')
- if struct_extends is not None:
- for parent in struct_extends.split(','):
- # self.gen.logMsg('diag', type_elem.get('name'), 'extends', parent)
- self.validextensionstructs[parent].append(type_elem.get('name'))
-
- # Sort the lists so they do not depend on the XML order
- for parent in self.validextensionstructs:
- self.validextensionstructs[parent].sort()
-
def apiGen(self):
"""Generate interface for specified versions using the current
generator and generator options"""
- self.gen.logMsg('diag', '*******************************************')
- self.gen.logMsg('diag', ' Registry.apiGen file:', self.genOpts.filename,
- 'api:', self.genOpts.apiname,
- 'profile:', self.genOpts.profile)
- self.gen.logMsg('diag', '*******************************************')
-
# Could reset required/declared flags for all features here.
# This has been removed as never used. The initial motivation was
# the idea of calling apiGen() repeatedly for different targets, but
@@ -1573,10 +825,7 @@
regVersions = re.compile(self.genOpts.versions)
regEmitVersions = re.compile(self.genOpts.emitversions)
regAddExtensions = re.compile(self.genOpts.addExtensions)
- regRemoveExtensions = re.compile(self.genOpts.removeExtensions)
regEmitExtensions = re.compile(self.genOpts.emitExtensions)
- regEmitSpirv = re.compile(self.genOpts.emitSpirv)
- regEmitFormats = re.compile(self.genOpts.emitFormats)
# Get all matching API feature names & add to list of FeatureInfo
# Note we used to select on feature version attributes, not names.
@@ -1585,7 +834,7 @@
for key in self.apidict:
fi = self.apidict[key]
api = fi.elem.get('api')
- if apiNameMatch(self.genOpts.apiname, api):
+ if apiNameMatch('vulkan', api):
apiMatch = True
if regVersions.match(fi.name):
# Matches API & version #s being generated. Mark for
@@ -1593,24 +842,6 @@
# @@ Could use 'declared' instead of 'emit'?
fi.emit = (regEmitVersions.match(fi.name) is not None)
features.append(fi)
- if not fi.emit:
- self.gen.logMsg('diag', 'NOT tagging feature api =', api,
- 'name =', fi.name, 'version =', fi.version,
- 'for emission (does not match emitversions pattern)')
- else:
- self.gen.logMsg('diag', 'Including feature api =', api,
- 'name =', fi.name, 'version =', fi.version,
- 'for emission (matches emitversions pattern)')
- else:
- self.gen.logMsg('diag', 'NOT including feature api =', api,
- 'name =', fi.name, 'version =', fi.version,
- '(does not match requested versions)')
- else:
- self.gen.logMsg('diag', 'NOT including feature api =', api,
- 'name =', fi.name,
- '(does not match requested API)')
- if not apiMatch:
- self.gen.logMsg('warn', 'No matching API versions found!')
# Get all matching extensions, in order by their extension number,
# and add to the list of features.
@@ -1624,10 +855,7 @@
# Include extension if defaultExtensions is not None and is
# exactly matched by the 'supported' attribute.
- if apiNameMatch(self.genOpts.defaultExtensions,
- ei.elem.get('supported')):
- self.gen.logMsg('diag', 'Including extension',
- extName, "(defaultExtensions matches the 'supported' attribute)")
+ if apiNameMatch('vulkan', ei.elem.get('supported')):
include = True
# Include additional extensions if the extension name matches
@@ -1636,60 +864,15 @@
# tagged appropriately in the registry.
# However, we still respect the 'supported' attribute.
if regAddExtensions.match(extName) is not None:
- 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)')
+ if not apiNameMatch('vulkan', ei.elem.get('supported')):
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 are tagged that
- # way in the registry.
- if regRemoveExtensions.match(extName) is not None:
- self.gen.logMsg('diag', 'Removing extension',
- extName, '(matches explicitly requested extensions to remove)')
- include = False
-
# If the extension is to be included, add it to the
# extension features list.
if include:
ei.emit = (regEmitExtensions.match(extName) is not None)
features.append(ei)
- if not ei.emit:
- self.gen.logMsg('diag', 'NOT tagging extension',
- extName,
- 'for emission (does not match emitextensions pattern)')
-
- # Hack - can be removed when validity generator goes away
- # (Jon) I am not sure what this does, or if it should
- # respect the ei.emit flag above.
- self.requiredextensions.append(extName)
- else:
- 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)
-
- formats = []
- for key in self.formatsdict:
- si = self.formatsdict[key]
- si.emit = (regEmitFormats.match(key) is not None)
- formats.append(si)
# Sort the features list, if a sort procedure is defined
if self.genOpts.sortProcedure:
@@ -1702,29 +885,9 @@
# If a profile other than 'None' is being generated, it must
# match the profile attribute (if any) of the <require> and
# <remove> tags.
- self.gen.logMsg('diag', 'PASS 1: TAG FEATURES')
for f in features:
- self.gen.logMsg('diag', 'PASS 1: Tagging required and features for', f.name)
- self.fillFeatureDictionary(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
- self.requireFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
- self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
-
- for f in features:
- self.gen.logMsg('diag', 'PASS 2: Tagging removed features for', f.name)
- self.removeFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
- self.removeAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
-
- # Now, strip references to APIs that are not required.
- # At present such references may occur in:
- # Structs in <type category="struct"> 'structextends' attributes
- # Enums in <command> 'successcodes' and 'errorcodes' attributes
- self.stripUnsupportedAPIs(self.typedict, 'structextends', self.typedict)
- self.stripUnsupportedAPIs(self.cmddict, 'successcodes', self.enumdict)
- self.stripUnsupportedAPIs(self.cmddict, 'errorcodes', self.enumdict)
- self.stripUnsupportedAPIsFromList(self.validextensionstructs, self.typedict)
-
- # Construct lists of valid extension structures
- self.tagValidExtensionStructs()
+ self.fillFeatureDictionary(f.elem, f.name, 'vulkan')
+ self.requireFeatures(f.elem, f.name, 'vulkan')
# @@May need to strip <spirvcapability> / <spirvextension> <enable>
# tags of these forms:
@@ -1736,44 +899,12 @@
# Pass 3: loop over specified API versions and extensions printing
# declarations for required things which have not already been
# generated.
- self.gen.logMsg('diag', 'PASS 3: GENERATE INTERFACES FOR FEATURES')
self.gen.beginFile(self.genOpts)
for f in features:
- self.gen.logMsg('diag', 'PASS 3: Generating interface for',
- f.name)
emit = self.emitFeatures = f.emit
- if not emit:
- self.gen.logMsg('diag', 'PASS 3: NOT declaring feature',
- f.elem.get('name'), 'because it is not tagged for emission')
# Generate the interface (or just tag its elements as having been
# emitted, if they have not been).
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)
- for s in formats:
- self.generateFormat(s, self.formatsdict)
- for s in self.syncstagedict:
- self.generateSyncStage(self.syncstagedict[s])
- for s in self.syncaccessdict:
- self.generateSyncAccess(self.syncaccessdict[s])
- for s in self.syncpipelinedict:
- self.generateSyncPipeline(self.syncpipelinedict[s])
self.gen.endFile()
-
- def apiReset(self):
- """Reset type/enum/command dictionaries before generating another API.
-
- Use between apiGen() calls to reset internal state."""
- for datatype in self.typedict:
- self.typedict[datatype].resetState()
- for enum in self.enumdict:
- self.enumdict[enum].resetState()
- for cmd in self.cmddict:
- self.cmddict[cmd].resetState()
- for cmd in self.apidict:
- self.apidict[cmd].resetState()
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/conventions.py b/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/conventions.py
deleted file mode 100644
index faca3a2..0000000
--- a/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/conventions.py
+++ /dev/null
@@ -1,454 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2023 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Base class for working-group-specific style conventions,
-# used in generation.
-
-from enum import Enum
-import abc
-import re
-
-# Type categories that respond "False" to isStructAlwaysValid
-# basetype is home to typedefs like ..Bool32
-CATEGORIES_REQUIRING_VALIDATION = set(('handle',
- 'enum',
- 'bitmask',
- 'basetype',
- None))
-
-# These are basic C types pulled in via openxr_platform_defines.h
-TYPES_KNOWN_ALWAYS_VALID = set(('char',
- 'float',
- 'int8_t', 'uint8_t',
- 'int16_t', 'uint16_t',
- 'int32_t', 'uint32_t',
- 'int64_t', 'uint64_t',
- 'size_t',
- 'intptr_t', 'uintptr_t',
- 'int',
- ))
-
-# Split an extension name into vendor ID and name portions
-EXT_NAME_DECOMPOSE_RE = re.compile(r'[A-Z]+_(?P<vendor>[A-Z]+)_(?P<name>[\w_]+)')
-
-# Match an API version name.
-# This could be refined further for specific APIs.
-API_VERSION_NAME_RE = re.compile(r'[A-Z]+_VERSION_[0-9]')
-
-
-class ProseListFormats(Enum):
- """A connective, possibly with a quantifier."""
- AND = 0
- EACH_AND = 1
- OR = 2
- ANY_OR = 3
-
- @classmethod
- def from_string(cls, s):
- if s == 'or':
- return cls.OR
- if s == 'and':
- return cls.AND
- raise RuntimeError("Unrecognized string connective: " + s)
-
- @property
- def connective(self):
- if self in (ProseListFormats.OR, ProseListFormats.ANY_OR):
- return 'or'
- return 'and'
-
- def quantifier(self, n):
- """Return the desired quantifier for a list of a given length."""
- if self == ProseListFormats.ANY_OR:
- if n > 1:
- return 'any of '
- elif self == ProseListFormats.EACH_AND:
- if n > 2:
- return 'each of '
- if n == 2:
- return 'both of '
- return ''
-
-
-class ConventionsBase(abc.ABC):
- """WG-specific conventions."""
-
- def __init__(self):
- self._command_prefix = None
- self._type_prefix = None
-
- def formatExtension(self, name):
- """Mark up an extension name as a link the spec."""
- return '`<<{}>>`'.format(name)
-
- @property
- @abc.abstractmethod
- def null(self):
- """Preferred spelling of NULL."""
- raise NotImplementedError
-
- def makeProseList(self, elements, fmt=ProseListFormats.AND, with_verb=False, *args, **kwargs):
- """Make a (comma-separated) list for use in prose.
-
- Adds a connective (by default, 'and')
- before the last element if there are more than 1.
-
- Adds the right one of "is" or "are" to the end if with_verb is true.
-
- Optionally adds a quantifier (like 'any') before a list of 2 or more,
- if specified by fmt.
-
- Override with a different method or different call to
- _implMakeProseList if you want to add a comma for two elements,
- or not use a serial comma.
- """
- return self._implMakeProseList(elements, fmt, with_verb, *args, **kwargs)
-
- @property
- def struct_macro(self):
- """Get the appropriate format macro for a structure.
-
- May override.
- """
- return 'slink:'
-
- @property
- def external_macro(self):
- """Get the appropriate format macro for an external type like uint32_t.
-
- May override.
- """
- return 'code:'
-
- @property
- @abc.abstractmethod
- def structtype_member_name(self):
- """Return name of the structure type member.
-
- Must implement.
- """
- raise NotImplementedError()
-
- @property
- @abc.abstractmethod
- def nextpointer_member_name(self):
- """Return name of the structure pointer chain member.
-
- Must implement.
- """
- raise NotImplementedError()
-
- @property
- @abc.abstractmethod
- def xml_api_name(self):
- """Return the name used in the default API XML registry for the default API"""
- raise NotImplementedError()
-
- @abc.abstractmethod
- def generate_structure_type_from_name(self, structname):
- """Generate a structure type name, like XR_TYPE_CREATE_INSTANCE_INFO.
-
- Must implement.
- """
- raise NotImplementedError()
-
- def makeStructName(self, name):
- """Prepend the appropriate format macro for a structure to a structure type name.
-
- Uses struct_macro, so just override that if you want to change behavior.
- """
- return self.struct_macro + name
-
- def makeExternalTypeName(self, name):
- """Prepend the appropriate format macro for an external type like uint32_t to a type name.
-
- Uses external_macro, so just override that if you want to change behavior.
- """
- return self.external_macro + name
-
- def _implMakeProseList(self, elements, fmt, with_verb, comma_for_two_elts=False, serial_comma=True):
- """Internal-use implementation to make a (comma-separated) list for use in prose.
-
- Adds a connective (by default, 'and')
- before the last element if there are more than 1,
- and only includes commas if there are more than 2
- (if comma_for_two_elts is False).
-
- Adds the right one of "is" or "are" to the end if with_verb is true.
-
- Optionally adds a quantifier (like 'any') before a list of 2 or more,
- if specified by fmt.
-
- Do not edit these defaults, override self.makeProseList().
- """
- assert(serial_comma) # did not implement what we did not need
- if isinstance(fmt, str):
- fmt = ProseListFormats.from_string(fmt)
-
- my_elts = list(elements)
- if len(my_elts) > 1:
- my_elts[-1] = '{} {}'.format(fmt.connective, my_elts[-1])
-
- if not comma_for_two_elts and len(my_elts) <= 2:
- prose = ' '.join(my_elts)
- else:
- prose = ', '.join(my_elts)
-
- quantifier = fmt.quantifier(len(my_elts))
-
- parts = [quantifier, prose]
-
- if with_verb:
- if len(my_elts) > 1:
- parts.append(' are')
- else:
- parts.append(' is')
- return ''.join(parts)
-
- @property
- @abc.abstractmethod
- def file_suffix(self):
- """Return suffix of generated Asciidoctor files"""
- raise NotImplementedError
-
- @abc.abstractmethod
- def api_name(self, spectype=None):
- """Return API or specification name for citations in ref pages.
-
- spectype is the spec this refpage is for.
- 'api' (the default value) is the main API Specification.
- If an unrecognized spectype is given, returns None.
-
- Must implement."""
- raise NotImplementedError
-
- def should_insert_may_alias_macro(self, genOpts):
- """Return true if we should insert a "may alias" macro in this file.
-
- Only used by OpenXR right now."""
- return False
-
- @property
- def command_prefix(self):
- """Return the expected prefix of commands/functions.
-
- Implemented in terms of api_prefix."""
- if not self._command_prefix:
- self._command_prefix = self.api_prefix[:].replace('_', '').lower()
- return self._command_prefix
-
- @property
- def type_prefix(self):
- """Return the expected prefix of type names.
-
- Implemented in terms of command_prefix (and in turn, api_prefix)."""
- if not self._type_prefix:
- self._type_prefix = ''.join(
- (self.command_prefix[0:1].upper(), self.command_prefix[1:]))
- return self._type_prefix
-
- @property
- @abc.abstractmethod
- def api_prefix(self):
- """Return API token prefix.
-
- Typically two uppercase letters followed by an underscore.
-
- Must implement."""
- raise NotImplementedError
-
- @property
- def api_version_prefix(self):
- """Return API core version token prefix.
-
- Implemented in terms of api_prefix.
-
- May override."""
- return self.api_prefix + 'VERSION_'
-
- @property
- def KHR_prefix(self):
- """Return extension name prefix for KHR extensions.
-
- Implemented in terms of api_prefix.
-
- May override."""
- return self.api_prefix + 'KHR_'
-
- @property
- def EXT_prefix(self):
- """Return extension name prefix for EXT extensions.
-
- Implemented in terms of api_prefix.
-
- May override."""
- return self.api_prefix + 'EXT_'
-
- def writeFeature(self, featureExtraProtect, filename):
- """Return True if OutputGenerator.endFeature should write this feature.
-
- Defaults to always True.
- Used in COutputGenerator.
-
- May override."""
- return True
-
- def requires_error_validation(self, return_type):
- """Return True if the return_type element is an API result code
- requiring error validation.
-
- Defaults to always False.
-
- May override."""
- return False
-
- @property
- def required_errors(self):
- """Return a list of required error codes for validation.
-
- Defaults to an empty list.
-
- May override."""
- return []
-
- def is_voidpointer_alias(self, tag, text, tail):
- """Return True if the declaration components (tag,text,tail) of an
- element represents a void * type.
-
- Defaults to a reasonable implementation.
-
- May override."""
- return tag == 'type' and text == 'void' and tail.startswith('*')
-
- def make_voidpointer_alias(self, tail):
- """Reformat a void * declaration to include the API alias macro.
-
- Defaults to a no-op.
-
- Must override if you actually want to use this feature in your project."""
- return tail
-
- def category_requires_validation(self, category):
- """Return True if the given type 'category' always requires validation.
-
- Defaults to a reasonable implementation.
-
- May override."""
- return category in CATEGORIES_REQUIRING_VALIDATION
-
- def type_always_valid(self, typename):
- """Return True if the given type name is always valid (never requires validation).
-
- This is for things like integers.
-
- Defaults to a reasonable implementation.
-
- May override."""
- return typename in TYPES_KNOWN_ALWAYS_VALID
-
- @property
- def should_skip_checking_codes(self):
- """Return True if more than the basic validation of return codes should
- be skipped for a command."""
-
- return False
-
- @property
- def generate_index_terms(self):
- """Return True if asiidoctor index terms should be generated as part
- of an API interface from the docgenerator."""
-
- return False
-
- @property
- def generate_enum_table(self):
- """Return True if asciidoctor tables describing enumerants in a
- group should be generated as part of group generation."""
- return False
-
- @property
- def generate_max_enum_in_docs(self):
- """Return True if MAX_ENUM tokens should be generated in
- documentation includes."""
- return False
-
- @abc.abstractmethod
- def extension_file_path(self, name):
- """Return file path to an extension appendix relative to a directory
- containing all such appendices.
- - name - extension name
-
- Must implement."""
- raise NotImplementedError
-
- def extension_include_string(self, name):
- """Return format string for include:: line for an extension appendix
- file.
- - name - extension name"""
-
- return 'include::{{appendices}}/{}[]'.format(
- self.extension_file_path(name))
-
- @property
- def provisional_extension_warning(self):
- """Return True if a warning should be included in extension
- appendices for provisional extensions."""
- return True
-
- @property
- def generated_include_path(self):
- """Return path relative to the generated reference pages, to the
- generated API include files."""
-
- return '{generated}'
-
- @property
- def include_extension_appendix_in_refpage(self):
- """Return True if generating extension refpages by embedding
- extension appendix content (default), False otherwise
- (OpenXR)."""
-
- return True
-
- def valid_flag_bit(self, bitpos):
- """Return True if bitpos is an allowed numeric bit position for
- an API flag.
-
- Behavior depends on the data type used for flags (which may be 32
- or 64 bits), and may depend on assumptions about compiler
- handling of sign bits in enumerated types, as well."""
- return True
-
- @property
- def duplicate_aliased_structs(self):
- """
- Should aliased structs have the original struct definition listed in the
- generated docs snippet?
- """
- return False
-
- @property
- def protectProtoComment(self):
- """Return True if generated #endif should have a comment matching
- the protection symbol used in the opening #ifdef/#ifndef."""
- return False
-
- @property
- def extra_refpage_headers(self):
- """Return any extra headers (preceding the title) for generated
- reference pages."""
- return ''
-
- @property
- def extra_refpage_body(self):
- """Return any extra text (following the title) for generated
- reference pages."""
- return ''
-
- def is_api_version_name(self, name):
- """Return True if name is an API version name."""
-
- return API_VERSION_NAME_RE.match(name) is not None
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/util.py b/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/util.py
deleted file mode 100644
index bf25845..0000000
--- a/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/util.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""Utility functions not closely tied to other spec_tools types."""
-# Copyright (c) 2018-2019 Collabora, Ltd.
-# Copyright 2013-2023 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-
-def getElemName(elem, default=None):
- """Get the name associated with an element, either a name child or name attribute."""
- name_elem = elem.find('name')
- if name_elem is not None:
- return name_elem.text
- # Fallback if there is no child.
- return elem.get('name', default)
-
-
-def getElemType(elem, default=None):
- """Get the type associated with an element, either a type child or type attribute."""
- type_elem = elem.find('type')
- if type_elem is not None:
- return type_elem.text
- # Fallback if there is no child.
- return elem.get('type', default)
-
-
-def findFirstWithPredicate(collection, pred):
- """Return the first element that satisfies the predicate, or None if none exist.
-
- NOTE: Some places where this is used might be better served by changing to a dictionary.
- """
- for elt in collection:
- if pred(elt):
- return elt
- return None
-
-
-def findNamedElem(elems, name):
- """Traverse a collection of elements with 'name' nodes or attributes, looking for and returning one with the right name.
-
- NOTE: Many places where this is used might be better served by changing to a dictionary.
- """
- return findFirstWithPredicate(elems, lambda elem: getElemName(elem) == name)
-
-
-def findTypedElem(elems, typename):
- """Traverse a collection of elements with 'type' nodes or attributes, looking for and returning one with the right typename.
-
- NOTE: Many places where this is used might be better served by changing to a dictionary.
- """
- return findFirstWithPredicate(elems, lambda elem: getElemType(elem) == typename)
-
-
-def findNamedObject(collection, name):
- """Traverse a collection of elements with 'name' attributes, looking for and returning one with the right name.
-
- NOTE: Many places where this is used might be better served by changing to a dictionary.
- """
- return findFirstWithPredicate(collection, lambda elt: elt.name == name)
diff --git a/codegen/vulkan/vulkan-docs-next/scripts/vkconventions.py b/codegen/vulkan/vulkan-docs-next/scripts/vkconventions.py
deleted file mode 100755
index b4e7966..0000000
--- a/codegen/vulkan/vulkan-docs-next/scripts/vkconventions.py
+++ /dev/null
@@ -1,298 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright 2013-2023 The Khronos Group Inc.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# Working-group-specific style conventions,
-# used in generation.
-
-import re
-import os
-
-from spec_tools.conventions import ConventionsBase
-
-# Modified from default implementation - see category_requires_validation() below
-CATEGORIES_REQUIRING_VALIDATION = set(('handle', 'enum', 'bitmask'))
-
-# Tokenize into "words" for structure types, approximately per spec "Implicit Valid Usage" section 2.7.2
-# This first set is for things we recognize explicitly as words,
-# as exceptions to the general regex.
-# Ideally these would be listed in the spec as exceptions, as OpenXR does.
-SPECIAL_WORDS = set((
- '16Bit', # VkPhysicalDevice16BitStorageFeatures
- '2D', # VkPhysicalDeviceImage2DViewOf3DFeaturesEXT
- '3D', # VkPhysicalDeviceImage2DViewOf3DFeaturesEXT
- '8Bit', # VkPhysicalDevice8BitStorageFeaturesKHR
- 'AABB', # VkGeometryAABBNV
- 'ASTC', # VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT
- 'D3D12', # VkD3D12FenceSubmitInfoKHR
- 'Float16', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
- 'ImagePipe', # VkImagePipeSurfaceCreateInfoFUCHSIA
- 'Int64', # VkPhysicalDeviceShaderAtomicInt64FeaturesKHR
- 'Int8', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
- 'MacOS', # VkMacOSSurfaceCreateInfoMVK
- 'RGBA10X6', # VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT
- 'Uint8', # VkPhysicalDeviceIndexTypeUint8FeaturesEXT
- 'Win32', # VkWin32SurfaceCreateInfoKHR
-))
-# A regex to match any of the SPECIAL_WORDS
-EXCEPTION_PATTERN = r'(?P<exception>{})'.format(
- '|'.join('(%s)' % re.escape(w) for w in SPECIAL_WORDS))
-MAIN_RE = re.compile(
- # the negative lookahead is to prevent the all-caps pattern from being too greedy.
- r'({}|([0-9]+)|([A-Z][a-z]+)|([A-Z][A-Z]*(?![a-z])))'.format(EXCEPTION_PATTERN))
-
-
-class VulkanConventions(ConventionsBase):
- @property
- def null(self):
- """Preferred spelling of NULL."""
- return '`NULL`'
-
- def formatExtension(self, name):
- """Mark up an extension name as a link the spec."""
- return '`apiext:{}`'.format(name)
-
- @property
- def struct_macro(self):
- """Get the appropriate format macro for a structure.
-
- Primarily affects generated valid usage statements.
- """
-
- return 'slink:'
-
- @property
- def constFlagBits(self):
- """Returns True if static const flag bits should be generated, False if an enumerated type should be generated."""
- return False
-
- @property
- def structtype_member_name(self):
- """Return name of the structure type member"""
- return 'sType'
-
- @property
- def nextpointer_member_name(self):
- """Return name of the structure pointer chain member"""
- return 'pNext'
-
- @property
- def valid_pointer_prefix(self):
- """Return prefix to pointers which must themselves be valid"""
- return 'valid'
-
- def is_structure_type_member(self, paramtype, paramname):
- """Determine if member type and name match the structure type member."""
- return paramtype == 'VkStructureType' and paramname == self.structtype_member_name
-
- def is_nextpointer_member(self, paramtype, paramname):
- """Determine if member type and name match the next pointer chain member."""
- return paramtype == 'void' and paramname == self.nextpointer_member_name
-
- 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):
- word = elem[0]
- if word == 'Vk':
- structure_type_parts.append('VK_STRUCTURE_TYPE')
- else:
- structure_type_parts.append(word.upper())
- 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'_VULKAN_SC_([0-9])([0-9])_',r'_VULKAN_SC_\1_\2_' ],
- [ r'_DIRECT_FB_', r'_DIRECTFB_' ],
- [ r'_VULKAN_SC_10', r'_VULKAN_SC_1_0' ],
-
- ]
-
- for subpat in subpats:
- name = re.sub(subpat[0], subpat[1], name)
- return name
-
- @property
- def warning_comment(self):
- """Return warning comment to be placed in header of generated Asciidoctor files"""
- return '// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry'
-
- @property
- def file_suffix(self):
- """Return suffix of generated Asciidoctor files"""
- return '.adoc'
-
- def api_name(self, spectype='api'):
- """Return API or specification name for citations in ref pages.ref
- pages should link to for
-
- spectype is the spec this refpage is for: 'api' is the Vulkan API
- Specification. Defaults to 'api'. If an unrecognized spectype is
- given, returns None.
- """
- if spectype == 'api' or spectype is None:
- return 'Vulkan'
- else:
- return None
-
- @property
- def api_prefix(self):
- """Return API token prefix"""
- return 'VK_'
-
- @property
- def write_contacts(self):
- """Return whether contact list should be written to extension appendices"""
- return True
-
- @property
- def write_refpage_include(self):
- """Return whether refpage include should be written to extension appendices"""
- return True
-
- @property
- def member_used_for_unique_vuid(self):
- """Return the member name used in the VUID-...-...-unique ID."""
- return self.structtype_member_name
-
- def is_externsync_command(self, protoname):
- """Returns True if the protoname element is an API command requiring
- external synchronization
- """
- return protoname is not None and 'vkCmd' in protoname
-
- def is_api_name(self, name):
- """Returns True if name is in the reserved API namespace.
- For Vulkan, these are names with a case-insensitive 'vk' prefix, or
- a 'PFN_vk' function pointer type prefix.
- """
- return name[0:2].lower() == 'vk' or name[0:6] == 'PFN_vk'
-
- def specURL(self, spectype='api'):
- """Return public registry URL which ref pages should link to for the
- current all-extensions HTML specification, so xrefs in the
- asciidoc source that are not to ref pages can link into it
- instead. N.b. this may need to change on a per-refpage basis if
- there are multiple documents involved.
- """
- return 'https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html'
-
- @property
- def xml_api_name(self):
- """Return the name used in the default API XML registry for the default API"""
- return 'vulkan'
-
- @property
- def registry_path(self):
- """Return relpath to the default API XML registry in this project."""
- return 'xml/vk.xml'
-
- @property
- def specification_path(self):
- """Return relpath to the Asciidoctor specification sources in this project."""
- return '{generated}/meta'
-
- @property
- def special_use_section_anchor(self):
- """Return asciidoctor anchor name in the API Specification of the
- section describing extension special uses in detail."""
- return 'extendingvulkan-compatibility-specialuse'
-
- @property
- def extension_index_prefixes(self):
- """Return a list of extension prefixes used to group extension refpages."""
- return ['VK_KHR', 'VK_EXT', 'VK']
-
- @property
- def unified_flag_refpages(self):
- """Return True if Flags/FlagBits refpages are unified, False if
- they are separate.
- """
- return False
-
- @property
- def spec_reflow_path(self):
- """Return the path to the spec source folder to reflow"""
- return os.getcwd()
-
- @property
- def spec_no_reflow_dirs(self):
- """Return a set of directories not to automatically descend into
- when reflowing spec text
- """
- return ('scripts', 'style')
-
- @property
- def zero(self):
- return '`0`'
-
- def category_requires_validation(self, category):
- """Return True if the given type 'category' always requires validation.
-
- Overridden because Vulkan does not require "valid" text for basetype
- in the spec right now."""
- return category in CATEGORIES_REQUIRING_VALIDATION
-
- @property
- def should_skip_checking_codes(self):
- """Return True if more than the basic validation of return codes should
- be skipped for a command.
-
- Vulkan mostly relies on the validation layers rather than API
- builtin error checking, so these checks are not appropriate.
-
- For example, passing in a VkFormat parameter will not potentially
- generate a VK_ERROR_FORMAT_NOT_SUPPORTED code."""
-
- return True
-
- def extension_file_path(self, name):
- """Return file path to an extension appendix relative to a directory
- containing all such appendices.
- - name - extension name"""
-
- return f'{name}{self.file_suffix}'
-
- def valid_flag_bit(self, bitpos):
- """Return True if bitpos is an allowed numeric bit position for
- an API flag bit.
-
- Vulkan uses 32 bit Vk*Flags types, and assumes C compilers may
- cause Vk*FlagBits values with bit 31 set to result in a 64 bit
- enumerated type, so disallows such flags."""
- return bitpos >= 0 and bitpos < 31
-
- @property
- def extra_refpage_headers(self):
- """Return any extra text to add to refpage headers."""
- return 'include::{config}/attribs.adoc[]'
-
- @property
- def extra_refpage_body(self):
- """Return any extra text (following the title) for generated
- reference pages."""
- return 'include::{generated}/specattribs.adoc[]'
-
-
-class VulkanSCConventions(VulkanConventions):
-
- def specURL(self, spectype='api'):
- """Return public registry URL which ref pages should link to for the
- current all-extensions HTML specification, so xrefs in the
- asciidoc source that are not to ref pages can link into it
- instead. N.b. this may need to change on a per-refpage basis if
- there are multiple documents involved.
- """
- return 'https://registry.khronos.org/vulkansc/specs/1.0-extensions/html/vkspec.html'
-
- @property
- def xml_api_name(self):
- """Return the name used in the default API XML registry for the default API"""
- return 'vulkansc'
-
diff --git a/host/vulkan/vulkan_gfxstream.h b/host/vulkan/vulkan_gfxstream.h
index a7ac22b..9cf4fe0 100644
--- a/host/vulkan/vulkan_gfxstream.h
+++ b/host/vulkan/vulkan_gfxstream.h
@@ -19,7 +19,6 @@
#endif
-
// VK_GOOGLE_gfxstream is a preprocessor guard. Do not pass it to API calls.
#define VK_GOOGLE_gfxstream 1
#define VK_GOOGLE_GFXSTREAM_SPEC_VERSION 0
@@ -71,7 +70,6 @@
typedef void (VKAPI_PTR *PFN_vkQueueSubmitAsync2GOOGLE)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence);
typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreGOOGLE)(VkDevice device, VkSemaphore semaphore, uint64_t syncId);
-#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkMapMemoryIntoAddressSpaceGOOGLE(
VkDevice device,
VkDeviceMemory memory,
@@ -233,7 +231,6 @@
VkDevice device,
VkSemaphore semaphore,
uint64_t syncId);
-#endif
#ifdef __cplusplus
}
diff --git a/scripts/print_gfx_logs/vulkan_printer.py b/scripts/print_gfx_logs/vulkan_printer.py
index c0b64e8..cd5a675 100644
--- a/scripts/print_gfx_logs/vulkan_printer.py
+++ b/scripts/print_gfx_logs/vulkan_printer.py
@@ -2072,6 +2072,15 @@
1000413001: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES",
1000413002: "VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS",
1000413003: "VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS",
+ 1000298000: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_SC_1_0_FEATURES",
+ 1000298001: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_SC_1_0_PROPERTIES",
+ 1000298002: "VK_STRUCTURE_TYPE_DEVICE_OBJECT_RESERVATION_CREATE_INFO",
+ 1000298003: "VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_RESERVATION_CREATE_INFO",
+ 1000298004: "VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_CONSUMPTION",
+ 1000298005: "VK_STRUCTURE_TYPE_PIPELINE_POOL_SIZE",
+ 1000298007: "VK_STRUCTURE_TYPE_FAULT_DATA",
+ 1000298008: "VK_STRUCTURE_TYPE_FAULT_CALLBACK_INFO",
+ 1000298010: "VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO",
1000001000: "VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR",
1000001001: "VK_STRUCTURE_TYPE_PRESENT_INFO_KHR",
1000060007: "VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR",
@@ -2235,6 +2244,7 @@
1000116004: "VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR",
1000116005: "VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR",
1000116006: "VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR",
+ 1000116007: "VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_RESERVATION_INFO_KHR",
1000119000: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR",
1000119001: "VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR",
1000119002: "VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR",
@@ -2703,6 +2713,7 @@
1000373001: "VK_STRUCTURE_TYPE_EXPORT_FENCE_SCI_SYNC_INFO_NV",
1000373002: "VK_STRUCTURE_TYPE_FENCE_GET_SCI_SYNC_INFO_NV",
1000373003: "VK_STRUCTURE_TYPE_SCI_SYNC_ATTRIBUTES_INFO_NV",
+ 1000489003: "VK_STRUCTURE_TYPE_DEVICE_SEMAPHORE_SCI_SYNC_POOL_RESERVATION_CREATE_INFO_NV",
1000490000: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV",
1000490001: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV",
1000492000: "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV",