use Zig build system

This commit is contained in:
LordMZTE 2023-04-03 17:22:46 +02:00
parent 63af1cf1ee
commit e44309e935
No known key found for this signature in database
GPG key ID: B64802DC33A64FF6
33 changed files with 22 additions and 116558 deletions

View file

@ -1,11 +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.
from vkconventions import VulkanConventions as APIConventions

View file

@ -1,511 +0,0 @@
#!/usr/bin/python3 -i
#
# Copyright 2013-2023 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
import os
import re
from generator import (GeneratorOptions,
MissingGeneratorOptionsConventionsError,
MissingGeneratorOptionsError, MissingRegistryError,
OutputGenerator, noneStr, regSortFeatures, write)
class CGeneratorOptions(GeneratorOptions):
"""CGeneratorOptions - subclass of GeneratorOptions.
Adds options used by COutputGenerator objects during C language header
generation."""
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.
Additional parameters beyond parent class:
- 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"""
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."""
# This is an ordered list of sections in the header file.
TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
'group', 'bitmask', 'funcpointer', 'struct']
ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 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:
for s in genOpts.prefixText:
write(s, file=self.outFile)
# C++ extern wrapper - after prefix lines so they can add includes.
self.newline()
write('#ifdef __cplusplus', file=self.outFile)
write('extern "C" {', file=self.outFile)
write('#endif', file=self.outFile)
self.newline()
def endFile(self):
# C-specific
# Finish C++ wrapper and multiple inclusion protection
if self.genOpts is None:
raise MissingGeneratorOptionsError()
self.newline()
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)
def beginFeature(self, interface, emit):
# Start processing in superclass
OutputGenerator.beginFeature(self, interface, emit)
# C-specific
# Accumulate includes, defines, types, enums, function pointer typedefs,
# end function prototypes separately for this feature. They are only
# printed in endFeature().
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
if self.emit:
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)
# 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)
self.newline()
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.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)
def appendSection(self, section, text):
"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)
self.feature_not_empty = True
def genType(self, typeinfo, name, alias):
"Generate type."
OutputGenerator.genType(self, typeinfo, name, alias)
typeElem = typeinfo.elem
# Vulkan:
# Determine the category of the type, and the type section to add
# its definition to.
# 'funcpointer' is added to the 'struct' section as a workaround for
# internal issue #877, since structures and function pointer types
# can have cross-dependencies.
category = typeElem.get('category')
if category == 'funcpointer':
section = 'struct'
else:
section = category
if category in ('struct', 'union'):
# If the type is a struct type, generate it using the
# special-purpose generator.
self.genStruct(typeinfo, name, alias)
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>")
if body:
# Add extra newline after multi-line entries.
if '\n' in body[0:-1]:
body += '\n'
self.appendSection(section, body)
def genProtectString(self, protect_str):
"""Generate protection string.
Protection strings are the strings defining the OS/Platform/Graphics
requirements for a given API command. When generating the
language header files, we need to make sure the items specific to a
graphics API or OS platform are properly wrapped in #ifs."""
protect_if_str = ''
protect_end_str = ''
if not protect_str:
return (protect_if_str, protect_end_str)
if ',' in protect_str:
protect_list = protect_str.split(',')
protect_defs = ('defined(%s)' % d for d in protect_list)
protect_def_str = ' && '.join(protect_defs)
protect_if_str = '#if %s\n' % protect_def_str
protect_end_str = '#endif // %s\n' % protect_def_str
else:
protect_if_str = '#ifdef %s\n' % protect_str
protect_end_str = '#endif // %s\n' % protect_str
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).
This is a special case of the <type> tag where the contents are
interpreted as a set of <member> tags instead of freeform C
C type declarations. The <member> tags are just like <param>
tags - they are a declaration of a struct or union member.
Only simple member declarations are supported (no nested
structs etc.)
If alias is not None, then this struct aliases another; just
generate a typedef of that alias."""
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
if self.genOpts is None:
raise MissingGeneratorOptionsError()
typeElem = typeinfo.elem
if alias:
body = 'typedef ' + alias + ' ' + typeName + ';\n'
else:
body = ''
(protect_begin, protect_end) = self.genProtectString(typeElem.get('protect'))
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)
for member in typeElem.findall('.//member'):
body += self.makeCParamDecl(member, targetLen + 4)
body += ';\n'
body += '} ' + typeName + ';\n'
if protect_end:
body += protect_end
self.appendSection('struct', body)
def genGroup(self, groupinfo, groupName, alias=None):
"""Generate groups (e.g. C "enum" type).
These are concatenated together with other types.
If alias is not None, it is the name of another group type
which aliases this type; just generate that alias."""
OutputGenerator.genGroup(self, groupinfo, groupName, alias)
groupElem = groupinfo.elem
# After either enumerated type or alias paths, add the declaration
# to the appropriate section for the group being defined.
if groupElem.get('type') == 'bitmask':
section = 'bitmask'
else:
section = 'group'
if alias:
# If the group name is aliased, just emit a typedef declaration
# 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).
<enum> tags may specify their values in several ways, but are usually
just integers."""
OutputGenerator.genEnum(self, enuminfo, name, alias)
body = self.buildConstantCDecl(enuminfo, name, alias)
self.appendSection('enum', body)
def genCmd(self, cmdinfo, name, alias):
"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;

File diff suppressed because it is too large Load diff

View file

@ -1,818 +0,0 @@
#!/usr/bin/python3
#
# Copyright 2013-2023 The Khronos Group 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__)))
from cgenerator import CGeneratorOptions, COutputGenerator
from docgenerator import DocGeneratorOptions, DocOutputGenerator
from extensionmetadocgenerator import (ExtensionMetaDocGeneratorOptions,
ExtensionMetaDocOutputGenerator)
from interfacedocgenerator import InterfaceDocGenerator
from generator import write
from spirvcapgenerator import SpirvCapabilityOutputGenerator
from hostsyncgenerator import HostSynchronizationOutputGenerator
from formatsgenerator import FormatsOutputGenerator
from pygenerator import PyOutputGenerator
from rubygenerator import RubyOutputGenerator
from reflib import logDiag, logWarn, logErr, setLogFile
from reg import Registry
from validitygenerator import ValidityOutputGenerator
from apiconventions import APIConventions
# Simple timer functions
startTime = None
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()
logDiag(msg, endTime - startTime)
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:
if not strings_are_regex:
strings = (re.escape(s) for s in strings)
return '^(' + '|'.join(strings) + ')$'
return default
def makeGenOpts(args):
"""Returns a directory of [ generator function, generator options ] indexed
by specified short names. The generator options incorporate the following
parameters:
args is an parsed argument object; see below for the fields that are used."""
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'.*'
# 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)
# Copyright text prefixing all headers (list of strings).
# The SPDX formatting below works around constraints of the 'reuse' tool
prefixStrings = [
'/*',
'** Copyright 2015-2023 The Khronos Group Inc.',
'**',
'** SPDX-License-Identifier' + ': Apache-2.0',
'*/',
''
]
# Text specific to Vulkan headers
vkPrefixStrings = [
'/*',
'** This header is generated from the Khronos Vulkan XML API Registry.',
'**',
'*/',
''
]
# 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
# API include files for spec and ref pages
# Overwrites include subdirectories in spec source tree
# The generated include files do not include the calling convention
# macros (apientry etc.), unlike the header files.
# Because the 1.0 core branch includes ref pages for extensions,
# all the extension interfaces need to be generated, even though
# none are used by the core spec itself.
genOpts['apiinc'] = [
DocOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = genpath,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
prefixText = prefixStrings + vkPrefixStrings,
apicall = '',
apientry = '',
apientryp = '*',
alignFuncParam = 48,
expandEnumerants = False)
]
# Python and Ruby representations of API information, used by scripts
# that do not need to load the full XML.
genOpts['apimap.py'] = [
PyOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'apimap.py',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
reparentEnums = False)
]
genOpts['apimap.rb'] = [
RubyOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'apimap.rb',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
reparentEnums = False)
]
# API validity files for spec
#
# requireCommandAliases is set to True because we need validity files
# for the command something is promoted to even when the promoted-to
# feature is not included. This avoids wordy includes of validity files.
genOpts['validinc'] = [
ValidityOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
requireCommandAliases = True,
)
]
# API host sync table files for spec
genOpts['hostsyncinc'] = [
HostSynchronizationOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
reparentEnums = False)
]
# Extension metainformation for spec extension appendices
# Includes all extensions by default, but only so that the generated
# 'promoted_extensions_*' files refer to all extensions that were
# promoted to a core version.
genOpts['extinc'] = [
ExtensionMetaDocOutputGenerator,
ExtensionMetaDocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = None,
defaultExtensions = defaultExtensions,
addExtensions = addExtensionsPat,
removeExtensions = None,
emitExtensions = emitExtensionsPat)
]
# Version and extension interface docs for version/extension appendices
# Includes all extensions by default.
genOpts['interfaceinc'] = [
InterfaceDocGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
reparentEnums = False)
]
genOpts['spirvcapinc'] = [
SpirvCapabilityOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
emitSpirv = emitSpirvPat,
reparentEnums = False)
]
# Used to generate various format chapter tables
genOpts['formatsinc'] = [
FormatsOutputGenerator,
DocGeneratorOptions(
conventions = conventions,
filename = 'timeMarker',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = None,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
emitFormats = emitFormatsPat,
reparentEnums = False)
]
# 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',
]
betaSuppressExtensions = [
'VK_KHR_video_queue',
'VK_EXT_opacity_micromap',
]
platforms = [
[ 'vulkan_android.h', [ 'VK_KHR_android_surface',
'VK_ANDROID_external_memory_android_hardware_buffer'
], 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' ], 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,
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,
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)
]
# Unused - vulkan10.h target.
# It is possible to generate a header with just the Vulkan 1.0 +
# extension interfaces defined, but since the promoted KHR extensions
# are now defined in terms of the 1.1 interfaces, such a header is very
# similar to vulkan_core.h.
genOpts['vulkan10.h'] = [
COutputGenerator,
CGeneratorOptions(
conventions = conventions,
filename = 'vulkan10.h',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = 'VK_VERSION_1_0',
emitversions = 'VK_VERSION_1_0',
defaultExtensions = None,
addExtensions = None,
removeExtensions = None,
emitExtensions = None,
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)
]
# Video header target - combines all video extension dependencies into a
# single header, at present.
genOpts['vk_video.h'] = [
COutputGenerator,
CGeneratorOptions(
conventions = conventions,
filename = 'vk_video.h',
directory = directory,
genpath = None,
apiname = 'vulkan',
profile = None,
versions = None,
emitversions = None,
defaultExtensions = defaultExtensions,
addExtensions = addExtensionsPat,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
prefixText = prefixStrings + vkPrefixStrings,
genFuncPointers = True,
protectFile = protectFile,
protectFeature = False,
protectProto = '#ifndef',
protectProtoStr = 'VK_NO_PROTOTYPES',
apicall = '',
apientry = '',
apientryp = '',
alignFuncParam = 48,
misracstyle = misracstyle,
misracppstyle = misracppstyle)
]
# Video extension 'Std' interfaces, each in its own header files
# These are not Vulkan extensions, or a part of the Vulkan API at all,
# but are treated in a similar fashion for generation purposes.
#
# Each element of the videoStd[] array is an extension name defining an
# interface, and is also the basis for the generated header file name.
videoStd = [
'vulkan_video_codecs_common',
'vulkan_video_codec_h264std',
'vulkan_video_codec_h264std_decode',
'vulkan_video_codec_h264std_encode',
'vulkan_video_codec_h265std',
'vulkan_video_codec_h265std_decode',
'vulkan_video_codec_h265std_encode',
]
addExtensionRE = makeREstring(videoStd)
for codec in videoStd:
headername = f'{codec}.h'
# Consider all of the codecs 'extensions', but only emit this one
emitExtensionRE = makeREstring([codec])
opts = CGeneratorOptions(
conventions = conventions,
filename = headername,
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = None,
emitversions = None,
defaultExtensions = None,
addExtensions = addExtensionRE,
removeExtensions = None,
emitExtensions = emitExtensionRE,
prefixText = prefixStrings + vkPrefixStrings,
genFuncPointers = False,
protectFile = protectFile,
protectFeature = False,
alignFuncParam = 48,
)
genOpts[headername] = [ COutputGenerator, opts ]
# Unused - vulkan11.h target.
# It is possible to generate a header with just the Vulkan 1.0 +
# extension interfaces defined, but since the promoted KHR extensions
# are now defined in terms of the 1.1 interfaces, such a header is very
# similar to vulkan_core.h.
genOpts['vulkan11.h'] = [
COutputGenerator,
CGeneratorOptions(
conventions = conventions,
filename = 'vulkan11.h',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = '^VK_VERSION_1_[01]$',
emitversions = '^VK_VERSION_1_[01]$',
defaultExtensions = None,
addExtensions = None,
removeExtensions = None,
emitExtensions = None,
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['alias.h'] = [
COutputGenerator,
CGeneratorOptions(
conventions = conventions,
filename = 'alias.h',
directory = directory,
genpath = None,
apiname = defaultAPIName,
profile = None,
versions = featuresPat,
emitversions = featuresPat,
defaultExtensions = defaultExtensions,
addExtensions = None,
removeExtensions = removeExtensionsPat,
emitExtensions = emitExtensionsPat,
prefixText = None,
genFuncPointers = False,
protectFile = False,
protectFeature = False,
protectProto = '',
protectProtoStr = '',
apicall = '',
apientry = '',
apientryp = '',
alignFuncParam = 36)
]
def genTarget(args):
"""Create an API generator and corresponding generator options based on
the requested target and command line options.
This is encapsulated in a function so it can be profiled and/or timed.
The args parameter is an parsed argument object containing the following
fields that are used:
- 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
makeGenOpts(args)
# Select a generator matching the requested target
if args.target in genOpts:
createGenerator = genOpts[args.target][0]
options = genOpts[args.target][1]
logDiag('* Building', options.filename)
logDiag('* options.versions =', options.versions)
logDiag('* options.emitversions =', options.emitversions)
logDiag('* options.defaultExtensions =', options.defaultExtensions)
logDiag('* options.addExtensions =', options.addExtensions)
logDiag('* options.removeExtensions =', options.removeExtensions)
logDiag('* options.emitExtensions =', options.emitExtensions)
logDiag('* options.emitSpirv =', options.emitSpirv)
logDiag('* options.emitFormats =', options.emitFormats)
gen = createGenerator(errFile=errWarn,
warnFile=errWarn,
diagFile=diag)
return (gen, options)
else:
logErr('No generator options for unknown target:', args.target)
return None
# -feature name
# -extension name
# For both, "name" may be a single name, or a space-separated list
# 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('-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('-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('-misracstyle', dest='misracstyle', action='store_true',
help='generate MISRA C-friendly headers')
parser.add_argument('-misracppstyle', dest='misracppstyle', action='store_true',
help='generate MISRA C++-friendly headers')
args = parser.parse_args()
# 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
if args.time:
# Log diagnostics and warnings
setLogFile(setDiag = True, setWarn = True, filename = '-')
# Create the API generator & generator options
(gen, options) = genTarget(args)
# Create the registry object with the specified generator and generator
# options. The options are set before XML loading as they may affect it.
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 =')
# Load the XML tree into the registry object
startTimer(args.time)
reg.loadElementTree(tree)
endTimer(args.time, '* Time to parse ElementTree =')
if args.dump:
logDiag('* Dumping registry to regdump.txt')
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 ' + options.filename + ' =')
if not args.quiet:
logDiag('* Generated', options.filename)

View file

@ -1,354 +0,0 @@
#!/usr/bin/python3
# Copyright 2022-2023 The Khronos Group Inc.
# Copyright 2003-2019 Paul McGuire
# SPDX-License-Identifier: MIT
# apirequirements.py - parse 'depends' expressions in API XML
# Supported methods:
# dependency - the expression string
#
# evaluateDependency(dependency, isSupported) evaluates the expression,
# returning a boolean result. isSupported takes an extension or version name
# string and returns a boolean.
#
# dependencyLanguage(dependency) returns an English string equivalent
# to the expression, suitable for header file comments.
#
# dependencyNames(dependency) returns a set of the extension and
# version names in the expression.
#
# dependencyMarkup(dependency) returns a string containing asciidoctor
# markup for English equivalent to the expression, suitable for extension
# appendices.
#
# All may throw a ParseException if the expression cannot be parsed or is
# not completely consumed by parsing.
# Supported expressions at present:
# - extension names
# - '+' as AND connector
# - ',' as OR connector
# - parenthesization for grouping
# Based on https://github.com/pyparsing/pyparsing/blob/master/examples/fourFn.py
from pyparsing import (
Literal,
Word,
Group,
Forward,
alphas,
alphanums,
Regex,
ParseException,
CaselessKeyword,
Suppress,
delimitedList,
infixNotation,
)
import math
import operator
import pyparsing as pp
import re
def nameMarkup(name):
"""Returns asciidoc markup to generate a link to an API version or
extension anchor.
- name - version or extension name"""
# Could use ApiConventions.is_api_version_name, but that does not split
# out the major/minor version numbers.
match = re.search("[A-Z]+_VERSION_([0-9]+)_([0-9]+)", name)
if match is not None:
major = match.group(1)
minor = match.group(2)
version = major + '.' + minor
return f'<<versions-{major}.{minor}, Version {version}>>'
else:
return 'apiext:' + name
exprStack = []
def push_first(toks):
"""Push a token on the global stack
- toks - first element is the token to push"""
exprStack.append(toks[0])
# An identifier (version or extension name)
dependencyIdent = Word(alphanums + '_')
# Infix expression for depends expressions
dependencyExpr = pp.infixNotation(dependencyIdent,
[ (pp.oneOf(', +'), 2, pp.opAssoc.LEFT), ])
# BNF grammar for depends expressions
_bnf = None
def dependencyBNF():
"""
boolop :: '+' | ','
extname :: Char(alphas)
atom :: extname | '(' expr ')'
expr :: atom [ boolop atom ]*
"""
global _bnf
if _bnf is None:
and_, or_ = map(Literal, '+,')
lpar, rpar = map(Suppress, '()')
boolop = and_ | or_
expr = Forward()
expr_list = delimitedList(Group(expr))
atom = (
boolop[...]
+ (
(dependencyIdent).setParseAction(push_first)
| Group(lpar + expr + rpar)
)
)
expr <<= atom + (boolop + atom).setParseAction(push_first)[...]
_bnf = expr
return _bnf
# map operator symbols to corresponding arithmetic operations
_opn = {
'+': operator.and_,
',': operator.or_,
}
# map operator symbols to corresponding words
_opname = {
'+': 'and',
',': 'or',
}
def evaluateStack(stack, isSupported):
"""Evaluate an expression stack, returning a boolean result.
- stack - the stack
- isSupported - function taking a version or extension name string and
returning True or False if that name is supported or not."""
op, num_args = stack.pop(), 0
if isinstance(op, tuple):
op, num_args = op
if op in '+,':
# Note: operands are pushed onto the stack in reverse order
op2 = evaluateStack(stack, isSupported)
op1 = evaluateStack(stack, isSupported)
return _opn[op](op1, op2)
elif op[0].isalpha():
return isSupported(op)
else:
raise Exception(f'invalid op: {op}')
def evaluateDependency(dependency, isSupported):
"""Evaluate a dependency expression, returning a boolean result.
- dependency - the expression
- isSupported - function taking a version or extension name string and
returning True or False if that name is supported or not."""
global exprStack
exprStack = []
results = dependencyBNF().parseString(dependency, parseAll=True)
val = evaluateStack(exprStack[:], isSupported)
return val
def evalDependencyLanguage(stack, specmacros):
"""Evaluate an expression stack, returning an English equivalent
- stack - the stack
- specmacros - if True, prepare the language for spec inclusion"""
op, num_args = stack.pop(), 0
if isinstance(op, tuple):
op, num_args = op
if op in '+,':
# Could parenthesize, not needed yet
rhs = evalDependencyLanguage(stack, specmacros)
return evalDependencyLanguage(stack, specmacros) + f' {_opname[op]} ' + rhs
elif op[0].isalpha():
# This is an extension or feature name
if specmacros:
return nameMarkup(op)
else:
return op
else:
raise Exception(f'invalid op: {op}')
def dependencyLanguage(dependency, specmacros = False):
"""Return an API dependency expression translated to a form suitable for
asciidoctor conditionals or header file comments.
- dependency - the expression
- specmacros - if False, return a string that can be used as an
asciidoctor conditional.
If True, return a string suitable for spec inclusion with macros and
xrefs included."""
global exprStack
exprStack = []
results = dependencyBNF().parseString(dependency, parseAll=True)
return evalDependencyLanguage(exprStack, specmacros)
def evalDependencyNames(stack):
"""Evaluate an expression stack, returning the set of extension and
feature names used in the expression.
- stack - the stack"""
op, num_args = stack.pop(), 0
if isinstance(op, tuple):
op, num_args = op
if op in '+,':
# Do not evaluate the operation. We only care about the names.
return evalDependencyNames(stack) | evalDependencyNames(stack)
elif op[0].isalpha():
return { op }
else:
raise Exception(f'invalid op: {op}')
def dependencyNames(dependency):
"""Return a set of the extension and version names in an API dependency
expression. Used when determining transitive dependencies for spec
generation with specific extensions included.
- dependency - the expression"""
global exprStack
exprStack = []
results = dependencyBNF().parseString(dependency, parseAll=True)
# print(f'names(): stack = {exprStack}')
return evalDependencyNames(exprStack)
def markupTraverse(expr, level = 0, root = True):
"""Recursively process a dependency in infix form, transforming it into
asciidoctor markup with expression nesting indicated by indentation
level.
- expr - expression to process
- level - indentation level to render expression at
- root - True only on initial call"""
if level > 0:
prefix = '{nbsp}{nbsp}' * level * 2 + ' '
else:
prefix = ''
str = ''
for elem in expr:
if isinstance(elem, pp.ParseResults):
if not root:
nextlevel = level + 1
else:
# Do not indent the outer expression
nextlevel = level
str = str + markupTraverse(elem, level = nextlevel, root = False)
elif elem in ('+', ','):
str = str + f'{prefix}{_opname[elem]} +\n'
else:
str = str + f'{prefix}{nameMarkup(elem)} +\n'
return str
def dependencyMarkup(dependency):
"""Return asciidoctor markup for a human-readable equivalent of an API
dependency expression, suitable for use in extension appendix
metadata.
- dependency - the expression"""
parsed = dependencyExpr.parseString(dependency)
return markupTraverse(parsed)
if __name__ == "__main__":
termdict = {
'VK_VERSION_1_1' : True,
'false' : False,
'true' : True,
}
termSupported = lambda name: name in termdict and termdict[name]
def test(dependency, expected):
val = False
try:
val = evaluateDependency(dependency, termSupported)
except ParseException as pe:
print(dependency, f'failed parse: {dependency}')
except Exception as e:
print(dependency, f'failed eval: {dependency}')
if val == expected:
print(f'{dependency} = {val} (as expected)')
else:
print(f'{dependency} ERROR: {val} != {expected}')
# Verify expressions are evaluated left-to-right
test('false,false+false', False)
test('false,false+true', False)
test('false,true+false', False)
test('false,true+true', True)
test('true,false+false', False)
test('true,false+true', True)
test('true,true+false', False)
test('true,true+true', True)
test('false,(false+false)', False)
test('false,(false+true)', False)
test('false,(true+false)', False)
test('false,(true+true)', True)
test('true,(false+false)', True)
test('true,(false+true)', True)
test('true,(true+false)', True)
test('true,(true+true)', True)
test('false+false,false', False)
test('false+false,true', True)
test('false+true,false', False)
test('false+true,true', True)
test('true+false,false', False)
test('true+false,true', True)
test('true+true,false', True)
test('true+true,true', True)
test('false+(false,false)', False)
test('false+(false,true)', False)
test('false+(true,false)', False)
test('false+(true,true)', False)
test('true+(false,false)', False)
test('true+(false,true)', True)
test('true+(true,false)', True)
test('true+(true,true)', True)
#test('VK_VERSION_1_1+(false,true)', True)
#test('true', True)
#test('(true)', True)
#test('false,false', False)
#test('false,true', True)
#test('false+true', False)
#test('true+true', True)
# Check formatting
for dependency in [
#'true',
#'true+true+false',
'true+(true+false),(false,true)',
'true+((true+false),(false,true))',
#'VK_VERSION_1_1+(true,false)',
]:
print(f'expr = {dependency}\n{dependencyMarkup(dependency)}')
print(f' language = {dependencyLanguage(dependency)}')
print(f' names = {dependencyNames(dependency)}')
print(f' value = {evaluateDependency(dependency, termSupported)}')

View file

@ -1,381 +0,0 @@
{
"$schema": "https://schema.khronos.org/vulkan/profiles-0.8.1-204.json#",
"capabilities": {
"vulkan10requirements": {
"features": {
"VkPhysicalDeviceFeatures": {
"robustBufferAccess": true
}
}
},
"vulkan10requirements_roadmap2022": {
"features": {
"VkPhysicalDeviceFeatures": {
"fullDrawIndexUint32": true,
"imageCubeArray": true,
"independentBlend": true,
"sampleRateShading": true,
"drawIndirectFirstInstance": true,
"depthClamp": true,
"depthBiasClamp": true,
"samplerAnisotropy": true,
"occlusionQueryPrecise": true,
"fragmentStoresAndAtomics": true,
"shaderStorageImageExtendedFormats": true,
"shaderUniformBufferArrayDynamicIndexing": true,
"shaderSampledImageArrayDynamicIndexing": true,
"shaderStorageBufferArrayDynamicIndexing": true,
"shaderStorageImageArrayDynamicIndexing": true
}
},
"properties": {
"VkPhysicalDeviceProperties": {
"limits": {
"maxImageDimension1D": 8192,
"maxImageDimension2D": 8192,
"maxImageDimensionCube": 8192,
"maxImageArrayLayers": 2048,
"maxUniformBufferRange": 65536,
"bufferImageGranularity": 4096,
"maxPerStageDescriptorSamplers": 64,
"maxPerStageDescriptorUniformBuffers": 15,
"maxPerStageDescriptorStorageBuffers": 30,
"maxPerStageDescriptorSampledImages": 200,
"maxPerStageDescriptorStorageImages": 16,
"maxPerStageResources": 200,
"maxDescriptorSetSamplers": 576,
"maxDescriptorSetUniformBuffers": 90,
"maxDescriptorSetStorageBuffers": 96,
"maxDescriptorSetSampledImages": 1800,
"maxDescriptorSetStorageImages": 144,
"maxFragmentCombinedOutputResources": 16,
"maxComputeWorkGroupInvocations": 256,
"maxComputeWorkGroupSize": [ 256, 256, 64 ],
"subTexelPrecisionBits": 8,
"mipmapPrecisionBits": 6,
"maxSamplerLodBias": 14,
"standardSampleLocations": true,
"maxColorAttachments": 7
}
}
}
},
"vulkan10optionals_roadmap2022": {
"features": {
"VkPhysicalDeviceFeatures": {
"largePoints": true,
"wideLines": true
}
},
"properties": {
"VkPhysicalDeviceProperties": {
"limits": {
"pointSizeGranularity": 0.125,
"lineWidthGranularity": 0.5
}
}
}
},
"vulkan11requirements": {
"features": {
"VkPhysicalDeviceVulkan11Features": {
"multiview": true
}
},
"properties": {
"VkPhysicalDeviceVulkan11Properties": {
"maxMultiviewViewCount": 6,
"maxMultiviewInstanceIndex": 134217727
}
}
},
"vulkan11requirements_roadmap2022": {
"features": {
"VkPhysicalDeviceVulkan11Features": {
"samplerYcbcrConversion": true
}
},
"properties": {
"VkPhysicalDeviceVulkan11Properties": {
"subgroupSize": 4,
"subgroupSupportedStages": [ "VK_SHADER_STAGE_COMPUTE_BIT", "VK_SHADER_STAGE_FRAGMENT_BIT" ],
"subgroupSupportedOperations": [ "VK_SUBGROUP_FEATURE_BASIC_BIT", "VK_SUBGROUP_FEATURE_VOTE_BIT", "VK_SUBGROUP_FEATURE_ARITHMETIC_BIT", "VK_SUBGROUP_FEATURE_BALLOT_BIT", "VK_SUBGROUP_FEATURE_SHUFFLE_BIT", "VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT", "VK_SUBGROUP_FEATURE_QUAD_BIT" ]
}
}
},
"vulkan12requirements": {
"features": {
"VkPhysicalDeviceVulkan12Features": {
"uniformBufferStandardLayout": true,
"subgroupBroadcastDynamicId": true,
"imagelessFramebuffer": true,
"separateDepthStencilLayouts": true,
"hostQueryReset": true,
"timelineSemaphore": true,
"shaderSubgroupExtendedTypes": true
}
},
"properties": {
"VkPhysicalDeviceVulkan12Properties": {
"maxTimelineSemaphoreValueDifference": 2147483647
}
}
},
"vulkan12requirements_roadmap2022": {
"features": {
"VkPhysicalDeviceVulkan12Features": {
"samplerMirrorClampToEdge": true,
"descriptorIndexing": true,
"shaderUniformTexelBufferArrayDynamicIndexing": true,
"shaderStorageTexelBufferArrayDynamicIndexing": true,
"shaderUniformBufferArrayNonUniformIndexing": true,
"shaderSampledImageArrayNonUniformIndexing": true,
"shaderStorageBufferArrayNonUniformIndexing": true,
"shaderStorageImageArrayNonUniformIndexing": true,
"shaderUniformTexelBufferArrayNonUniformIndexing": true,
"shaderStorageTexelBufferArrayNonUniformIndexing": true,
"descriptorBindingSampledImageUpdateAfterBind": true,
"descriptorBindingStorageImageUpdateAfterBind": true,
"descriptorBindingStorageBufferUpdateAfterBind": true,
"descriptorBindingUniformTexelBufferUpdateAfterBind": true,
"descriptorBindingStorageTexelBufferUpdateAfterBind": true,
"descriptorBindingUpdateUnusedWhilePending": true,
"descriptorBindingPartiallyBound": true,
"descriptorBindingVariableDescriptorCount": true,
"runtimeDescriptorArray": true,
"scalarBlockLayout": true
}
},
"properties": {
"VkPhysicalDeviceVulkan12Properties": {
"shaderSignedZeroInfNanPreserveFloat16": true,
"shaderSignedZeroInfNanPreserveFloat32": true,
"maxPerStageDescriptorUpdateAfterBindSamplers": 500000,
"maxPerStageDescriptorUpdateAfterBindUniformBuffers": 12,
"maxPerStageDescriptorUpdateAfterBindStorageBuffers": 500000,
"maxPerStageDescriptorUpdateAfterBindSampledImages": 500000,
"maxPerStageDescriptorUpdateAfterBindStorageImages": 500000,
"maxPerStageDescriptorUpdateAfterBindInputAttachments": 7,
"maxPerStageUpdateAfterBindResources": 500000,
"maxDescriptorSetUpdateAfterBindSamplers": 500000,
"maxDescriptorSetUpdateAfterBindUniformBuffers": 72,
"maxDescriptorSetUpdateAfterBindUniformBuffersDynamic": 8,
"maxDescriptorSetUpdateAfterBindStorageBuffers": 500000,
"maxDescriptorSetUpdateAfterBindStorageBuffersDynamic": 4,
"maxDescriptorSetUpdateAfterBindSampledImages": 500000,
"maxDescriptorSetUpdateAfterBindStorageImages": 500000,
"maxDescriptorSetUpdateAfterBindInputAttachments": 7
}
}
},
"vulkan13requirements": {
"features": {
"VkPhysicalDeviceVulkan12Features": {
"vulkanMemoryModel": true,
"vulkanMemoryModelDeviceScope": true,
"bufferDeviceAddress": true
},
"VkPhysicalDeviceVulkan13Features": {
"robustImageAccess": true,
"shaderTerminateInvocation": true,
"shaderZeroInitializeWorkgroupMemory": true,
"synchronization2": true,
"shaderIntegerDotProduct": true,
"maintenance4": true,
"pipelineCreationCacheControl": true,
"subgroupSizeControl": true,
"computeFullSubgroups": true,
"shaderDemoteToHelperInvocation": true,
"inlineUniformBlock": true,
"dynamicRendering": true
}
},
"properties": {
"VkPhysicalDeviceVulkan13Properties": {
"maxBufferSize": 1073741824,
"maxInlineUniformBlockSize": 256,
"maxPerStageDescriptorInlineUniformBlocks": 4,
"maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks": 4,
"maxDescriptorSetInlineUniformBlocks": 4,
"maxDescriptorSetUpdateAfterBindInlineUniformBlocks": 4,
"maxInlineUniformTotalSize": 256
}
}
},
"vulkan13requirements_1_2": {
"extensions": {
"VK_EXT_image_robustness": 1,
"VK_KHR_shader_non_semantic_info": 1,
"VK_KHR_shader_terminate_invocation": 1,
"VK_KHR_format_feature_flags2": 1,
"VK_KHR_zero_initialize_workgroup_memory": 1,
"VK_KHR_synchronization2": 1,
"VK_KHR_shader_integer_dot_product": 1,
"VK_KHR_maintenance4": 1,
"VK_EXT_4444_formats": 1,
"VK_EXT_extended_dynamic_state": 1,
"VK_EXT_extended_dynamic_state2": 1,
"VK_EXT_pipeline_creation_cache_control": 1,
"VK_EXT_subgroup_size_control": 1,
"VK_EXT_shader_demote_to_helper_invocation": 1,
"VK_EXT_inline_uniform_block": 1,
"VK_EXT_pipeline_creation_feedback": 1,
"VK_EXT_texel_buffer_alignment": 1,
"VK_EXT_ycbcr_2plane_444_formats": 1,
"VK_EXT_texture_compression_astc_hdr": 1,
"VK_EXT_tooling_info": 1,
"VK_EXT_private_data": 1,
"VK_KHR_dynamic_rendering": 1
},
"features": {
"VkPhysicalDeviceVulkan12Features": {
"vulkanMemoryModel": true,
"vulkanMemoryModelDeviceScope": true,
"vulkanMemoryModelAvailabilityVisibilityChains": true,
"bufferDeviceAddress": true
},
"VkPhysicalDeviceImageRobustnessFeaturesEXT": {
"robustImageAccess": true
},
"VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR": {
"shaderTerminateInvocation": true
},
"VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR": {
"shaderZeroInitializeWorkgroupMemory": true
},
"VkPhysicalDeviceSynchronization2FeaturesKHR": {
"synchronization2": true
},
"VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR": {
"shaderIntegerDotProduct": true
},
"VkPhysicalDeviceMaintenance4FeaturesKHR": {
"maintenance4": true
},
"VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT": {
"pipelineCreationCacheControl": true
},
"VkPhysicalDeviceSubgroupSizeControlFeaturesEXT": {
"subgroupSizeControl": true,
"computeFullSubgroups": true
},
"VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT": {
"shaderDemoteToHelperInvocation": true
},
"VkPhysicalDeviceInlineUniformBlockFeaturesEXT": {
"inlineUniformBlock": true
}
},
"properties": {
"VkPhysicalDeviceMaintenance4PropertiesKHR": {
"maxBufferSize": 1073741824
},
"VkPhysicalDeviceInlineUniformBlockPropertiesEXT": {
"maxInlineUniformBlockSize": 256,
"maxPerStageDescriptorInlineUniformBlocks": 4,
"maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks": 4,
"maxDescriptorSetInlineUniformBlocks": 4,
"maxDescriptorSetUpdateAfterBindInlineUniformBlocks": 4
}
}
},
"vulkan13requirements_roadmap2022": {
"extensions": {
"VK_KHR_global_priority": 1
},
"features": {
"VkPhysicalDeviceVulkan13Features": {
"descriptorBindingInlineUniformBlockUpdateAfterBind": true
}
}
},
"vulkan13requirements_roadmap2022_1_2": {
"extensions": {
"VK_EXT_global_priority": 1,
"VK_EXT_inline_uniform_block": 1
},
"features": {
"VkPhysicalDeviceInlineUniformBlockFeaturesEXT": {
"descriptorBindingInlineUniformBlockUpdateAfterBind": true
}
}
}
},
"profiles": {
"VP_KHR_roadmap_2022": {
"version": 1,
"api-version": "1.3.204",
"label": "Khronos Vulkan Roadmap 2022 profile",
"description": "This roadmap profile is intended to be supported by newer devices shipping in 2022 across mainstream smartphone, tablet, laptops, console and desktop devices.",
"contributors": {
"Tobias Hector": {
"company": "AMD",
"email": "tobias.hector@amd.com",
"contact": true
},
"Christophe Riccio": {
"company": "LunarG",
"email": "christophe@lunarg.com",
"contact": true
}
},
"history": [
{
"revision": 7,
"date": "2022-11-16",
"author": "Christophe Riccio",
"comment": "Fix wideLines and largePoints that are optionals"
},
{
"revision": 6,
"date": "2022-11-02",
"author": "Christophe Riccio",
"comment": "Fix roadmap 2022 maxInlineUniformTotalSize limit, 256 instead of 4"
},
{
"revision": 5,
"date": "2022-05-02",
"author": "Christophe Riccio",
"comment": "Add missing dynamicRendering that is a Vulkan 1.3 requirement"
},
{
"revision": 4,
"date": "2022-03-08",
"author": "Christophe Riccio",
"comment": "Refactor requirements per Vulkan API version"
},
{
"revision": 3,
"date": "2022-03-08",
"author": "Christophe Riccio",
"comment": "Fix Vulkan 1.3.204 API version requirement"
},
{
"revision": 2,
"date": "2022-01-03",
"author": "Christophe Riccio",
"comment": "Rebase against Vulkan 1.3.203 revision"
},
{
"revision": 1,
"date": "2021-12-08",
"author": "Christophe Riccio",
"comment": "Initial revision"
}
],
"capabilities": [
"vulkan10requirements",
"vulkan10requirements_roadmap2022",
"vulkan11requirements",
"vulkan11requirements_roadmap2022",
"vulkan12requirements",
"vulkan12requirements_roadmap2022",
"vulkan13requirements",
"vulkan13requirements_roadmap2022"
],
"optionals": [
"vulkan10optionals_roadmap2022"
]
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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)

View file

@ -1,42 +0,0 @@
#!/usr/bin/python3
#
# Copyright 2023 The Khronos Group Inc.
# SPDX-License-Identifier: Apache-2.0
import argparse
import xml.etree.ElementTree as etree
from reg import stripNonmatchingAPIs
if __name__ == '__main__':
parser = argparse.ArgumentParser(prog='stripAPI',
formatter_class=argparse.RawDescriptionHelpFormatter,
description='''\
Filters out elements with non-matching explicit 'api' attributes from API XML.
To remove Vulkan SC-only elements from the combined API XML:
python3 scripts/stripAPI.py -input xml/vk.xml -output vulkan-only.xml -keepAPI vulkan
To remove Vulkan-only elements:
python3 scripts/stripAPI.py -input xml/vk.xml -output vulkansc-only.xml -keepAPI vulkansc
If you are parsing the XML yourself but using the xml.etree package, the
equivalent runtime code is:
import reg
reg.stripNonmatchingAPIs(tree.getroot(), keepAPI, actuallyDelete=True)
where 'tree' is an ElementTree created from the XML file using
etree.parse(filename)''')
parser.add_argument('-input', action='store',
required=True,
help='Specify input registry XML')
parser.add_argument('-output', action='store',
required=True,
help='Specify output registry XML')
parser.add_argument('-keepAPI', action='store',
default=None,
help='Specify API name whose \'api\' tags are kept')
args = parser.parse_args()
tree = etree.parse(args.input)
if args.keepAPI is not None:
stripNonmatchingAPIs(tree.getroot(), args.keepAPI, actuallyDelete = True)
tree.write(args.output)

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,279 +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'_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[]'