Update for Vulkan-Docs 1.1.122

This commit is contained in:
Jon Leech 2019-09-08 21:57:00 -07:00 committed by Jon Leech
parent 5671d014bc
commit 42ad3f90fa
10 changed files with 1107 additions and 955 deletions

File diff suppressed because it is too large Load diff

View file

@ -44,7 +44,7 @@ extern "C" {
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
#define VK_HEADER_VERSION 121
#define VK_HEADER_VERSION 122
#define VK_NULL_HANDLE 0
@ -6993,7 +6993,7 @@ typedef struct VkExportMemoryAllocateInfoNV {
#define VK_EXT_validation_flags 1
#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2
#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
typedef enum VkValidationCheckEXT {
@ -9729,7 +9729,7 @@ typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT {
#define VK_EXT_headless_surface 1
#define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 0
#define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1
#define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface"
typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT;
typedef struct VkHeadlessSurfaceCreateInfoEXT {

View file

@ -16,119 +16,120 @@
import os
import re
import sys
from generator import (GeneratorOptions, OutputGenerator, noneStr,
regSortFeatures, write)
# CGeneratorOptions - subclass of GeneratorOptions.
#
# Adds options used by COutputGenerator objects during C language header
# generation.
#
# Additional members
# 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
# 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.
# directory - directory into which to generate include files
# 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)
# aliasMacro - alias macro to inject when genAliasMacro is True
class CGeneratorOptions(GeneratorOptions):
"""Represents options during C interface generation for headers"""
"""CGeneratorOptions - subclass of GeneratorOptions.
Adds options used by COutputGenerator objects during C language header
generation."""
def __init__(self,
conventions = None,
filename = None,
directory = '.',
apiname = None,
profile = None,
versions = '.*',
emitversions = '.*',
defaultExtensions = None,
addExtensions = None,
removeExtensions = None,
emitExtensions = None,
sortProcedure = regSortFeatures,
prefixText = "",
genFuncPointers = True,
protectFile = True,
protectFeature = True,
protectProto = None,
protectProtoStr = None,
apicall = '',
apientry = '',
apientryp = '',
indentFuncProto = True,
indentFuncPointer = False,
alignFuncParam = 0,
genEnumBeginEndRange = False,
genAliasMacro = False,
aliasMacro = ''
):
GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
versions, emitversions, defaultExtensions,
addExtensions, removeExtensions,
emitExtensions, sortProcedure)
self.prefixText = prefixText
self.genFuncPointers = genFuncPointers
self.protectFile = protectFile
self.protectFeature = protectFeature
self.protectProto = protectProto
self.protectProtoStr = protectProtoStr
self.apicall = apicall
self.apientry = apientry
self.apientryp = apientryp
self.indentFuncProto = indentFuncProto
self.indentFuncPointer = indentFuncPointer
self.alignFuncParam = alignFuncParam
self.genEnumBeginEndRange = genEnumBeginEndRange
self.genAliasMacro = genAliasMacro
self.aliasMacro = aliasMacro
prefixText="",
genFuncPointers=True,
protectFile=True,
protectFeature=True,
protectProto=None,
protectProtoStr=None,
apicall='',
apientry='',
apientryp='',
indentFuncProto=True,
indentFuncPointer=False,
alignFuncParam=0,
genEnumBeginEndRange=False,
genAliasMacro=False,
aliasMacro='',
**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
- 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)
- aliasMacro - alias macro to inject when genAliasMacro is True"""
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.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.aliasMacro = aliasMacro
"""alias macro to inject when genAliasMacro is True"""
# COutputGenerator - subclass of OutputGenerator.
# Generates C-language API interfaces.
#
# ---- methods ----
# COutputGenerator(errFile, warnFile, diagFile) - args as for
# OutputGenerator. Defines additional internal state.
# ---- methods overriding base class ----
# beginFile(genOpts)
# endFile()
# beginFeature(interface, emit)
# endFeature()
# genType(typeinfo,name)
# genStruct(typeinfo,name)
# genGroup(groupinfo,name)
# genEnum(enuminfo, name)
# genCmd(cmdinfo)
class COutputGenerator(OutputGenerator):
"""Generate specified API interfaces in a specific style, such as a C header"""
"""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']
@ -189,8 +190,8 @@ class COutputGenerator(OutputGenerator):
self.feature_not_empty = False
def endFeature(self):
"Actually write the interface to the output file."
# C-specific
# Actually write the interface to the output file.
if self.emit:
if self.feature_not_empty:
if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
@ -214,7 +215,7 @@ class COutputGenerator(OutputGenerator):
if self.sections['command']:
if self.genOpts.protectProto:
write(self.genOpts.protectProto,
self.genOpts.protectProtoStr, file=self.outFile)
self.genOpts.protectProtoStr, file=self.outFile)
write('\n'.join(self.sections['command']), end='', file=self.outFile)
if self.genOpts.protectProto:
write('#endif', file=self.outFile)
@ -227,14 +228,14 @@ class COutputGenerator(OutputGenerator):
# Finish processing in superclass
OutputGenerator.endFeature(self)
# Append a definition to the specified section
def appendSection(self, section, text):
"Append a definition to the specified section"
# self.sections[section].append('SECTION: ' + section + '\n')
self.sections[section].append(text)
self.feature_not_empty = True
# Type generation
def genType(self, typeinfo, name, alias):
"Generate type."
OutputGenerator.genType(self, typeinfo, name, alias)
typeElem = typeinfo.elem
@ -275,12 +276,13 @@ class COutputGenerator(OutputGenerator):
body += '\n'
self.appendSection(section, body)
# Protection string generation
# Protection strings are the strings defining the OS/Platform/Graphics
# requirements for a given OpenXR 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.
def genProtectString(self, protect_str):
"""Generate protection string.
Protection strings are the strings defining the OS/Platform/Graphics
requirements for a given OpenXR 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:
@ -315,16 +317,18 @@ class COutputGenerator(OutputGenerator):
if x is not None))
return typeName in self.may_alias
# Struct (e.g. C "struct" type) generation.
# 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.
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)
typeElem = typeinfo.elem
@ -356,11 +360,13 @@ class COutputGenerator(OutputGenerator):
self.appendSection('struct', body)
# Group (e.g. C "enum" type) generation.
# 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.
def genGroup(self, groupinfo, groupName, alias = None):
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
@ -380,17 +386,18 @@ class COutputGenerator(OutputGenerator):
(section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName)
self.appendSection(section, "\n" + body)
# Enumerant generation
# <enum> tags may specify their values in several ways, but are usually
# just integers.
def genEnum(self, enuminfo, name, alias):
"""Generate enumerants.
<enum> tags may specify their values in several ways, but are usually
just integers."""
OutputGenerator.genEnum(self, enuminfo, name, alias)
(_, strVal) = self.enumToValue(enuminfo.elem, False)
body = '#define ' + name.ljust(33) + ' ' + strVal
self.appendSection('enum', body)
# Command generation
def genCmd(self, cmdinfo, name, alias):
"Command generation"
OutputGenerator.genCmd(self, cmdinfo, name, alias)
# if alias:

View file

@ -314,3 +314,10 @@ class ConventionsBase:
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

View file

@ -13,6 +13,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Base class for source/header/doc generators, as well as some utility functions."""
from __future__ import unicode_literals
@ -35,111 +36,82 @@ def write(*args, **kwargs):
file.write(' '.join(str(arg) for arg in args))
file.write(end)
# noneStr - returns string argument, or "" if argument is None.
# Used in converting etree Elements into text.
# s - string to convert
def noneStr(s):
"""Return string argument, or "" if argument is None.
Used in converting etree Elements into text.
s - string to convert"""
if s:
return s
return ""
# noneInt - returns string argument as an integer, or default if argument is
# None.
# Used in converting etree Elements into integers.
# s - string to convert
# default - default value
def noneInt(s, default = 0):
if s:
return int(s)
else:
return default
# enquote - returns string argument with surrounding quotes,
# for serialization into Python code.
def enquote(s):
"""Return string argument with surrounding quotes,
for serialization into Python code."""
if s:
return "'{}'".format(s)
return None
# 1st sort key for regSortFeatures.
# Sorts by category of the feature name string:
# Core API features (those defined with a <feature> tag)
# ARB/KHR/OES (Khronos extensions)
# other (EXT/vendor extensions)
# This will need changing for Vulkan!
def regSortCategoryKey(feature):
"""Primary sort key for regSortFeatures.
Sorts by category of the feature name string:
- Core API features (those defined with a `<feature>` tag)
- ARB/KHR/OES (Khronos extensions)
- other (EXT/vendor extensions)
This may need to change for some APIs"""
if feature.elem.tag == 'feature':
return 0
if (feature.category == 'ARB' or
feature.category == 'KHR' or
feature.category == 'OES'):
if (feature.category == 'ARB'
or feature.category == 'KHR'
or feature.category == 'OES'):
return 1
return 2
# 2nd sort key for regSortFeatures.
# Sorts by sortorder attribute
def regSortOrderKey(feature):
"""Secondary sort key for regSortFeatures.
Sorts by sortorder attribute."""
return feature.sortorder
# 3rd sort key for regSortFeatures.
# Sorts by feature version. <extension> elements all have version number "0"
def regSortFeatureVersionKey(feature):
"""Tertiary sort key for regSortFeatures.
Sorts by feature version.
`<extension>` elements all have version number 0."""
return float(feature.versionNumber)
# 4th sort key for regSortFeatures.
# Sorts by extension number. <feature> elements all have extension number 0.
def regSortExtensionNumberKey(feature):
"""Last sort key for regSortFeatures.
Sorts by extension number.
`<feature>` elements all have extension number 0."""
return int(feature.number)
# regSortFeatures - default sort procedure for features.
# Sorts by primary key of feature category ('feature', or extension tag)
# then by sort order within the category
# then by version number (for features)
# then by extension number (for extensions)
def regSortFeatures(featureList):
"""Default sort procedure for features.
- Sorts by primary key of feature category ('feature' or 'extension'),
- then by sort order within the category
- then by version number (for features)
- then by extension number (for extensions)"""
featureList.sort(key=regSortExtensionNumberKey)
featureList.sort(key=regSortFeatureVersionKey)
featureList.sort(key=regSortOrderKey)
featureList.sort(key=regSortCategoryKey)
# GeneratorOptions - base class for options used during header production
# These options are target language independent, and used by
# Registry.apiGen() and by base OutputGenerator objects.
#
# Members
# 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
# apiname - string matching <api> 'apiname' attribute, e.g. 'gl'.
# 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).
# 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, by core API version number or extension number in
# each group.
# The regex patterns can be None or empty, in which case they match
# nothing.
class GeneratorOptions:
"""Represents options during header production from an API registry"""
"""Base class for options used during header/documentation production.
These options are target language independent, and used by
Registry.apiGen() and by base OutputGenerator objects."""
def __init__(self,
conventions=None,
@ -154,71 +126,108 @@ class GeneratorOptions:
removeExtensions=None,
emitExtensions=None,
sortProcedure=regSortFeatures):
self.conventions = conventions
self.filename = filename
self.directory = directory
self.apiname = apiname
self.profile = profile
self.versions = self.emptyRegex(versions)
self.emitversions = self.emptyRegex(emitversions)
self.defaultExtensions = defaultExtensions
self.addExtensions = self.emptyRegex(addExtensions)
self.removeExtensions = self.emptyRegex(removeExtensions)
self.emitExtensions = self.emptyRegex(emitExtensions)
self.sortProcedure = sortProcedure
"""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
- apiname - string matching `<api>` 'apiname' attribute, e.g. 'gl'.
- 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).
- 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, by core API version number or extension number in each
group.
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.directory = directory
"directory in which to generate filename"
self.apiname = apiname
"string matching `<api>` 'apiname' attribute, e.g. 'gl'."
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."""
self.emitversions = self.emptyRegex(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]'`."""
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.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."""
# Substitute a regular expression which matches no version
# or extension names for None or the empty string.
def emptyRegex(self, pat):
if pat is None or pat == '':
"""Substitute a regular expression which matches no version
or extension names for None or the empty string."""
if not pat:
return '_nomatch_^'
return pat
# OutputGenerator - base class for generating API interfaces.
# Manages basic logic, logging, and output file control
# Derived classes actually generate formatted output.
#
# ---- methods ----
# OutputGenerator(errFile, warnFile, diagFile)
# errFile, warnFile, diagFile - file handles to write errors,
# warnings, diagnostics to. May be None to not write.
# logMsg(level, *args) - log messages of different categories
# level - 'error', 'warn', or 'diag'. 'error' will also
# raise a UserWarning exception
# *args - print()-style arguments
# setExtMap(map) - specify a dictionary map from extension names to
# numbers, used in creating values for extension enumerants.
# makeDir(directory) - create a directory, if not already done.
# Generally called from derived generators creating hierarchies.
# beginFile(genOpts) - start a new interface file
# genOpts - GeneratorOptions controlling what's generated and how
# endFile() - finish an interface file, closing it when done
# beginFeature(interface, emit) - write interface for a feature
# and tag generated features as having been done.
# interface - element for the <version> / <extension> to generate
# emit - actually write to the header only when True
# endFeature() - finish an interface.
# genType(typeinfo,name,alias) - generate interface for a type
# typeinfo - TypeInfo for a type
# genStruct(typeinfo,name,alias) - generate interface for a C "struct" type.
# typeinfo - TypeInfo for a type interpreted as a struct
# genGroup(groupinfo,name,alias) - generate interface for a group of enums (C "enum")
# groupinfo - GroupInfo for a group
# genEnum(enuminfo,name,alias) - generate interface for an enum (constant)
# enuminfo - EnumInfo for an enum
# name - enum name
# genCmd(cmdinfo,name,alias) - generate interface for a command
# cmdinfo - CmdInfo for a command
# isEnumRequired(enumElem) - return True if this <enum> element is required
# elem - <enum> element to test
# makeCDecls(cmd) - return C prototype and function pointer typedef for a
# <command> Element, as a list of two strings
# cmd - Element for the <command>
# newline() - print a newline to the output file (utility function)
#
class OutputGenerator:
"""Generate specified API interfaces in a specific style, such as a C header"""
"""Generate specified API interfaces in a specific style, such as a C header.
Base class for generating API interfaces.
Manages basic logic, logging, and output file control.
Derived classes actually generate formatted output.
"""
# categoryToPath - map XML 'category' to include file directory name
categoryToPath = {
@ -230,11 +239,11 @@ class OutputGenerator:
'basetype': 'basetypes',
}
# Constructor
def __init__(self,
errFile=sys.stderr,
warnFile=sys.stderr,
diagFile=sys.stdout):
def __init__(self, errFile=sys.stderr, warnFile=sys.stderr, diagFile=sys.stdout):
"""Constructor
- errFile, warnFile, diagFile - file handles to write errors,
warnings, diagnostics to. May be None to not write."""
self.outFile = None
self.errFile = errFile
self.warnFile = warnFile
@ -248,15 +257,16 @@ class OutputGenerator:
self.extBlockSize = 1000
self.madeDirs = {}
# logMsg - 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
def logMsg(self, level, *args):
"""Log a message at the given level. Can be ignored or log to a file"""
"""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)
@ -273,26 +283,30 @@ class OutputGenerator:
raise UserWarning(
'*** FATAL ERROR in Generator.logMsg: unknown level:' + level)
# enumToValue - parses and converts an <enum> tag into a value.
# Returns a list
# first element - integer representation of the value, or None
# if needsNum is False. The value must be a legal number
# if needsNum is True.
# second element - string representation of the value
# There are several possible representations of values.
# A 'value' attribute simply contains the value.
# A 'bitpos' attribute defines a value by specifying the bit
# position which is set in that value.
# A 'offset','extbase','extends' triplet specifies a value
# as an offset to a base value defined by the specified
# 'extbase' extension name, which is then cast to the
# typename specified by 'extends'. This requires probing
# the registry database, and imbeds knowledge of the
# API extension enum scheme in this function.
# A 'alias' attribute contains the name of another enum
# which this is an alias of. The other enum must be
# declared first when emitting this enum.
def enumToValue(self, elem, needsNum):
"""Parse and convert an `<enum>` tag into a value.
Returns a list:
- first element - integer representation of the value, or None
if needsNum is False. The value must be a legal number
if needsNum is True.
- second element - string representation of the value
There are several possible representations of values.
- A 'value' attribute simply contains the value.
- A 'bitpos' attribute defines a value by specifying the bit
position which is set in that value.
- An 'offset','extbase','extends' triplet specifies a value
as an offset to a base value defined by the specified
'extbase' extension name, which is then cast to the
typename specified by 'extends'. This requires probing
the registry database, and imbeds knowledge of the
API extension enum scheme in this function.
- An 'alias' attribute contains the name of another enum
which this is an alias of. The other enum must be
declared first when emitting this enum."""
name = elem.get('name')
numVal = None
if 'value' in elem.keys():
@ -340,10 +354,12 @@ class OutputGenerator:
return [None, elem.get('alias')]
return [None, None]
# checkDuplicateEnums - sanity check for enumerated values
# enums - list of <enum> Elements
# returns the list with duplicates stripped
def checkDuplicateEnums(self, enums):
"""Sanity check enumerated values.
- 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
@ -362,15 +378,15 @@ class OutputGenerator:
# 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)):
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)
self.logMsg('warn', 'checkDuplicateEnums: Duplicate enum (' + name
+ ') found with different values:' + strVal
+ ' and ' + strVal2)
# Don't add the duplicate to the returned list
continue
@ -380,8 +396,8 @@ class OutputGenerator:
(name2, numVal2, strVal2) = valueMap[numVal]
try:
self.logMsg('warn', 'Two enums found with the same value: '
+ name + ' = ' + name2.get('name') + ' = ' + strVal)
self.logMsg('warn', 'Two enums found with the same value: ' +
name + ' = ' + name2.get('name') + ' = ' + strVal)
except:
pdb.set_trace()
@ -396,9 +412,8 @@ class OutputGenerator:
# Return the list
return stripped
# buildEnumCDecl
# Generates the C declaration for an enum
def buildEnumCDecl(self, expand, groupinfo, groupName):
"""Generate the C declaration for an enum"""
groupElem = groupinfo.elem
if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
@ -406,10 +421,9 @@ class OutputGenerator:
else:
return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
# buildEnumCDecl_Bitmask
# Generates the C declaration for an "enum" that is actually a
# set of flag bits
def buildEnumCDecl_Bitmask(self, groupinfo, groupName):
"""Generate the C declaration for an "enum" that is actually a
set of flag bits"""
groupElem = groupinfo.elem
flagTypeName = groupinfo.flagType.elem.get('name')
@ -429,8 +443,8 @@ class OutputGenerator:
return ("bitmask", body)
# Generates the C declaration for an enumerated type
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
@ -522,6 +536,9 @@ class OutputGenerator:
return (section, '\n'.join(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
@ -531,6 +548,9 @@ class OutputGenerator:
self.madeDirs[path] = None
def beginFile(self, genOpts):
"""Start a new interface file
- genOpts - GeneratorOptions controlling what's generated and how"""
self.genOpts = genOpts
self.should_insert_may_alias_macro = \
self.genOpts.conventions.should_insert_may_alias_macro(self.genOpts)
@ -564,29 +584,42 @@ class OutputGenerator:
self.genOpts = None
def beginFeature(self, interface, emit):
"""Write interface for a feature and tag generated features as having been done.
- interface - element for the `<version>` / `<extension>` to generate
- emit - actually write to the header only when True"""
self.emit = emit
self.featureName = interface.get('name')
# If there's an additional 'protect' attribute in the feature, save it
self.featureExtraProtect = interface.get('protect')
def endFeature(self):
# Derived classes responsible for emitting feature
"""Finish an interface file, closing it when done.
Derived classes responsible for emitting feature"""
self.featureName = None
self.featureExtraProtect = None
# Utility method to validate we're generating something only inside a
# <feature> tag
def validateFeature(self, featureType, featureName):
"""Validate we're generating something only inside a `<feature>` tag"""
if self.featureName is None:
raise UserWarning('Attempt to generate', featureType,
featureName, 'when not in feature')
# Type generation
def genType(self, typeinfo, name, alias):
"""Generate interface for a type
- typeinfo - TypeInfo for a type
Extend to generate as desired in your derived class."""
self.validateFeature('type', name)
# Struct (e.g. C "struct" type) generation
def genStruct(self, typeinfo, typeName, alias):
"""Generate interface for a C "struct" type.
- typeinfo - TypeInfo for a type interpreted as a struct
Extend to generate as desired in your derived class."""
self.validateFeature('struct', typeName)
# The mixed-mode <member> tags may contain no-op <comment> tags.
@ -596,35 +629,52 @@ class OutputGenerator:
for comment in member.findall('comment'):
member.remove(comment)
# Group (e.g. C "enum" type) generation
def genGroup(self, groupinfo, groupName, alias):
"""Generate interface for a group of enums (C "enum")
- groupinfo - GroupInfo for a group.
Extend to generate as desired in your derived class."""
self.validateFeature('group', groupName)
# Enumerant (really, constant) generation
def genEnum(self, enuminfo, typeName, alias):
"""Generate interface for an enum (constant).
- enuminfo - EnumInfo for an enum
- name - enum name
Extend to generate as desired in your derived class."""
self.validateFeature('enum', typeName)
# Command generation
def genCmd(self, cmd, cmdinfo, alias):
"""Generate interface for a command.
- cmdinfo - CmdInfo for a command
Extend to generate as desired in your derived class."""
self.validateFeature('command', cmdinfo)
# Utility functions - turn a <proto> <name> into C-language prototype
# and typedef declarations for that name.
# name - contents of <name> tag
# tail - whatever text follows that tag in the Element
def makeProtoName(self, name, tail):
"""Turn a `<proto>` `<name>` into C-language prototype
and typedef declarations for that name.
- name - contents of `<name>` tag
- tail - whatever text follows that tag in the Element"""
return self.genOpts.apientry + name + tail
def makeTypedefName(self, name, tail):
"""Make the function-pointer typedef name for a command."""
return '(' + self.genOpts.apientryp + 'PFN_' + name + tail + ')'
# makeCParamDecl - return a string which is an indented, formatted
# declaration for a <param> or <member> block (e.g. function parameter
# or structure/union member).
# param - Element (<param> or <member>) to format
# aligncol - if non-zero, attempt to align the nested <name> element
# at this column
def makeCParamDecl(self, param, aligncol):
"""Return a string which is an indented, formatted
declaration for a `<param>` or `<member>` block (e.g. function parameter
or structure/union member).
- param - Element (`<param>` or `<member>`) to format
- aligncol - if non-zero, attempt to align the nested `<name>` element
at this column"""
indent = ' '
paramdecl = indent + noneStr(param.text)
for elem in param:
@ -647,23 +697,24 @@ class OutputGenerator:
self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
paramdecl += text + tail
if aligncol == 0:
# Squeeze out multiple spaces other than the identation
# Squeeze out multiple spaces other than the indentation
paramdecl = indent + ' '.join(paramdecl.split())
return paramdecl
# getCParamTypeLength - return the length of the type field in an
# indented, formatted declaration for a <param> or <member> block (e.g.
# function parameter or structure/union member). This relies on the
# presence of the <name> tag; if not present, return zero.
# param - Element (<param> or <member>) to identify
def getCParamTypeLength(self, param):
"""Return the length of the type field is an indented, formatted
declaration for a `<param>` or `<member>` block (e.g. function parameter
or structure/union member).
- param - Element (`<param>` or `<member>`) to identify"""
# Allow for missing <name> tag
newLen = 0
paramdecl = ' ' + noneStr(param.text)
for elem in param:
text = noneStr(elem.text)
tail = noneStr(elem.tail)
if self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
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':
@ -677,7 +728,7 @@ class OutputGenerator:
def getMaxCParamTypeLength(self, info):
"""Return the length of the longest type field for a member/parameter.
info - TypeInfo or CommandInfo.
- info - TypeInfo or CommandInfo.
"""
lengths = (self.getCParamTypeLength(member)
for member in info.getMembers())
@ -763,10 +814,11 @@ class OutputGenerator:
return True
# isEnumRequired(elem) - return True if this <enum> element is
# required, False otherwise
# elem - <enum> element to test
def isEnumRequired(self, elem):
"""Return True if this `<enum>` element is
required, False otherwise
- elem - `<enum>` element to test"""
required = elem.get('required') is not None
self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
'->', required)
@ -792,11 +844,11 @@ class OutputGenerator:
return required
# makeCDecls - return C prototype and function pointer typedef for a
# command, as a two-element list of strings.
# cmd - Element containing a <command> tag
def makeCDecls(self, cmd):
"""Generate C function pointer typedef for <command> Element"""
"""Return C prototype and function pointer typedef for a
`<command>` Element, as a two-element list of strings.
- cmd - Element containing a `<command>` tag"""
proto = cmd.find('proto')
params = cmd.findall('param')
# Begin accumulating prototype and typedef strings
@ -858,6 +910,7 @@ class OutputGenerator:
return [pdecl + indentdecl, tdecl + paramdecl]
def newline(self):
"""Print a newline to the output file (utility function)"""
write('', file=self.outFile)
def setRegistry(self, registry):

View file

@ -32,6 +32,7 @@ from reg import Registry
from validitygenerator import ValidityOutputGenerator
from vkconventions import VulkanConventions
# Simple timer functions
startTime = None
@ -41,6 +42,7 @@ def startTimer(timeit):
if timeit:
startTime = time.process_time()
def endTimer(timeit, msg):
global startTime
if timeit:
@ -57,12 +59,13 @@ def makeREstring(strings, default=None, strings_are_regex=False):
return '^(' + '|'.join(strings) + ')$'
return default
# 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.
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 = {}
@ -403,16 +406,18 @@ def makeGenOpts(args):
alignFuncParam = 36)
]
# Generate a target based on the options in the matching genOpts{} object.
# This is encapsulated in a function so it can be profiled and/or timed.
# 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
def genTarget(args):
"""Generate a target based on the options in the matching genOpts{} object.
This is encapsulated in a function so it can be profiled and/or timed.
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 specified parameters
makeGenOpts(args)
@ -522,7 +527,7 @@ if __name__ == '__main__':
if args.dump:
write('* Dumping registry to regdump.txt', file=sys.stderr)
reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8'))
reg.dumpReg(filehandle=open('regdump.txt', 'w', encoding='utf-8'))
# create error/warning & diagnostic files
if args.errfile:

View file

@ -13,101 +13,117 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Types and classes for manipulating an API registry."""
import copy
import re
import sys
import xml.etree.ElementTree as etree
from collections import defaultdict, namedtuple
from generator import OutputGenerator, write, noneInt
import pdb
from generator import OutputGenerator, write
# matchAPIProfile - returns 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. Can't 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 isn't really quite enough, we might prefer something
# like "gl(core)|gles1(common-lite)".
def matchAPIProfile(api, profile, elem):
"""Match a requested API & profile name to a api & profile attributes of an Element"""
"""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. Can't 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 isn't really quite enough, we might prefer something
like `"gl(core)|gles1(common-lite)"`."""
# Match 'api', if present
elem_api = elem.get('api')
if elem_api:
if api is None:
raise UserWarning("No API requested, but 'api' attribute is present with value '" +
elem_api + "'")
raise UserWarning("No API requested, but 'api' attribute is present with value '"
+ elem_api + "'")
elif api != elem_api:
# Requested API doesn't 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 + "'")
raise UserWarning("No profile requested, but 'profile' attribute is present with value '"
+ elem_profile + "'")
elif profile != elem_profile:
# Requested profile doesn't match attribute
return False
return True
# Print all the keys in an Element - only for diagnostics
# def printKeys(msg, elem):
# """Print all the keys in an Element - only for diagnostics"""
# print('printKeys:', msg, file=sys.stderr)
# for key in elem.keys():
# print(' {} -> {}'.format(key, elem.get(key)), file=sys.stderr)
# BaseInfo - base class for information about a registry feature
# (type/group/enum/command/API/extension).
# required - should this feature be defined during header generation
# (has it been removed by a profile or version)?
# declared - has this feature been defined already?
# elem - etree Element for this feature
# resetState() - reset required/declared to initial values. Used
# prior to generating a new API interface.
# compareElem(info) - return True if self.elem and info.elem have the
# same definition.
class BaseInfo:
"""Represents the state of a registry feature, used during API generation"""
"""Base class for information about a registry feature
(type/group/enum/command/API/extension).
Represents the state of a registry feature, used during API generation.
"""
def __init__(self, elem):
self.required = False
"""should this feature be defined during header generation
(has it been removed by a profile or version)?"""
self.declared = False
"has this feature been defined already?"
self.elem = elem
"etree Element for this feature"
def resetState(self):
"""Reset required/declared to initial values. Used
prior to generating a new API interface."""
self.required = False
self.declared = False
def compareKeys(self, info, key, required = False):
# Return True if self.elem and info.elem have the same attribute
# value for key.
# If 'required' is not True, also returns True if neither element
# has an attribute value for key.
"""Return True if self.elem and info.elem have the same attribute
value for key.
If 'required' is not True, also returns True if neither element
has an attribute value for key."""
if required and key not in self.elem.keys():
return False
return self.elem.get(key) == info.elem.get(key)
def compareElem(self, info, infoName):
# Return True if self.elem and info.elem have the same definition
# info - the other object
# infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension'
"""Return True if self.elem and info.elem have the same definition.
info - the other object
infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' /
'extension'"""
if infoName == 'enum':
if self.compareKeys(info, 'extends'):
@ -132,16 +148,18 @@ class BaseInfo:
# Non-<enum>s should never be redefined
return False
# TypeInfo - registry information about a type. No additional state
# beyond BaseInfo is required.
class TypeInfo(BaseInfo):
"""Represents the state of a registry type"""
"""Registry information about a type. No additional state
beyond BaseInfo is required."""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.additionalValidity = []
self.removedValidity = []
def getMembers(self):
"""Get a collection of all member elements for this type, if any."""
return self.elem.findall('member')
def resetState(self):
@ -149,33 +167,37 @@ class TypeInfo(BaseInfo):
self.additionalValidity = []
self.removedValidity = []
# GroupInfo - registry information about a group of related enums
# in an <enums> block, generally corresponding to a C "enum" type.
class GroupInfo(BaseInfo):
"""Represents the state of a registry <enums> group"""
"""Registry information about a group of related enums
in an <enums> block, generally corresponding to a C "enum" type."""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
# EnumInfo - registry information about an enum
# type - numeric type of the value of the <enum> tag
# ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )
class EnumInfo(BaseInfo):
"""Represents the state of a registry enum"""
"""Registry information about an enum"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.type = elem.get('type')
"""numeric type of the value of the <enum> tag
( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )"""
if self.type is None:
self.type = ''
# CmdInfo - registry information about a command
class CmdInfo(BaseInfo):
"""Represents the state of a registry command"""
"""Registry information about a command"""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.additionalValidity = []
self.removedValidity = []
def getParams(self):
"""Get a collection of all param elements for this command, if any."""
return self.elem.findall('param')
def resetState(self):
@ -183,33 +205,35 @@ class CmdInfo(BaseInfo):
self.additionalValidity = []
self.removedValidity = []
# FeatureInfo - registry information about an API <feature>
# or <extension>
# name - feature name string (e.g. 'VK_KHR_surface')
# category - category, e.g. VERSION or khr/vendor tag
# version - feature name string
# features are unversioned and assigned version number 0.
# ** This is confusingly taken from the 'number' attribute of <feature>.
# Needs fixing.
# versionNumber - API version number, taken from the 'number' attribute
# of <feature>. Extensions do not have API version numbers and are
# assigned number 0.
# number - extension number, used for ordering and for
# assigning enumerant offsets. <feature> features do
# not have extension numbers and are assigned number 0.
# emit - has this feature been defined already?
class FeatureInfo(BaseInfo):
"""Represents the state of an API feature (version/extension)"""
"""Registry information about an API <feature>
or <extension>."""
def __init__(self, elem):
BaseInfo.__init__(self, elem)
self.name = elem.get('name')
self.sortorder = noneInt(elem.get('sortorder'), 0)
"feature name string (e.g. 'VK_KHR_surface')"
self.emit = False
"has this feature been defined already?"
self.sortorder = int(elem.get('sortorder', 0))
"""explicit numeric sort key within feature and extension groups.
Defaults to 0."""
if elem.tag == 'feature':
# Element category (vendor) is meaningless for <feature>
self.category = 'VERSION'
"category, e.g. VERSION or khr/vendor tag"
self.version = elem.get('name')
"""feature name string"""
self.versionNumber = elem.get('number')
"""versionNumber - API version number, taken from the 'number'
attribute of <feature>. Extensions do not have API version
numbers and are assigned number 0."""
self.number = "0"
self.supported = None
else:
@ -218,78 +242,77 @@ class FeatureInfo(BaseInfo):
self.version = "0"
self.versionNumber = "0"
self.number = elem.get('number')
"""extension number, used for ordering and for assigning
enumerant offsets. <feature> features do not have extension
numbers and are assigned number 0."""
# If there's no 'number' attribute, use 0, so sorting works
if self.number is None:
self.number = 0
self.supported = elem.get('supported')
self.emit = False
# Registry - object representing an API registry, loaded from an XML file
# Members
# tree - ElementTree containing the root <registry>
# typedict - dictionary of TypeInfo objects keyed by type name
# groupdict - dictionary of GroupInfo objects keyed by group name
# enumdict - dictionary of EnumInfo objects keyed by enum name
# cmddict - dictionary of CmdInfo objects keyed by command name
# apidict - dictionary of <api> Elements keyed by API name
# extensions - list of <extension> Elements
# extdict - dictionary of <extension> Elements keyed by extension name
# gen - OutputGenerator object used to write headers / messages
# genOpts - GeneratorOptions object used to control which
# fetures to write and how to format them
# emitFeatures - True to actually emit features for a version / extension,
# or False to just treat them as emitted
# breakPat - regexp pattern to break on when generatng names
# Public methods
# loadElementTree(etree) - load registry from specified ElementTree
# loadFile(filename) - load registry from XML file
# setGenerator(gen) - OutputGenerator to use
# breakOnName() - specify a feature name regexp to break on when
# generating features.
# parseTree() - parse the registry once loaded & create dictionaries
# dumpReg(maxlen, filehandle) - diagnostic to dump the dictionaries
# to specified file handle (default stdout). Truncates type /
# enum / command elements to maxlen characters (default 80)
# generator(g) - specify the output generator object
# apiGen(apiname, genOpts) - generate API headers for the API type
# and profile specified in genOpts, but only for the versions and
# extensions specified there.
# apiReset() - call between calls to apiGen() to reset internal state
# Private methods
# addElementInfo(elem,info,infoName,dictionary) - add feature info to dict
# lookupElementInfo(fname,dictionary) - lookup feature info in dict
class Registry:
"""Represents an API registry loaded from XML"""
"""Object representing an API registry, loaded from an XML file."""
def __init__(self):
self.tree = None
self.typedict = {}
self.groupdict = {}
self.enumdict = {}
self.cmddict = {}
self.apidict = {}
self.extensions = []
self.requiredextensions = [] # Hack - can remove it after validity generator goes away
self.tree = None
"ElementTree containing the root `<registry>`"
self.typedict = {}
"dictionary of TypeInfo objects keyed by type name"
self.groupdict = {}
"dictionary of GroupInfo objects keyed by group name"
self.enumdict = {}
"dictionary of EnumInfo objects keyed by enum name"
self.cmddict = {}
"dictionary of CmdInfo objects keyed by command name"
self.apidict = {}
"dictionary of FeatureInfo objects for `<feature>` elements keyed by API name"
self.extensions = []
"list of `<extension>` Elements"
self.extdict = {}
"dictionary of FeatureInfo objects for `<extension>` elements keyed by extension name"
# A default output generator, so commands prior to apiGen can report
# errors via the generator object.
self.gen = OutputGenerator()
"OutputGenerator object used to write headers / messages"
self.genOpts = None
"""GeneratorOptions object used to control which
features to write and how to format them"""
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 generatng 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
['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.extdict = {}
# A default output generator, so commands prior to apiGen can report
# errors via the generator object.
self.gen = OutputGenerator()
self.genOpts = None
self.emitFeatures = False
self.breakPat = None
# self.breakPat = re.compile('VkFenceImportFlagBits.*')
self.filename = None
def loadElementTree(self, tree):
"""Load ElementTree into a Registry object and parse it"""
"""Load ElementTree into a Registry object and parse it."""
self.tree = tree
self.parseTree()
@ -300,20 +323,25 @@ class Registry:
self.parseTree()
def setGenerator(self, gen):
"""Specify output generator object. None restores the default generator"""
"""Specify output generator object.
`None` restores the default generator."""
self.gen = gen
self.gen.setRegistry(self)
# addElementInfo - add information about an element to the
# corresponding dictionary
# elem - <type>/<enums>/<enum>/<command>/<feature>/<extension> Element
# info - corresponding {Type|Group|Enum|Cmd|Feature}Info object
# infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension'
# dictionary - self.{type|group|enum|cmd|api|ext}dict
# If the Element has an 'api' attribute, the dictionary key is the
# tuple (name,api). If not, the key is the name. 'name' is an
# attribute of the Element
def addElementInfo(self, elem, info, infoName, dictionary):
"""Add information about an element to the corresponding dictionary.
Intended for internal use only.
- elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>` Element
- info - corresponding {Type|Group|Enum|Cmd|Feature}Info object
- infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension'
- dictionary - self.{type|group|enum|cmd|api|ext}dict
If the Element has an 'api' attribute, the dictionary key is the
tuple (name,api). If not, the key is the name. 'name' is an
attribute of the Element"""
# self.gen.logMsg('diag', 'Adding ElementInfo.required =',
# info.required, 'name =', elem.get('name'))
api = elem.get('api')
@ -333,11 +361,15 @@ class Registry:
else:
dictionary[key] = info
# lookupElementInfo - find a {Type|Enum|Cmd}Info object by name.
# If an object qualified by API name exists, use that.
# fname - name of type / enum / command
# dictionary - self.{type|enum|cmd}dict
def lookupElementInfo(self, fname, dictionary):
"""Find a {Type|Enum|Cmd}Info object by name.
Intended for internal use only.
If an object qualified by API name exists, use that.
- fname - name of type / enum / command
- dictionary - self.{type|enum|cmd}dict"""
key = (fname, self.genOpts.apiname)
if key in dictionary:
# self.gen.logMsg('diag', 'Found API-specific element for feature', fname)
@ -349,6 +381,7 @@ class Registry:
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):
@ -424,7 +457,7 @@ class Registry:
# name - if it exists.
for (name, alias, cmd) in cmdAlias:
if alias in self.cmddict:
#@ pdb.set_trace()
# @ pdb.set_trace()
aliasInfo = self.cmddict[alias]
cmdElem = copy.deepcopy(aliasInfo.elem)
cmdElem.find('proto/name').text = name
@ -434,11 +467,11 @@ class Registry:
# 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))
# @ 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)
cmd.get('name'), 'alias', alias)
# Create dictionaries of API and extension interfaces
# from toplevel <api> and <extension> tags.
@ -496,7 +529,7 @@ class Registry:
pass
else:
self.gen.logMsg('warn', 'NO matching group',
groupName, 'for enum', enum.get('name'), 'found.')
groupName, 'for enum', enum.get('name'), 'found.')
addEnumInfo = True
elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
# self.gen.logMsg('diag', 'Adding extension constant "enum"',
@ -550,7 +583,7 @@ class Registry:
pass
else:
self.gen.logMsg('warn', 'NO matching group',
groupName, 'for enum', enum.get('name'), 'found.')
groupName, 'for enum', enum.get('name'), 'found.')
addEnumInfo = True
elif enum.get('value') or enum.get('bitpos') or enum.get('alias'):
# self.gen.logMsg('diag', 'Adding extension constant "enum"',
@ -577,8 +610,11 @@ class Registry:
for parent in self.validextensionstructs:
self.validextensionstructs[parent].sort()
def dumpReg(self, maxlen = 120, filehandle = sys.stdout):
"""Dump all the dictionaries constructed from the Registry object"""
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)
@ -601,20 +637,18 @@ class Registry:
write('// APIs', file=filehandle)
for key in self.apidict:
write(' API Version ', key, '->',
etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle)
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('***************************************', file=filehandle)
# write(' ** Dumping XML ElementTree **', file=filehandle)
# write('***************************************', file=filehandle)
# write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle)
etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle)
# typename - name of type
# required - boolean (to tag features as required or not)
def markTypeRequired(self, typename, required):
"""Require (along with its dependencies) or remove (but not its dependencies) a type"""
"""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)
@ -623,11 +657,11 @@ class Registry:
# Tag type dependencies in 'alias' and 'required' attributes as
# required. This DOES NOT un-tag dependencies in a <remove>
# tag. See comments in markRequired() below for the reason.
for attrib_name in [ 'requires', 'alias' ]:
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)
depname, 'for', attrib_name, 'type', typename)
# Don't recurse on self-referential structures.
if typename != depname:
self.markTypeRequired(depname, required)
@ -654,7 +688,7 @@ class Registry:
depType = typeinfo.elem.get('bitvalues')
if depType:
self.gen.logMsg('diag', 'Generating bitflag type',
depType, 'for type', typename)
depType, 'for type', typename)
self.markTypeRequired(depType, required)
group = self.lookupElementInfo(depType, self.groupdict)
if group is not None:
@ -662,11 +696,13 @@ class Registry:
typeinfo.required = required
elif '.h' not in typename:
self.gen.logMsg('warn', 'type:', typename , 'IS NOT DEFINED')
self.gen.logMsg('warn', 'type:', typename, 'IS NOT DEFINED')
# enumname - name of enum
# required - boolean (to tag features as required or not)
def markEnumRequired(self, enumname, required):
"""Mark an enum as required or not.
- enumname - name of enum
- required - boolean (to tag features as required or not)"""
self.gen.logMsg('diag', 'tagging enum:', enumname, '-> required =', required)
enum = self.lookupElementInfo(enumname, self.enumdict)
if enum is not None:
@ -675,14 +711,16 @@ class Registry:
depname = enum.elem.get('alias')
if depname:
self.gen.logMsg('diag', 'Generating dependent enum',
depname, 'for alias', enumname, 'required =', enum.required)
depname, 'for alias', enumname, 'required =', enum.required)
self.markEnumRequired(depname, required)
else:
self.gen.logMsg('warn', 'enum:', enumname , 'IS NOT DEFINED')
self.gen.logMsg('warn', 'enum:', enumname, 'IS NOT DEFINED')
# cmdname - name of command
# required - boolean (to tag features as required or not)
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:
@ -691,7 +729,7 @@ class Registry:
depname = cmd.elem.get('alias')
if depname:
self.gen.logMsg('diag', 'Generating dependent command',
depname, 'for alias', cmdname)
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>
@ -707,11 +745,12 @@ class Registry:
else:
self.gen.logMsg('warn', 'command:', cmdname, 'IS NOT DEFINED')
# featurename - name of the feature
# feature - Element for <require> or <remove> tag
# required - boolean (to tag features as required or not)
def markRequired(self, featurename, feature, required):
"""Require or remove features specified in the Element"""
"""Require or remove features specified in the Element.
- 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
@ -745,13 +784,14 @@ class Registry:
else:
self.gen.logMsg('warn', 'extend type:', extendType, 'IS NOT SUPPORTED')
# 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
def requireAndRemoveFeatures(self, interface, featurename, api, profile):
"""Process <require> and <remove> tags for a <version> or <extension>"""
"""Process `<require>` and `<remove>` tags 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"""
# <require> marks things that are required by this version/profile
for feature in interface.findall('require'):
if matchAPIProfile(api, profile, feature):
@ -780,15 +820,16 @@ class Registry:
if v.get('struct'):
self.typedict[v.get('struct')].removedValidity.append(copy.deepcopy(v))
# generateFeature - generate a single type / enum group / enum / command,
# and all its dependencies as needed.
# fname - name of feature (<type>/<enum>/<command>)
# ftype - type of feature, 'type' | 'enum' | 'command'
# dictionary - of *Info objects - self.{type|enum|cmd}dict
def generateFeature(self, fname, ftype, dictionary):
#@ # Break to debugger on matching name pattern
#@ if self.breakPat and re.match(self.breakPat, fname):
#@ pdb.set_trace()
"""Generate a single type / enum group / enum / command,
and all its dependencies as needed.
- fname - name of feature (`<type>`/`<enum>`/`<command>`)
- ftype - type of feature, 'type' | 'enum' | 'command'
- dictionary - of *Info objects - self.{type|enum|cmd}dict"""
# @ # Break to debugger on matching name pattern
# @ if self.breakPat and re.match(self.breakPat, fname):
# @ pdb.set_trace()
self.gen.logMsg('diag', 'generateFeature: generating', ftype, fname)
f = self.lookupElementInfo(fname, dictionary)
@ -840,14 +881,14 @@ class Registry:
# not just immediate children
for subtype in f.elem.findall('.//type'):
self.gen.logMsg('diag', 'Generating required dependent <type>',
subtype.text)
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)
subtype.text)
self.generateFeature(subtype.text, 'enum', self.enumdict)
# If the type is an enum group, look up the corresponding
@ -866,22 +907,22 @@ class Registry:
f = self.lookupElementInfo(alias, self.groupdict)
elif group is None:
self.gen.logMsg('warn', 'Skipping enum type', fname,
': No matching enumerant group')
': No matching enumerant group')
return
else:
genProc = self.gen.genGroup
f = group
#@ The enum group is not ready for generation. At this
#@ point, it contains all <enum> tags injected by
#@ <extension> tags without any verification of whether
#@ they're required or not. It may also contain
#@ duplicates injected by multiple consistent
#@ definitions of an <enum>.
# @ The enum group is not ready for generation. At this
# @ point, it contains all <enum> tags injected by
# @ <extension> tags without any verification of whether
# @ they're required or not. It may also contain
# @ duplicates injected by multiple consistent
# @ definitions of an <enum>.
#@ Pass over each enum, marking its enumdict[] entry as
#@ required or not. Mark aliases of enums as required,
#@ too.
# @ Pass over each enum, marking its enumdict[] entry as
# @ required or not. Mark aliases of enums as required,
# @ too.
enums = group.elem.findall('enum')
@ -923,7 +964,7 @@ class Registry:
elem.set('required', 'true')
self.gen.logMsg('diag', '* also need to require alias', name)
if f.elem.get('category') == 'bitmask':
followupFeature = f.elem.get( 'bitvalues' )
followupFeature = f.elem.get('bitvalues')
elif ftype == 'command':
# Generate command dependencies in 'alias' attribute
if alias:
@ -949,16 +990,15 @@ class Registry:
self.gen.logMsg('diag', 'Skipping', ftype, fname,
'(should not be emitted)')
if followupFeature :
if followupFeature:
self.gen.logMsg('diag', 'Generating required bitvalues <enum>',
followupFeature)
followupFeature)
self.generateFeature(followupFeature, "type", self.typedict)
# generateRequiredInterface - generate all interfaces required
# by an API version or extension
# interface - Element for <version> or <extension>
def generateRequiredInterface(self, interface):
"""Generate required C interface for specified API version/extension"""
"""Generate all interfaces required by an API version or extension.
- interface - Element for `<version>` or `<extension>`"""
# Loop over all features inside all <require> tags.
for features in interface.findall('require'):
@ -969,12 +1009,11 @@ class Registry:
for c in features.findall('command'):
self.generateFeature(c.get('name'), 'command', self.cmddict)
# apiGen(genOpts) - generate interface for specified versions
# genOpts - GeneratorOptions object with parameters used
# by the Generator object.
def apiGen(self, genOpts):
"""Generate interfaces for the specified API type and range of versions"""
"""Generate interface for specified versions
- genOpts - GeneratorOptions object with parameters used
by the Generator object."""
self.gen.logMsg('diag', '*******************************************')
self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename,
'api:', genOpts.apiname,
@ -1009,20 +1048,20 @@ class Registry:
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)')
'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)')
'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)')
'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)')
'name =', fi.name,
'(does not match requested API)')
if not apiMatch:
self.gen.logMsg('warn', 'No matching API versions found!')
@ -1032,7 +1071,7 @@ class Registry:
# being generated. Add extensions matching the pattern specified in
# regExtensions, then remove extensions matching the pattern
# specified in regRemoveExtensions
for (extName,ei) in sorted(self.extdict.items(),key = lambda x : x[1].number if x[1].number is not None else '0'):
for (extName, ei) in sorted(self.extdict.items(), key=lambda x: x[1].number if x[1].number is not None else '0'):
extName = ei.name
include = False
@ -1041,10 +1080,10 @@ class Registry:
# 'supported' must exactly match defaultExtensions, so bracket
# it with ^(pat)$.
pat = '^(' + ei.elem.get('supported') + ')$'
if (self.genOpts.defaultExtensions and
re.match(pat, self.genOpts.defaultExtensions)):
if (self.genOpts.defaultExtensions
and re.match(pat, self.genOpts.defaultExtensions)):
self.gen.logMsg('diag', 'Including extension',
extName, "(defaultExtensions matches the 'supported' attribute)")
extName, "(defaultExtensions matches the 'supported' attribute)")
include = True
# Include additional extensions if the extension name matches
@ -1053,7 +1092,7 @@ class Registry:
# tagged appropriately in the registry.
if regAddExtensions.match(extName) is not None:
self.gen.logMsg('diag', 'Including extension',
extName, '(matches explicitly requested extensions to add)')
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
@ -1061,7 +1100,7 @@ class Registry:
# way in the registry.
if regRemoveExtensions.match(extName) is not None:
self.gen.logMsg('diag', 'Removing extension',
extName, '(matches explicitly requested extensions to remove)')
extName, '(matches explicitly requested extensions to remove)')
include = False
# If the extension is to be included, add it to the
@ -1071,8 +1110,8 @@ class Registry:
features.append(ei)
if not ei.emit:
self.gen.logMsg('diag', 'NOT tagging extension',
extName,
'for emission (does not match emitextensions pattern)')
extName,
'for emission (does not match emitextensions pattern)')
# Hack - can be removed when validity generator goes away
# (Jon) I'm not sure what this does, or if it should respect
@ -1080,7 +1119,7 @@ class Registry:
self.requiredextensions.append(extName)
else:
self.gen.logMsg('diag', 'NOT including extension',
extName, '(does not match api attribute or explicitly requested extensions)')
extName, '(does not match api attribute or explicitly requested extensions)')
# Sort the features list, if a sort procedure is defined
if self.genOpts.sortProcedure:
@ -1097,7 +1136,7 @@ class Registry:
self.gen.logMsg('diag', 'PASS 1: TAG FEATURES')
for f in features:
self.gen.logMsg('diag', 'PASS 1: Tagging required and removed features for',
f.name)
f.name)
self.requireAndRemoveFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile)
self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile)
@ -1108,11 +1147,11 @@ class Registry:
self.gen.beginFile(self.genOpts)
for f in features:
self.gen.logMsg('diag', 'PASS 2: Generating interface for',
f.name)
f.name)
emit = self.emitFeatures = f.emit
if not emit:
self.gen.logMsg('diag', 'PASS 2: NOT declaring feature',
f.elem.get('name'), 'because it is not tagged for emission')
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 haven't been).
self.gen.beginFeature(f.elem, emit)
@ -1120,9 +1159,10 @@ class Registry:
self.gen.endFeature()
self.gen.endFile()
# apiReset - use between apiGen() calls to reset internal state
def apiReset(self):
"""Reset type/enum/command dictionaries before generating another API"""
"""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:
@ -1132,9 +1172,10 @@ class Registry:
for cmd in self.apidict:
self.apidict[cmd].resetState()
# validateGroups - check that group= attributes match actual groups
def validateGroups(self):
"""Validate group= attributes on <param> and <proto> tags"""
"""Validate `group=` attributes on `<param>` and `<proto>` tags.
Check that `group=` attributes match actual groups"""
# Keep track of group names not in <group> tags
badGroup = {}
self.gen.logMsg('diag', 'VALIDATING GROUP ATTRIBUTES')
@ -1147,7 +1188,7 @@ class Registry:
if group not in badGroup:
badGroup[group] = 1
else:
badGroup[group] = badGroup[group] + 1
badGroup[group] = badGroup[group] + 1
for param in cmd.findall('param'):
pname = param.find('name')
@ -1161,7 +1202,7 @@ class Registry:
if group not in badGroup:
badGroup[group] = 1
else:
badGroup[group] = badGroup[group] + 1
badGroup[group] = badGroup[group] + 1
if badGroup:
self.gen.logMsg('diag', 'SUMMARY OF UNRECOGNIZED GROUPS')

View file

@ -1,9 +1,9 @@
{
"version info": {
"schema version": 2,
"api version": "1.1.121",
"comment": "from git branch: github-master commit: 59750fe4c72a9295a94e22474060d3a1635e92c8",
"date": "2019-08-25 10:57:34Z"
"api version": "1.1.122",
"comment": "from git branch: github-master commit: 194a7f4d0d552e78d6f1a2fa2ae0ddbe0215090a",
"date": "2019-09-09 03:41:35Z"
},
"validation": {
"vkGetInstanceProcAddr": {
@ -4062,7 +4062,7 @@
},
{
"vuid": "VUID-VkFramebufferCreateInfo-pAttachments-00880",
"text": " If <code>flags</code> does not include <code>VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR</code>, each element of <code>pAttachments</code> <strong class=\"purple\">must</strong> have been created with an <a href=\"#VkFormat\">VkFormat</a> value that matches the <a href=\"#VkFormat\">VkFormat</a> specified by the corresponding <code>VkAttachmentDescription</code> in <code>renderPass</code>"
"text": " If <code>flags</code> does not include <code>VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR</code>, each element of <code>pAttachments</code> <strong class=\"purple\">must</strong> have been created with a <a href=\"#VkFormat\">VkFormat</a> value that matches the <a href=\"#VkFormat\">VkFormat</a> specified by the corresponding <code>VkAttachmentDescription</code> in <code>renderPass</code>"
},
{
"vuid": "VUID-VkFramebufferCreateInfo-pAttachments-00881",
@ -4940,7 +4940,7 @@
"(VK_NV_glsl_shader)": [
{
"vuid": "VUID-VkShaderModuleCreateInfo-pCode-01376",
"text": " If <code>pCode</code> points to SPIR-V code, <code>codeSize</code> <strong class=\"purple\">must</strong> be a multiple of 4"
"text": " If <code>pCode</code> is a pointer to SPIR-V code, <code>codeSize</code> <strong class=\"purple\">must</strong> be a multiple of 4"
},
{
"vuid": "VUID-VkShaderModuleCreateInfo-pCode-01377",
@ -4948,11 +4948,11 @@
},
{
"vuid": "VUID-VkShaderModuleCreateInfo-pCode-01378",
"text": " If <code>pCode</code> points to SPIR-V code, that code <strong class=\"purple\">must</strong> adhere to the validation rules described by the <a href=\"#spirvenv-module-validation\">Validation Rules within a Module</a> section of the <a href=\"#spirvenv-capabilities\">SPIR-V Environment</a> appendix"
"text": " If <code>pCode</code> is a pointer to SPIR-V code, that code <strong class=\"purple\">must</strong> adhere to the validation rules described by the <a href=\"#spirvenv-module-validation\">Validation Rules within a Module</a> section of the <a href=\"#spirvenv-capabilities\">SPIR-V Environment</a> appendix"
},
{
"vuid": "VUID-VkShaderModuleCreateInfo-pCode-01379",
"text": " If <code>pCode</code> points to GLSL code, it <strong class=\"purple\">must</strong> be valid GLSL code written to the <code>GL_KHR_vulkan_glsl</code> GLSL extension specification"
"text": " If <code>pCode</code> is a pointer to GLSL code, it <strong class=\"purple\">must</strong> be valid GLSL code written to the <code>GL_KHR_vulkan_glsl</code> GLSL extension specification"
}
]
},
@ -8477,12 +8477,20 @@
],
"(VK_EXT_separate_stencil_usage)": [
{
"vuid": "VUID-VkImageCreateInfo-format-02534",
"text": " If <code>format</code> is a depth-stencil format and the <code>pNext</code> chain contains an instance of <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>, then its <code>stencilUsage</code> member <strong class=\"purple\">must</strong> only include <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code> if <code>usage</code> also includes it"
"vuid": "VUID-VkImageCreateInfo-format-02795",
"text": " If <code>format</code> is a depth-stencil format, <code>usage</code> includes <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code>, and the <code>pNext</code> chain contains an instance of <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>, then <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>::<code>stencilUsage</code> member <strong class=\"purple\">must</strong> also include <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code>"
},
{
"vuid": "VUID-VkImageCreateInfo-format-02535",
"text": " If <code>format</code> is a depth-stencil format and the <code>pNext</code> chain contains an instance of <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>, then its <code>stencilUsage</code> member <strong class=\"purple\">must</strong> only include <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code> if <code>usage</code> also includes it"
"vuid": "VUID-VkImageCreateInfo-format-02796",
"text": " If <code>format</code> is a depth-stencil format, <code>usage</code> does not include <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code>, and the <code>pNext</code> chain contains an instance of <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>, then <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>::<code>stencilUsage</code> member <strong class=\"purple\">must</strong> also not include <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code>"
},
{
"vuid": "VUID-VkImageCreateInfo-format-02797",
"text": " If <code>format</code> is a depth-stencil format, <code>usage</code> includes <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code>, and the <code>pNext</code> chain contains an instance of <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>, then <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>::<code>stencilUsage</code> member <strong class=\"purple\">must</strong> also include <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code>"
},
{
"vuid": "VUID-VkImageCreateInfo-format-02798",
"text": " If <code>format</code> is a depth-stencil format, <code>usage</code> does not include <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code>, and the <code>pNext</code> chain contains an instance of <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>, then <a href=\"#VkImageStencilUsageCreateInfoEXT\">VkImageStencilUsageCreateInfoEXT</a>::<code>stencilUsage</code> member <strong class=\"purple\">must</strong> also not include <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code>"
},
{
"vuid": "VUID-VkImageCreateInfo-Format-02536",
@ -8534,7 +8542,7 @@
"(VK_EXT_separate_stencil_usage)": [
{
"vuid": "VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-02539",
"text": " If <code>stencilUsage</code> includes <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code>, then bits other than <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code>, and <code>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</code> <strong class=\"purple\">must</strong> not be set"
"text": " If <code>stencilUsage</code> includes <code>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</code>, it <strong class=\"purple\">must</strong> not include bits other than <code>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</code> or <code>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</code>"
},
{
"vuid": "VUID-VkImageStencilUsageCreateInfoEXT-sType-sType",
@ -9054,7 +9062,7 @@
"(VK_KHR_image_format_list)": [
{
"vuid": "VUID-VkImageViewCreateInfo-pNext-01585",
"text": " If a <code>VkImageFormatListCreateInfoKHR</code> structure was included in the <code>pNext</code> chain of the <code>VkImageCreateInfo</code> struct used when creating <code>image</code> and the <code>viewFormatCount</code> field of <code>VkImageFormatListCreateInfoKHR</code> is not zero then <code>format</code> <strong class=\"purple\">must</strong> be one of the formats in <code>VkImageFormatListCreateInfoKHR</code>::<code>pViewFormats</code>."
"text": " If a <code>VkImageFormatListCreateInfoKHR</code> structure was included in the <code>pNext</code> chain of the <code>VkImageCreateInfo</code> structure used when creating <code>image</code> and the <code>viewFormatCount</code> field of <code>VkImageFormatListCreateInfoKHR</code> is not zero then <code>format</code> <strong class=\"purple\">must</strong> be one of the formats in <code>VkImageFormatListCreateInfoKHR</code>::<code>pViewFormats</code>."
}
],
"(VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion)": [
@ -10020,11 +10028,11 @@
},
{
"vuid": "VUID-VkBindImageMemoryDeviceGroupInfo-extent-01640",
"text": " The <code>extent.width</code> member of any element of <code>pSplitInstanceBindRegions</code> <strong class=\"purple\">must</strong> either be a multiple of the sparse image block width of all non-metadata aspects of the image, or else <code>extent.width</code> + <code>offset.x</code> <strong class=\"purple\">must</strong> equal the width of the image subresource"
"text": " The <code>extent.width</code> member of any element of <code>pSplitInstanceBindRegions</code> <strong class=\"purple\">must</strong> either be a multiple of the sparse image block width of all non-metadata aspects of the image, or else <code>extent.width</code> &#43; <code>offset.x</code> <strong class=\"purple\">must</strong> equal the width of the image subresource"
},
{
"vuid": "VUID-VkBindImageMemoryDeviceGroupInfo-extent-01641",
"text": " The <code>extent.height</code> member of any element of <code>pSplitInstanceBindRegions</code> <strong class=\"purple\">must</strong> either be a multiple of the sparse image block height of all non-metadata aspects of the image, or else <code>extent.height</code><br> <code>offset.y</code> <strong class=\"purple\">must</strong> equal the width of the image subresource"
"text": " The <code>extent.height</code> member of any element of <code>pSplitInstanceBindRegions</code> <strong class=\"purple\">must</strong> either be a multiple of the sparse image block height of all non-metadata aspects of the image, or else <code>extent.height</code> &#43; <code>offset.y</code> <strong class=\"purple\">must</strong> equal the width of the image subresource"
},
{
"vuid": "VUID-VkBindImageMemoryDeviceGroupInfo-sType-sType",
@ -12216,7 +12224,7 @@
"(VK_VERSION_1_1,VK_KHR_descriptor_update_template)": [
{
"vuid": "VUID-vkUpdateDescriptorSetWithTemplate-pData-01685",
"text": " <code>pData</code> <strong class=\"purple\">must</strong> be a valid pointer to a memory that contains one or more valid instances of <a href=\"#VkDescriptorImageInfo\">VkDescriptorImageInfo</a>, <a href=\"#VkDescriptorBufferInfo\">VkDescriptorBufferInfo</a>, or <a href=\"#VkBufferView\">VkBufferView</a> in a layout defined by <code>descriptorUpdateTemplate</code> when it was created with <a href=\"#vkCreateDescriptorUpdateTemplate\">vkCreateDescriptorUpdateTemplate</a>"
"text": " <code>pData</code> <strong class=\"purple\">must</strong> be a valid pointer to a memory containing one or more valid instances of <a href=\"#VkDescriptorImageInfo\">VkDescriptorImageInfo</a>, <a href=\"#VkDescriptorBufferInfo\">VkDescriptorBufferInfo</a>, or <a href=\"#VkBufferView\">VkBufferView</a> in a layout defined by <code>descriptorUpdateTemplate</code> when it was created with <a href=\"#vkCreateDescriptorUpdateTemplate\">vkCreateDescriptorUpdateTemplate</a>"
},
{
"vuid": "VUID-vkUpdateDescriptorSetWithTemplate-device-parameter",
@ -12360,7 +12368,7 @@
},
{
"vuid": "VUID-vkCmdPushDescriptorSetWithTemplateKHR-pData-01686",
"text": " <code>pData</code> <strong class=\"purple\">must</strong> be a valid pointer to a memory that contains one or more valid instances of <a href=\"#VkDescriptorImageInfo\">VkDescriptorImageInfo</a>, <a href=\"#VkDescriptorBufferInfo\">VkDescriptorBufferInfo</a>, or <a href=\"#VkBufferView\">VkBufferView</a> in a layout defined by <code>descriptorUpdateTemplate</code> when it was created with <a href=\"#vkCreateDescriptorUpdateTemplateKHR\">vkCreateDescriptorUpdateTemplateKHR</a>"
"text": " <code>pData</code> <strong class=\"purple\">must</strong> be a valid pointer to a memory containing one or more valid instances of <a href=\"#VkDescriptorImageInfo\">VkDescriptorImageInfo</a>, <a href=\"#VkDescriptorBufferInfo\">VkDescriptorBufferInfo</a>, or <a href=\"#VkBufferView\">VkBufferView</a> in a layout defined by <code>descriptorUpdateTemplate</code> when it was created with <a href=\"#vkCreateDescriptorUpdateTemplateKHR\">vkCreateDescriptorUpdateTemplateKHR</a>"
},
{
"vuid": "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-parameter",

View file

@ -154,7 +154,7 @@ server.
<type category="define">// Vulkan 1.1 version number
#define <name>VK_API_VERSION_1_1</name> <type>VK_MAKE_VERSION</type>(1, 1, 0)// Patch version should always be set to 0</type>
<type category="define">// Version of this file
#define <name>VK_HEADER_VERSION</name> 121</type>
#define <name>VK_HEADER_VERSION</name> 122</type>
<type category="define">
#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
@ -8881,7 +8881,7 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceMultiviewPropertiesKHR"/>
</require>
</extension>
<extension name="VK_IMG_format_pvrtc" number="55" type="device" author="IMG" contact="Tobias Hector @tobski" supported="vulkan">
<extension name="VK_IMG_format_pvrtc" number="55" type="device" author="IMG" contact="Stuart Smith" supported="vulkan">
<require>
<enum value="1" name="VK_IMG_FORMAT_PVRTC_SPEC_VERSION"/>
<enum value="&quot;VK_IMG_format_pvrtc&quot;" name="VK_IMG_FORMAT_PVRTC_EXTENSION_NAME"/>
@ -9028,9 +9028,9 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkAcquireNextImage2KHR"/>
</require>
</extension>
<extension name="VK_EXT_validation_flags" number="62" type="instance" author="GOOGLE" contact="Tobin Ehlis @tobine" supported="vulkan">
<extension name="VK_EXT_validation_flags" number="62" type="instance" author="GOOGLE" contact="Tobin Ehlis @tobine" supported="vulkan" deprecatedby="VK_EXT_validation_features">
<require>
<enum value="1" name="VK_EXT_VALIDATION_FLAGS_SPEC_VERSION"/>
<enum value="2" name="VK_EXT_VALIDATION_FLAGS_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_validation_flags&quot;" name="VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT"/>
<type name="VkValidationFlagsEXT"/>
@ -11264,7 +11264,7 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_EXT_headless_surface" number="257" type="instance" requires="VK_KHR_surface" author="EXT" contact="Ray Smith @raysmith-arm" supported="vulkan">
<require>
<enum value="0" name="VK_EXT_HEADLESS_SURFACE_SPEC_VERSION"/>
<enum value="1" name="VK_EXT_HEADLESS_SURFACE_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_headless_surface&quot;" name="VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT"/>
<type name="VkHeadlessSurfaceCreateFlagsEXT"/>

View file

@ -25,6 +25,31 @@ from 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
'8Bit', # VkPhysicalDevice8BitStorageFeaturesKHR
'AABB', # VkGeometryAABBNV
'ASTC', # VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT
'D3D12', # VkD3D12FenceSubmitInfoKHR
'Float16', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
'ImagePipe', # VkImagePipeSurfaceCreateInfoFUCHSIA
'Int64', # VkPhysicalDeviceShaderAtomicInt64FeaturesKHR
'Int8', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
'MacOS', # VkMacOSSurfaceCreateInfoMVK
'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):
def formatExtension(self, name):
@ -68,11 +93,12 @@ class VulkanConventions(ConventionsBase):
"""Generate a structure type name, like VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO"""
structure_type_parts = []
# Tokenize into "words"
for elem in re.findall(r'(([A-Z][a-z]+)|([A-Z][A-Z]+))', structname):
if elem[0] == 'Vk':
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(elem[0].upper())
structure_type_parts.append(word.upper())
return '_'.join(structure_type_parts)
@property
@ -172,7 +198,7 @@ class VulkanConventions(ConventionsBase):
@property
def unified_flag_refpages(self):
"""Returns True if Flags/FlagBits refpages are unified, False if
"""Return True if Flags/FlagBits refpages are unified, False if
they're separate.
"""
return False
@ -198,3 +224,16 @@ class VulkanConventions(ConventionsBase):
Overridden because Vulkan doesn't 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