Update for Vulkan-Docs 1.4.319

This commit is contained in:
Jon Leech 2025-06-20 13:17:34 +01:00 committed by Jon Leech
parent b39ab380a4
commit 10739e8e00
38 changed files with 184363 additions and 135674 deletions

View file

@ -9,7 +9,7 @@ import os
import tempfile
from vulkan_object import (VulkanObject,
Extension, Version, Deprecate, Handle, Param, Queues, CommandScope, Command,
EnumField, Enum, Flag, Bitmask, Flags, Member, Struct,
EnumField, Enum, Flag, Bitmask, ExternSync, Flags, Member, Struct,
FormatComponent, FormatPlane, Format,
SyncSupport, SyncEquivalent, SyncStage, SyncAccess, SyncPipelineStage, SyncPipeline,
SpirvEnables, Spirv)
@ -35,6 +35,30 @@ def intIfGet(elem, name):
def boolGet(elem, name) -> bool:
return elem.get(name) is not None and elem.get(name) == "true"
def externSyncGet(elem):
value = elem.get('externsync')
if value is None:
return (ExternSync.NONE, None)
if value == 'true':
return (ExternSync.ALWAYS, None)
if value == 'maybe':
return (ExternSync.MAYBE, None)
# There are no cases where multiple members of the param are marked as
# externsync. Supporting that with maybe: requires more than
# ExternSync.SUBTYPE_MAYBE (which is only one bit of information), which is
# not currently done as there are no users.
#
# If this assert is hit, please consider simplifying the design such that
# externsync can move to the struct itself and so external synchronization
# requirements do not depend on the context.
assert ',' not in value
if value.startswith('maybe:'):
return (ExternSync.SUBTYPE_MAYBE, value.removeprefix('maybe:'))
return (ExternSync.SUBTYPE, value)
def getQueues(elem) -> Queues:
queues = 0
queues_list = splitIfGet(elem, 'queues')
@ -139,6 +163,10 @@ class BaseGenerator(OutputGenerator):
self.currentExtension = None
self.currentVersion = None
# We need to flag extensions that we ignore because they are disabled or not
# supported in the target API(s)
self.unsupportedExtension = False
# Will map alias to promoted name
# ex. ['VK_FILTER_CUBIC_IMG' : 'VK_FILTER_CUBIC_EXT']
# When generating any code, there is no reason so use the old name
@ -437,6 +465,17 @@ class BaseGenerator(OutputGenerator):
name = interface.get('name')
if interface.tag == 'extension':
# Generator scripts built on BaseGenerator do not handle the `supported` attribute of extensions
# therefore historically the `generate_source.py` in individual ecosystem components hacked the
# registry by removing non-applicable or disabled extensions from the loaded XML already before
# reg.py parsed it. That broke the general behavior of reg.py for certain use cases so we now
# filter extensions here instead (after parsing) in order to no longer need the filtering hack
# in downstream `generate_source.py` scripts.
enabledApiList = [ globalApiName ] + ([] if mergedApiNames is None else mergedApiNames.split(','))
if (sup := interface.get('supported')) is not None and all(api not in sup.split(',') for api in enabledApiList):
self.unsupportedExtension = True
return
instance = interface.get('type') == 'instance'
device = not instance
depends = interface.get('depends')
@ -468,12 +507,17 @@ class BaseGenerator(OutputGenerator):
OutputGenerator.endFeature(self)
self.currentExtension = None
self.currentVersion = None
self.unsupportedExtension = False
#
# All <command> from XML
def genCmd(self, cmdinfo, name, alias):
OutputGenerator.genCmd(self, cmdinfo, name, alias)
# Do not include APIs from unsupported extensions
if self.unsupportedExtension:
return
params = []
for param in cmdinfo.elem.findall('param'):
paramName = param.find('name').text
@ -505,12 +549,8 @@ class BaseGenerator(OutputGenerator):
optional = optionalValues is not None and optionalValues[0].lower() == "true"
optionalPointer = optionalValues is not None and len(optionalValues) > 1 and optionalValues[1].lower() == "true"
# externsync will be 'true' or expression
# if expression, it should be same as 'true'
externSync = boolGet(param, 'externsync')
externSyncPointer = None if externSync else splitIfGet(param, 'externsync')
if not externSync and externSyncPointer is not None:
externSync = True
# externsync will be 'true', 'maybe', '<expression>' or 'maybe:<expression>'
(externSync, externSyncPointer) = externSyncGet(param)
params.append(Param(paramName, paramAlias, paramType, paramFullType, paramNoautovalidity,
paramConst, length, nullTerminated, pointer, fixedSizeArray,
@ -566,6 +606,10 @@ class BaseGenerator(OutputGenerator):
# List the enum for the commands
# TODO - Seems empty groups like `VkDeviceDeviceMemoryReportCreateInfoEXT` do not show up in here
def genGroup(self, groupinfo, groupName, alias):
# Do not include APIs from unsupported extensions
if self.unsupportedExtension:
return
# There can be case where the Enum/Bitmask is in a protect, but the individual
# fields also have their own protect
groupProtect = self.currentExtension.protect if hasattr(self.currentExtension, 'protect') and self.currentExtension.protect is not None else None
@ -580,6 +624,15 @@ class BaseGenerator(OutputGenerator):
for elem in enumElem.findall('enum'):
fieldName = elem.get('name')
# Do not include non-required enum constants
# reg.py emits the enum constants of the entire type, even constants that are part of unsupported
# extensions or those that are removed by <remove> elements in a given API. reg.py correctly tracks
# down these and also alias dependencies and marks the enum constants that are actually required
# with the 'required' attribute. Therefore we also have to verify that here to make sure we only
# include enum constants that are actually required in the target API(s).
if elem.get('required') is None:
continue
if elem.get('alias') is not None:
self.enumFieldAliasMap[fieldName] = elem.get('alias')
continue
@ -604,6 +657,15 @@ class BaseGenerator(OutputGenerator):
for elem in enumElem.findall('enum'):
flagName = elem.get('name')
# Do not include non-required enum constants
# reg.py emits the enum constants of the entire type, even constants that are part of unsupported
# extensions or those that are removed by <remove> elements in a given API. reg.py correctly tracks
# down these and also alias dependencies and marks the enum constants that are actually required
# with the 'required' attribute. Therefore we also have to verify that here to make sure we only
# include enum constants that are actually required in the target API(s).
if elem.get('required') is None:
continue
if elem.get('alias') is not None:
self.flagAliasMap[flagName] = elem.get('alias')
continue
@ -628,6 +690,11 @@ class BaseGenerator(OutputGenerator):
def genType(self, typeInfo, typeName, alias):
OutputGenerator.genType(self, typeInfo, typeName, alias)
# Do not include APIs from unsupported extensions
if self.unsupportedExtension:
return
typeElem = typeInfo.elem
protect = self.currentExtension.protect if hasattr(self.currentExtension, 'protect') and self.currentExtension.protect is not None else None
extension = [self.currentExtension] if self.currentExtension is not None else []
@ -656,10 +723,13 @@ class BaseGenerator(OutputGenerator):
name = textIfFind(member, 'name')
type = textIfFind(member, 'type')
sType = member.get('values') if member.get('values') is not None else sType
externSync = boolGet(member, 'externsync')
noautovalidity = boolGet(member, 'noautovalidity')
limittype = member.get('limittype')
(externSync, externSyncPointer) = externSyncGet(member)
# No cases currently where a subtype of a struct is marked as externally synchronized.
assert externSyncPointer is None
nullTerminated = False
length = member.get('altlen') if member.get('altlen') is not None else member.get('len')
if length:

View file

@ -27,6 +27,8 @@ class CGeneratorOptions(GeneratorOptions):
protectProtoStr=None,
protectExtensionProto=None,
protectExtensionProtoStr=None,
protectExportName=None,
protectExportProtoStr=None,
apicall='',
apientry='',
apientryp='',
@ -66,6 +68,12 @@ class CGeneratorOptions(GeneratorOptions):
set to None
- protectExtensionProtoStr - #ifdef/#ifndef symbol to use around
extension prototype declarations, if protectExtensionProto is set
- protectExportName - name used to determine if a command is
exported matching an entry in the XML 'export' attribute.
Set to None if no matching should be done.
- protectExportProtoStr - #ifndef symbol to use around prototypes
for commands that are not exported.
Set to None if no protection is wanted.
- apicall - string to use for the function declaration prefix,
such as APICALL on Windows
- apientry - string to use for the calling convention macro,
@ -115,6 +123,12 @@ class CGeneratorOptions(GeneratorOptions):
self.protectExtensionProtoStr = protectExtensionProtoStr
"""#ifdef/#ifndef symbol to use around extension prototype declarations, if protectExtensionProto is set"""
self.protectExportName = protectExportName
"""Export name for commands which are exported"""
self.protectExportProtoStr = protectExportProtoStr
"""#ifndef symbol to use around prototypes for commands which are not exported"""
self.apicall = apicall
"""string to use for the function declaration prefix, such as APICALL on Windows."""
@ -507,6 +521,23 @@ class COutputGenerator(OutputGenerator):
prefix = ''
decls = self.makeCDecls(cmdinfo.elem)
# If the 'export' attribute is not set for this command, or does not
# match the export name selected during generation, wrap the command
# prototype in a C conditional which can be enabled to make the
# prototype not appear at compile time.
export = cmdinfo.elem.get('export','')
protect_prefix = protect_suffix = ''
if export is None or self.genOpts.protectExportName not in export.split(','):
if self.genOpts.protectExportProtoStr is not None:
# Command is not exported, so should not be visible if
# suppressed by this symbol
protect_prefix = f'#ifndef {self.genOpts.protectExportProtoStr}\n'
protect_suffix = '\n#endif'
decls[0] = protect_prefix + decls[0] + protect_suffix
self.appendSection('command', f"{prefix + decls[0]}\n")
if self.genOpts.genFuncPointers:
self.appendSection('commandPointer', decls[1])

View file

@ -1413,6 +1413,7 @@ class OutputGenerator:
else:
paramdecl += 'void'
paramdecl += ");"
return [pdecl + indentdecl, tdecl + paramdecl]
def newline(self):

View file

@ -210,7 +210,7 @@ class BaseInfo:
self.elem = elem
"etree Element for this feature"
self.deprecatedbyversion = None
self.deprecatedbyextensions = []
self.deprecatedlink = None
@ -353,7 +353,7 @@ class FeatureInfo(BaseInfo):
self.number = 0
self.supported = None
self.deprecates = elem.findall('deprecate')
else:
# Extract vendor portion of <APIprefix>_<vendor>_<name>
@ -688,6 +688,9 @@ class Registry:
# Now loop over aliases, injecting a copy of the aliased command's
# Element with the aliased prototype name replaced with the command
# name - if it exists.
# Copy the 'export' sttribute (whether it exists or not) from the
# original, aliased command, since that can be different for a
# command and its alias.
for (name, alias, cmd) in cmdAlias:
if alias in self.cmddict:
aliasInfo = self.cmddict[alias]
@ -695,6 +698,14 @@ class Registry:
cmdElem.find('proto/name').text = name
cmdElem.set('name', name)
cmdElem.set('alias', alias)
export = cmd.get('export')
if export is not None:
# Replicate the command's 'export' attribute
cmdElem.set('export', export)
elif cmdElem.get('export') is not None:
# Remove the 'export' attribute, if the alias has one but
# the command does not.
del cmdElem.attrib['export']
ci = CmdInfo(cmdElem)
# Replace the dictionary entry for the CmdInfo element
self.cmddict[name] = ci
@ -1264,7 +1275,7 @@ class Registry:
- featurename - name of the feature
- api - string specifying API name being generated
- profile - string specifying API profile being generated"""
versionmatch = APIConventions().is_api_version_name(featurename)
# <deprecate> marks things that are deprecated by this version/profile

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -81,6 +81,13 @@ class Handle:
def __lt__(self, other):
return self.name < other.name
class ExternSync(Enum):
NONE = auto() # no externsync attribute
ALWAYS = auto() # externsync="true"
MAYBE = auto() # externsync="maybe"
SUBTYPE = auto() # externsync="param->member"
SUBTYPE_MAYBE = auto() # externsync="maybe:param->member"
@dataclass
class Param:
"""<command/param>"""
@ -110,8 +117,9 @@ class Param:
optional: bool
optionalPointer: bool # if type contains a pointer, is the pointer value optional
externSync: bool
externSyncPointer: list[str] # if type contains a pointer, might only specific members modified
externSync: ExternSync
externSyncPointer: (str | None) # if type contains a pointer (externSync is SUBTYPE*),
# only a specific member is externally synchronized.
# C string of member, example:
# - const void* pNext
@ -217,7 +225,7 @@ class Member:
optional: bool
optionalPointer: bool # if type contains a pointer, is the pointer value optional
externSync: bool
externSync: ExternSync
# C string of member, example:
# - const void* pNext