blob: ac80be1d8a00ffe8ac747f95615a2faad5ffaa38 [file] [log] [blame]
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------
# Vulkan CTS
# ----------
#
# Copyright (c) 2015 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
#
#-------------------------------------------------------------------------
import os
import re
import sys
import glob
import json
import argparse
import datetime
import collections
from lxml import etree
scriptPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts")
sys.path.insert(0, scriptPath)
from ctsbuild.common import DEQP_DIR, execute
from khr_util.format import indentLines, writeInlFile
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "scripts"))
from reg import stripNonmatchingAPIs
VULKAN_XML_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "xml")
SCRIPTS_SRC_DIR = os.path.join(os.path.dirname(__file__), "src")
DEFAULT_OUTPUT_DIR = { "" : os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkan"),
"SC" : os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkansc") }
INL_HEADER = """\
/* WARNING: This is auto-generated file. Do not modify, since changes will
* be lost! Modify the generating script instead.
* This file was generated by /scripts/gen_framework.py
*/\
"""
DEFINITIONS = {
"VK_MAX_PHYSICAL_DEVICE_NAME_SIZE": "size_t",
"VK_MAX_EXTENSION_NAME_SIZE": "size_t",
"VK_MAX_DRIVER_NAME_SIZE": "size_t",
"VK_MAX_DRIVER_INFO_SIZE": "size_t",
"VK_UUID_SIZE": "size_t",
"VK_LUID_SIZE": "size_t",
"VK_MAX_MEMORY_TYPES": "size_t",
"VK_MAX_MEMORY_HEAPS": "size_t",
"VK_MAX_DESCRIPTION_SIZE": "size_t",
"VK_MAX_DEVICE_GROUP_SIZE": "size_t",
"VK_ATTACHMENT_UNUSED": "uint32_t",
"VK_SUBPASS_EXTERNAL": "uint32_t",
"VK_QUEUE_FAMILY_IGNORED": "uint32_t",
"VK_QUEUE_FAMILY_EXTERNAL": "uint32_t",
"VK_REMAINING_MIP_LEVELS": "uint32_t",
"VK_REMAINING_ARRAY_LAYERS": "uint32_t",
"VK_WHOLE_SIZE": "vk::VkDeviceSize",
"VK_TRUE": "vk::VkBool32",
"VK_FALSE": "vk::VkBool32",
}
PLATFORM_TYPES = [
# VK_KHR_xlib_surface
(["Display","*"], ["XlibDisplayPtr"], "void*"),
(["Window"], ["XlibWindow"], "uintptr_t",),
(["VisualID"], ["XlibVisualID"], "uint32_t"),
# VK_KHR_xcb_surface
(["xcb_connection_t", "*"], ["XcbConnectionPtr"], "void*"),
(["xcb_window_t"], ["XcbWindow"], "uintptr_t"),
(["xcb_visualid_t"], ["XcbVisualid"], "uint32_t"),
# VK_KHR_wayland_surface
(["struct", "wl_display","*"], ["WaylandDisplayPtr"], "void*"),
(["struct", "wl_surface", "*"], ["WaylandSurfacePtr"], "void*"),
# VK_KHR_mir_surface
(["MirConnection", "*"], ["MirConnectionPtr"], "void*"),
(["MirSurface", "*"], ["MirSurfacePtr"], "void*"),
# VK_KHR_android_surface
(["ANativeWindow", "*"], ["AndroidNativeWindowPtr"], "void*"),
# VK_KHR_win32_surface
(["HINSTANCE"], ["Win32InstanceHandle"], "void*"),
(["HWND"], ["Win32WindowHandle"], "void*"),
(["HANDLE"], ["Win32Handle"], "void*"),
(["const", "SECURITY_ATTRIBUTES", "*"], ["Win32SecurityAttributesPtr"], "const void*"),
(["AHardwareBuffer", "*"], ["AndroidHardwareBufferPtr"], "void*"),
(["HMONITOR"], ["Win32MonitorHandle"], "void*"),
(["LPCWSTR"], ["Win32LPCWSTR"], "const void*"),
# VK_EXT_acquire_xlib_display
(["RROutput"], ["RROutput"], "void*"),
(["zx_handle_t"], ["zx_handle_t"], "uint32_t"),
(["GgpFrameToken"], ["GgpFrameToken"], "int32_t"),
(["GgpStreamDescriptor"], ["GgpStreamDescriptor"], "int32_t"),
(["CAMetalLayer"], ["CAMetalLayer"], "void*"),
(["struct", "_screen_context", "*"], ["QNXScreenContextPtr"], "void*"),
(["struct", "_screen_window", "*"], ["QNXScreenWindowPtr"], "void*"),
# VK_EXT_metal_objects
(["MTLDevice_id"], ["MTLDevice_id"], "void*"),
(["MTLCommandQueue_id"], ["MTLCommandQueue_id"], "void*"),
(["MTLBuffer_id"], ["MTLBuffer_id"], "void*"),
(["MTLTexture_id"], ["MTLTexture_id"], "void*"),
(["IOSurfaceRef"], ["IOSurfaceRef"], "void*"),
(["MTLSharedEvent_id"], ["MTLSharedEvent_id"], "void*"),
# VK_NV_external_sci_sync
(["NvSciBufObj"], ["NvSciBufObj"], "int"),
(["NvSciSyncObj"], ["NvSciSyncObj"], "int"),
(["NvSciSyncFence"], ["NvSciSyncFence"], "int"),
(["NvSciBufAttrList"], ["NvSciBufAttrList"], "int"),
(["NvSciSyncAttrList"], ["NvSciSyncAttrList"], "int"),
]
PLATFORM_TYPE_NAMESPACE = "pt"
TYPE_SUBSTITUTIONS = [
# Platform-specific
("DWORD", "uint32_t"),
("HANDLE*", PLATFORM_TYPE_NAMESPACE + "::" + "Win32Handle*"),
]
EXTENSION_POSTFIXES_STANDARD = ["KHR", "EXT"]
EXTENSION_POSTFIXES_VENDOR = ["AMD", "ARM", "NV", 'INTEL', "NVX", "KHX", "NN", "MVK", "FUCHSIA", 'QCOM', "GGP", "QNX", "ANDROID", 'VALVE', 'HUAWEI']
EXTENSION_POSTFIXES = EXTENSION_POSTFIXES_STANDARD + EXTENSION_POSTFIXES_VENDOR
def substituteType(object): # both CompositeMember and FunctionArgument can be passed to this function
for src, dst in TYPE_SUBSTITUTIONS:
object.type = object.type.replace(src, dst)
for platformType, substitute, _ in PLATFORM_TYPES:
platformTypeName = platformType[0]
platformTypeName = platformType[-2] if "*" in platformType else platformType[0]
if object.type == platformTypeName:
object.type = PLATFORM_TYPE_NAMESPACE + '::' + substitute[0]
object.qualifiers = None if 'struct' in platformType else object.qualifiers
object.qualifiers = None if 'const' in platformType else object.qualifiers
if "*" in platformType:
object.pointer = "*" if object.pointer == "**" else None
class Define:
def __init__ (self, name, aType, alias, value):
self.name = name
self.type = aType
self.alias = alias
self.value = value
class Handle:
def __init__ (self, name, aType, alias, parent, objtypeenum):
self.name = name
self.type = aType
self.alias = alias
self.parent = parent
self.objtypeenum = objtypeenum
class Bitmask:
def __init__ (self, name, aType, requires, bitvalues):
self.name = name
self.type = aType
self.alias = None # initialy None but may be filled while parsing next tag
self.requires = requires
self.bitvalues = bitvalues
class Enumerator:
def __init__ (self, name, value, bitpos):
self.name = name
self.aliasList = [] # list of strings
self.value = value # some enums specify value and some bitpos
self.bitpos = bitpos
self.extension = None # name of extension that added this enumerator
class Enum:
def __init__ (self, name):
self.name = name
self.alias = None # name of enum alias or None
self.type = None # enum or bitmask
self.bitwidth = "32"
self.enumeratorList = [] # list of Enumerator objects
def areValuesLinear (self):
if self.type == 'bitmask':
return False
curIndex = 0
for enumerator in self.enumeratorList:
intValue = parseInt(enumerator.value)
if intValue != curIndex:
return False
curIndex += 1
return True
class CompositeMember:
def __init__ (self, name, aType, pointer, qualifiers, arraySizeList, optional, limittype, values, fieldWidth):
self.name = name
self.type = aType # member type
self.pointer = pointer # None, '*' or '**'
self.qualifiers = qualifiers # 'const' or 'struct' or None
self.arraySizeList = arraySizeList # can contain digits or enums
self.optional = optional
self.limittype = limittype
self.values = values # allowed member values
self.fieldWidth = fieldWidth # ':' followed by number of bits
# check if type should be swaped
substituteType(self)
class Composite:
def __init__ (self, name, category, allowduplicate, structextends, returnedonly, members):
self.name = name
self.category = category # is it struct or union
self.aliasList = [] # most composite types have single alias but there are cases like VkPhysicalDeviceVariablePointersFeatures that have 3
self.allowduplicate = allowduplicate
self.structextends = structextends
self.returnedonly = returnedonly
self.members = members # list of CompositeMember objects
class FunctionArgument:
def __init__ (self, name, qualifiers, aType, pointer = None, secondPointerIsConst = False, arraySize = None, len = None):
self.name = name
self.qualifiers = qualifiers
self.type = aType
self.pointer = pointer # None, '*' or '**'
self.secondPointerIsConst = secondPointerIsConst
self.arraySize = arraySize
self.len = len
# check if type should be swaped
substituteType(self)
class Function:
TYPE_PLATFORM = 0 # Not bound to anything
TYPE_INSTANCE = 1 # Bound to VkInstance
TYPE_DEVICE = 2 # Bound to VkDevice
def __init__ (self, name, returnType = None, arguments = None):
self.name = name
self.aliasList = []
self.returnType = returnType
self.arguments = arguments # list of FunctionArgument objects
self.functionType = Function.TYPE_PLATFORM
# Determine function type based on first argument but use TYPE_PLATFORM for vkGetInstanceProcAddr
if self.name == "vkGetInstanceProcAddr":
return
assert len(self.arguments) > 0
firstArgType = self.arguments[0].type
if firstArgType in ["VkInstance", "VkPhysicalDevice"]:
self.functionType = Function.TYPE_INSTANCE
elif firstArgType in ["VkDevice", "VkCommandBuffer", "VkQueue"]:
self.functionType = Function.TYPE_DEVICE
def getType (self):
return self.functionType
class FeatureEnumerator:
def __init__ (self, name, extends):
self.name = name
self.extends = extends
class FeatureRequirement:
def __init__ (self, operation, comment, enumList, typeList, commandList):
self.operation = operation # "require" or "remove"
self.comment = comment
self.enumList = enumList # list of FeatureEnumerator objects
self.typeList = typeList # list of strings, each representing required structure name
self.commandList = commandList # list of strings, each representing required function name
class Feature:
def __init__ (self, api, name, number, requirementsList):
self.api = api
self.name = name
self.number = number
self.requirementsList = requirementsList # list of FeatureRequirement objects
class ExtensionEnumerator:
def __init__ (self, name, extends, alias, value, extnumber, offset, bitpos, vdir, comment):
self.name = name
self.extends = extends
self.alias = alias
self.value = value
self.extnumber = extnumber
self.offset = offset
self.bitpos = bitpos
self.dir = vdir
self.comment = comment # note: comment is used to mark not promoted features for partially promoted extensions
class ExtensionCommand:
def __init__ (self, name, comment):
self.name = name
self.comment = comment
class ExtensionType:
def __init__ (self, name, comment):
self.name = name
self.comment = comment
class ExtensionRequirements:
def __init__ (self, depends, extendedEnums, newCommands, newTypes):
self.depends = depends # None when requirement apply to all implementations of extension or string with dependencies
# string with extension name when requirements apply to implementations that also support given extension
self.extendedEnums = extendedEnums # list of ExtensionEnumerator objects
self.newCommands = newCommands # list of ExtensionCommand objects
self.newTypes = newTypes # list of ExtensionType objects
class Extension:
def __init__ (self, name, number, type, depends, platform, promotedto, partiallyPromoted, requirementsList):
self.name = name # extension name
self.number = number # extension version
self.type = type # extension type - "device" or "instance"
self.depends = depends # string containig grammar for required core vulkan version and/or other extensions
self.platform = platform # None, "win32", "ios", "android" etc.
self.promotedto = promotedto # vulkan version, other extension or None
self.partiallyPromoted = partiallyPromoted # when True then some of requirements were not promoted
self.requirementsList = requirementsList # list of ExtensionRequirements objects
class API:
def __init__ (self, apiName):
self.apiName = apiName # string "vulkan" or "vulkansc"
self.versions = []
self.basetypes = {} # dictionary, e.g. one of keys is VkFlags and its value is uint32_t
self.defines = []
self.handles = [] # list of Handle objects
self.bitmasks = [] # list of Bitmask objects
self.enums = [] # list of Enum objects - each contains individual enum definition (including extension enums)
self.compositeTypes = [] # list of Composite objects - each contains individual structure/union definition (including extension structures)
self.functions = [] # list of Function objects - each contains individual command definition (including extension functions)
self.features = [] # list of Feature objects
self.extensions = [] # list of Extension objects - each contains individual, supported extension definition
self.notSupportedExtensions = [] # list of Extension objects - it contains NOT supported extensions; this is filled and needed only for SC
self.basicCTypes = [] # list of basic C types e.g. 'void', 'int8_t'
self.tempAliasesList = [] # list of aliases for enums that could not be added because enum is defined later than its alias; this is needed for SC
# read all files from extensions directory
additionalExtensionData = {}
for fileName in glob.glob(os.path.join(SCRIPTS_SRC_DIR, "extensions", "*.json")):
if "schema.json" in fileName:
continue
extensionName = os.path.basename(fileName)[:-5]
fileContent = readFile(fileName)
try:
additionalExtensionData[extensionName] = json.loads(fileContent)
except ValueError as err:
print("Error in %s: %s" % (os.path.basename(fileName), str(err)))
sys.exit(-1)
self.additionalExtensionData = sorted(additionalExtensionData.items(), key=lambda e: e[0])
def addEnumerator(self, targetEnum, name, value, offset, extnumber, bitpos, dir = None):
# calculate enumerator value if offset attribute is present
if value is None and offset is not None:
value = 1000000000 + (int(extnumber) - 1) * 1000 + int(offset)
# check if value should be negative
value = -value if dir == "-" else value
# convert to string so that type matches the type in which values
# are stored for enums that were read from enums xml section
value = str(value)
# add new enumerator
targetEnum.enumeratorList.append(Enumerator(name, value, bitpos))
def addAliasToEnumerator (self, targetEnum, name, alias):
assert(alias is not None)
for e in reversed(targetEnum.enumeratorList):
if alias == e.name or alias in e.aliasList:
# make sure same alias is not already on the list; this handles special case like
# VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR alais which is defined in three places
if name not in e.aliasList:
e.aliasList.append(name)
return True
return False
def readEnum (self, enumsNode):
enumName = enumsNode.get("name")
# special case for vulkan hardcoded constants that are specified as enum in vk.xml
if enumName == "API Constants":
for enumItem in enumsNode:
self.defines.append(Define(
enumItem.get("name"),
enumItem.get("type"),
enumItem.get("alias"),
enumItem.get("value")
))
return
# initial enum definition is read while processing types section;
# we need to find this enum definition and add data to it
enumDefinition = [enumDef for enumDef in self.enums if enumName == enumDef.name][0]
# add type and bitwidth to enum definition
enumDefinition.type = enumsNode.get("type")
enumDefinition.bitwidth = enumsNode.get("bitwidth")
if enumDefinition.bitwidth is None:
enumDefinition.bitwidth = "32"
# add components to enum definition
for enumeratorItem in enumsNode:
# skip comment tags
if enumeratorItem.tag != "enum":
continue
name = enumeratorItem.get("name")
alias = enumeratorItem.get("alias")
if alias is None:
self.addEnumerator(
enumDefinition,
name,
enumeratorItem.get("value"),
enumeratorItem.get("offset"),
enumeratorItem.get("extnumber"),
enumeratorItem.get("bitpos"),
enumeratorItem.get("dir"))
else:
self.addAliasToEnumerator(enumDefinition, name, alias)
def readCommand (self, commandNode):
protoNode = None # proto is a first child of every command node
# check if this is alias
alias = commandNode.get("alias")
# if node is alias then use the fact that alias definition follows aliased structure
if alias is not None:
# aliased command has usually been added recently, so we iterate in reverse order
found = False
for f in reversed(self.functions):
found = (f.name == alias)
if found:
f.aliasList.append(commandNode.get("name"))
break
assert found
# go to next node
return
# memorize all parameters
functionParams = []
for paramNode in commandNode:
# memorize prototype node
if paramNode.tag == "proto":
protoNode = paramNode
continue
# skip implicitexternsyncparams
if paramNode.tag != "param":
continue
nameNode = paramNode.find("name")
typeNode = paramNode.find("type")
starCount = typeNode.tail.count('*')
lenAttr = paramNode.get("len")
functionParams.append(FunctionArgument(
nameNode.text,
paramNode.text,
paramNode.find("type").text,
'*' * starCount if starCount > 0 else None,
'const' in typeNode.tail,
nameNode.tail,
lenAttr
))
# memorize whole function
self.functions.append(Function(
protoNode.find("name").text,
protoNode.find("type").text,
functionParams,
))
def readExtension (self, extensionNode):
# check to which list this extension should be added
supportedList = extensionNode.get("supported")
isExtensionSupported = self.apiName in supportedList.split(',')
targetExtensionList = self.extensions if isExtensionSupported else self.notSupportedExtensions
# read extension definition to proper list
extensionName = extensionNode.get("name")
extensionNumber = extensionNode.get("number")
partiallyPromoted = False
# before reading extension data first read extension
# requirements by iterating over all require tags
requirementsList = []
for requireItem in extensionNode:
extendedEnums = []
newCommands = []
newTypes = []
# iterate over all children in current require tag
# and add them to proper list
for individualRequirement in requireItem:
requirementName = individualRequirement.get("name")
requirementComment = individualRequirement.get("comment")
# check if this requirement was not promoted and mark
# this extension as not fully promoted
if requirementComment is not None and "Not promoted to" in requirementComment:
partiallyPromoted = True
# check if this requirement describes enum, command or type
if individualRequirement.tag == "enum":
extendedEnumName = individualRequirement.get("extends")
extendedEnums.append(ExtensionEnumerator(
requirementName,
extendedEnumName,
individualRequirement.get("alias"),
individualRequirement.get("value"),
individualRequirement.get("extnumber"),
individualRequirement.get("offset"),
individualRequirement.get("bitpos"),
individualRequirement.get("dir"),
requirementComment))
elif individualRequirement.tag == "command":
newCommands.append(ExtensionCommand(requirementName, requirementComment))
elif individualRequirement.tag == "type":
newTypes.append(ExtensionType(requirementName, requirementComment))
elif individualRequirement.tag == "comment" and "not promoted to" in individualRequirement.text:
# partial promotion of VK_EXT_ycbcr_2plane_444_formats and VK_EXT_4444_formats
# is marked with comment tag in first require section
partiallyPromoted = True
# construct requirement object and add it to the list
requirementsList.append(ExtensionRequirements(
requireItem.get("depends"), # dependencies that can include "and/or" grammar
extendedEnums, # extendedEnums
newCommands, # newCommands
newTypes # newTypes
))
# add extension definition to proper api object
targetExtensionList.append(Extension(
extensionName, # name
extensionNumber, # number
extensionNode.get("type"), # type
extensionNode.get("depends"), # depends
extensionNode.get("platform"), # platform
extensionNode.get("promotedto"), # promotedto
partiallyPromoted, # partiallyPromoted
requirementsList # requirementsList
))
def readFeature (self, featureNode):
requirementsList = []
for requirementGroup in featureNode:
enumList = []
typeList = []
commandList = []
for requirement in requirementGroup:
requirementName = requirement.get("name")
if requirement.tag == "enum":
extendedEnumName = requirement.get("extends")
enumList.append(FeatureEnumerator(requirementName, extendedEnumName))
if extendedEnumName is not None:
# find extended enum in api.enums list
for e in self.enums:
if extendedEnumName == e.name:
# read enumerator and add it to enum
alias = requirement.get("alias")
if alias is None:
self.addEnumerator(
e,
requirementName,
requirement.get("value"),
requirement.get("offset"),
requirement.get("extnumber"),
requirement.get("bitpos"),
requirement.get("dir"))
elif not self.addAliasToEnumerator(e, requirementName, alias):
self.tempAliasesList.append((e, requirementName, alias))
break
elif requirement.tag == "type":
typeList.append(requirementName)
elif requirement.tag == "command":
commandList.append(requirementName)
requirementsList.append(FeatureRequirement(
requirementGroup.tag,
requirementGroup.get("comment"),
enumList,
typeList,
commandList
))
self.features.append(Feature(
featureNode.get("api"),
featureNode.get("name"),
featureNode.get("number"),
requirementsList
))
def readType (self, typeNode):
name = typeNode.get("name")
alias = typeNode.get("alias")
category = typeNode.get("category")
if category == "enum":
if alias is None:
self.enums.append(Enum(name))
else:
for e in reversed(self.enums):
if alias == e.name:
e.alias = name
break
elif category == "handle":
type = None
if alias is None:
name = typeNode.find("name").text
type = typeNode.find("type").text
self.handles.append(Handle(
name,
type,
alias,
typeNode.get("parent"),
typeNode.get("objtypeenum"),
))
else:
for h in reversed(self.handles):
if alias == h.name:
h.alias = name
break
elif category == "basetype":
# processing only those basetypes that have type child
type = typeNode.find("type")
if type is not None:
self.basetypes[typeNode.find("name").text] = type.text
elif category == "bitmask":
# if node is alias then use the fact that alias definition follows aliased bitmasks;
# in majoriti of cases it follows directly aliased bitmasks but in some cases there
# is a unrelated bitmasks definition in between - to handle this traverse in reverse order
if alias is not None:
for bm in reversed(self.bitmasks):
if alias == bm.name:
bm.alias = name
break
else:
self.bitmasks.append(Bitmask(
typeNode.find("name").text,
typeNode.find("type").text,
typeNode.get("requires"),
typeNode.get("bitvalues")
))
elif category in ["struct", "union"]:
# if node is alias then use the fact that alias definition follows aliased structure;
# in majoriti of cases it follows directly aliased structure but in some cases there
# is a unrelated structure definition in between - to handle this traverse in reverse order
if alias is not None:
for ct in reversed(self.compositeTypes):
if alias == ct.name:
ct.aliasList.append(name)
break
# go to next node
return
# read structure members
structMembers = []
for memberNode in typeNode:
if memberNode.tag != "member":
continue
# handle enum nodes that can be used for array dimensions
arraySizeList = []
for node in memberNode:
if node.tag == "enum":
arraySizeList.append(node.text)
# check if there are array dimension that are not enums
if '[' in node.tail and len(node.tail) > 2:
arraySizeList += node.tail.replace(']', ' ').replace('[', ' ').split()
# handle additional text after name tag; it can represent array
# size like in VkPipelineFragmentShadingRateEnumStateCreateInfoNV
# or number of bits like in VkAccelerationStructureInstanceKHR
nameNode = memberNode.find("name")
nameTail = nameNode.tail
fieldWidth = None
if nameTail:
if ':' in nameTail:
fieldWidth = nameTail.replace(':', '').replace(' ', '')
elif '[' in nameTail and ']' in nameTail:
nameTail = nameTail.replace(']', ' ').replace('[', ' ')
arraySizeList = nameTail.split() + arraySizeList
# handle additional text after type tag; it can represent pointers like *pNext
memberTypeNode = memberNode.find("type")
pointer = memberTypeNode.tail.strip() if memberTypeNode.tail is not None else None
structMembers.append(CompositeMember(
nameNode.text, # name
memberTypeNode.text, # type
pointer, # pointer
memberNode.text, # qualifiers
arraySizeList, # arraySizeList
memberNode.get("optional"), # optional
memberNode.get("limittype"), # limittype
memberNode.get("values"), # values
fieldWidth # fieldWidth
))
# create structure definition
self.compositeTypes.append(Composite(
name,
category,
typeNode.get("allowduplicate"),
typeNode.get("structextends"),
typeNode.get("returnedonly"),
structMembers
))
elif category == "define":
nNode = typeNode.find("name")
tNode = typeNode.find("type")
if nNode == None or tNode == None:
return
requires = typeNode.get("requires")
name = nNode.text
if "API_VERSION_" in name or requires == "VK_MAKE_VIDEO_STD_VERSION":
value = tNode.tail
value = tNode.text + value[:value.find(')')+1]
value = value.replace('VKSC_API_VARIANT', '1')
self.defines.append(Define(
name,
"uint32_t",
None,
value
))
else:
requires = typeNode.get("requires")
if requires == 'vk_platform':
self.basicCTypes.append(name)
def build (self, rawVkXml):
# iterate over all *.xml root children
for rootChild in rawVkXml.getroot():
# each enum is defined in separate enums node directly under root node
if rootChild.tag == "enums":
self.readEnum(rootChild)
# read function definitions
if rootChild.tag == "commands":
commandsNode = rootChild
for commandItem in commandsNode:
self.readCommand(commandItem)
# read vulkan versions
if rootChild.tag == "feature":
self.readFeature(rootChild)
# read extensions
if rootChild.tag == "extensions":
extensionsNode = rootChild
for extensionItem in extensionsNode:
self.readExtension(extensionItem)
# "types" is a first child of root so it's optimal to check for it
# last and don't repeat this check for all other iterations
if rootChild.tag == "types":
typesNode = rootChild
for typeItem in typesNode:
self.readType(typeItem)
# Verify that promotedto extensions are supported by the api
for ext in self.extensions:
if ext.promotedto is not None and "VK_VERSION" not in ext.promotedto:
if not any(x.name == ext.promotedto for x in self.extensions):
ext.promotedto = None
def postProcess (self):
# temporary workaround for extensions that are marked only for vulkan api in xml while
# they are need by vulkan_json_data.hpp and vulkan_json_parser.hpp in vulkansc
if self.apiName == "vulkansc":
deviceDiagnosticCheckpoints = [e for e in self.notSupportedExtensions if e.name == "VK_NV_device_diagnostic_checkpoints"]
if len(deviceDiagnosticCheckpoints):
deviceDiagnosticCheckpoints = deviceDiagnosticCheckpoints[0]
self.extensions.append(deviceDiagnosticCheckpoints)
self.notSupportedExtensions.remove(deviceDiagnosticCheckpoints)
formatFeatureFlags2 = [e for e in self.notSupportedExtensions if e.name == "VK_KHR_format_feature_flags2"]
if len(formatFeatureFlags2):
formatFeatureFlags2 = formatFeatureFlags2[0]
self.extensions.append(formatFeatureFlags2)
self.notSupportedExtensions.remove(formatFeatureFlags2)
# add new enumerators that were added by extensions to api.enums
# we have to do it at the end for SC becouse some enums are dependednt from extensions/api versions
# and those dependencies can be checked only after all extensions were read
for ext in self.extensions:
for requirement in ext.requirementsList:
# check if this requirement is supported by current implementation
isRequirementSupported = True
dependencies = requirement.depends
if dependencies is not None:
# check if dependency extension or api version is part of this api
# note: this logic will have to changed if there are dependencies with "and/or" grammar
assert((',' not in dependencies) or ('+' not in dependencies))
isRequirementSupported = '_VERSION_' in dependencies
if isRequirementSupported == False:
for e in self.extensions:
if e.name in dependencies:
isRequirementSupported = True
break
# add enumerator to proper enum from api.enums
if isRequirementSupported:
for enumerator in requirement.extendedEnums:
if enumerator.extends is None:
continue
# find enum in api.enums
matchedEnum = [enum for enum in api.enums if enumerator.extends == enum.name][0]
# add enumerator only when it is not already in enum
if len([e for e in matchedEnum.enumeratorList if e.name == enumerator.name]) == 0:
if enumerator.alias == None:
self.addEnumerator(
matchedEnum,
enumerator.name,
enumerator.value,
enumerator.offset,
enumerator.extnumber if enumerator.extnumber else ext.number,
enumerator.bitpos,
enumerator.dir)
elif not self.addAliasToEnumerator(matchedEnum, enumerator.name, enumerator.alias):
# we might not be able to add alias as we might be missing what we are aliasing
# this will hapen when aliased enum is added later then definition of alias
self.tempAliasesList.append((matchedEnum, enumerator.name, enumerator.alias))
# add aliases to enumerators that were defined after alias definition
for enum, name, alias in self.tempAliasesList:
if not self.addAliasToEnumerator(enum, name, alias):
# if enumerator that should be aliased was not found then try to insert it without alias
# (this happens for vulkansc as in xml enumerator might be defined in extension that is not supported by sc)
def tryToFindEnumValue(searchedName):
for nsExt in self.notSupportedExtensions:
for r in nsExt.requirementsList:
for enumerator in r.extendedEnums:
if enumerator.name == searchedName:
self.addEnumerator(
enum,
name,
enumerator.value,
enumerator.offset,
enumerator.extnumber if enumerator.extnumber else ext.number,
enumerator.bitpos,
enumerator.dir)
# there are ~2 cases where alias that is not part of SC still needs to be added for SC
self.addAliasToEnumerator(enum, alias, name)
return
# using function for easy stack unwinding
tryToFindEnumValue(alias)
self.tempAliasesList = None
if self.apiName == "vulkan":
def removeExtensionFromApi(extName, structureNameList, commandNameList):
extObjectList = [e for e in api.extensions if e.name == extName]
if len(extObjectList) > 0:
api.extensions.remove(extObjectList[0])
structObjectList = [ct for ct in api.compositeTypes if ct.name in structureNameList]
for s in structObjectList:
api.compositeTypes.remove(s)
commandObjectList = [f for f in api.functions if f.name in commandNameList]
for f in commandObjectList:
api.functions.remove(f)
# remove structures and commands added by VK_EXT_directfb_surface extension
removeExtensionFromApi("VK_EXT_directfb_surface",
["VkDirectFBSurfaceCreateFlagsEXT", "VkDirectFBSurfaceCreateInfoEXT"],
["vkCreateDirectFBSurfaceEXT", "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"])
# remove structures and commands added by disabled VK_ANDROID_native_buffer extension;
# disabled extensions aren't read but their structures and commands will be in types and commands sections in vk.xml
removeExtensionFromApi("VK_ANDROID_native_buffer",
["VkNativeBufferANDROID", "VkSwapchainImageCreateInfoANDROID",
"VkPhysicalDevicePresentationPropertiesANDROID", "VkNativeBufferUsage2ANDROID",
"VkSwapchainImageUsageFlagBitsANDROID", "VkSwapchainImageUsageFlagsANDROID"],
["vkGetSwapchainGrallocUsageANDROID", "vkAcquireImageANDROID",
"vkQueueSignalReleaseImageANDROID", "vkGetSwapchainGrallocUsage2ANDROID"])
# remove empty enums e.g. VkQueryPoolCreateFlagBits, VkDeviceCreateFlagBits
enumsToRemove = [enum for enum in self.enums if len(enum.enumeratorList) == 0]
for er in enumsToRemove:
self.enums.remove(er)
# add alias for VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR (in vk.xml for this struct alias is defined before struct
# where in all other cases it is defined after structure definition)
barycentricFeaturesStruct = [c for c in api.compositeTypes if c.name == 'VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR'][0]
barycentricFeaturesStruct.aliasList.append('VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV')
elif self.apiName == "vulkansc":
# remove commands that are marked with <remove> tag in SC feature specification;
# e.g. there is no vkCreateShaderModule in SC
functionsToRemove = []
scFeatures = [f for f in self.features if f.api == "vulkansc"][0]
for featureRequirement in scFeatures.requirementsList:
if featureRequirement.operation == "remove":
for removeFun in featureRequirement.commandList:
# find function in the list of all functions
for fun in self.functions:
if removeFun == fun.name:
functionsToRemove.append(fun)
break
for fun in functionsToRemove:
self.functions.remove(fun)
# sc is based on vk1.2 so we need to check features of vk1.3+
# and rename functions and structures that were promoted in
# those versions to their previous names (aliases)
renamedStructuresDict = {}
for feature in self.features:
# skip vk versions smaller than 1.3
if int(feature.number[-1]) < 3:
continue
# iterate over all requirements and enums/commands/structs added in them
for featureRequirement in feature.requirementsList:
for promotedEnumerator in featureRequirement.enumList:
# iterate over all enums and find one that was extended
for enum in self.enums:
if enum.name != promotedEnumerator.extends:
continue
enumeratorReplaced = False
# find enumerator that should have changed name
for enumerator in enum.enumeratorList:
if enumerator.name != promotedEnumerator.name or len(enumerator.aliasList) == 0:
continue
# replace enumerator name with its first alias
enumerator.name = enumerator.aliasList[0]
enumerator.aliasList = enumerator.aliasList[1:]
# first member of almost all structures is VkStructureType and in xml that member
# has defined value - we need to change those values to versions supported by SC
if "STRUCTURE_TYPE" in enumerator.name:
for struct in self.compositeTypes:
if struct.members[0].values == promotedEnumerator.name:
struct.members[0].values = enumerator.name
break
enumeratorReplaced = True
break
if enumeratorReplaced:
break
renamedFunctionsList = []
for promotedFun in featureRequirement.commandList:
# find promotedFun in list of all functions
for fun in self.functions:
if fun.name != promotedFun:
continue
# replace function name with its first alias
fun.name = fun.aliasList[0]
fun.aliasList = fun.aliasList[1:]
# memorize renamed functions
renamedFunctionsList.append(fun)
break
for promotedStruct in featureRequirement.typeList:
# find promotedStruct in list of all structures
for struct in self.compositeTypes:
if struct.name != promotedStruct:
continue
# skip structures without alias
if len(struct.aliasList) == 0:
break
# replace struct name with its first alias
struct.name = struct.aliasList[0]
struct.aliasList = struct.aliasList[1:]
# memorize all renamed structures
renamedStructuresDict[promotedStruct] = struct
# check all all renamed functions and make sure that argument types are also renamed
for renamedFun in renamedFunctionsList:
for arg in renamedFun.arguments:
if arg.type == promotedStruct:
arg.type = struct.name
break
# iterate over all renamed structures and make sure that all their attributes are also renamed
for newName in renamedStructuresDict:
for member in renamedStructuresDict[newName].members:
if member.type in renamedStructuresDict:
member.type = renamedStructuresDict[member.type].name
# remove enums that are not part of any vulkan version nor extension
# (SC specific enums are in vk.xml without any attribute identifying that they are SC specific; same for enums for disabled extensions)
def isEnumUsed(featureList, extensionList, enumName, enumAlias):
for feature in featureList:
for requirement in feature.requirementsList:
for typeName in requirement.typeList:
if (typeName == enumName) or (typeName == enumAlias):
return True
for ext in extensionList:
for requirement in ext.requirementsList:
for newType in requirement.newTypes:
if (newType.name == enumName) or (newType.name == enumAlias):
return True
return False
# do removal using above function
enumsToRemove = []
for enum in self.enums:
if isEnumUsed(self.features, self.extensions, enum.name, enum.alias):
continue
enumsToRemove.append(enum)
for er in enumsToRemove:
self.enums.remove(er)
# helper function that check if dependency is in list of extension
def isDependencyMeet(dependency, extensionList):
if dependency == None:
return True
# check if requirement dependencies are meet; if not then struct/function is not used
# note: this logic will have to changed if there are dependencies with "and/or" grammar
if '_VERSION_' in dependency:
return True
dependency = dependency.split(',')[0]
for e in extensionList:
if dependency == e.name:
return True
return False
# remove structures that are not part of any vulkan version nor extension
# (SC specific structures are in vk.xml without any attribute identifying that they are SC specific)
def isStructUsed(featureList, extensionList, structNameList):
for feature in featureList:
for requirement in feature.requirementsList:
for typeName in requirement.typeList:
if typeName in structNameList:
return True
for ext in extensionList:
for requirement in ext.requirementsList:
for newType in requirement.newTypes:
if newType.name in structNameList:
return isDependencyMeet(requirement.depends, extensionList)
return False
structsToRemove = []
for struct in self.compositeTypes:
structNameList = [struct.name] + struct.aliasList
if isStructUsed(self.features, self.extensions, structNameList):
continue
structsToRemove.append(struct)
for st in structsToRemove:
self.compositeTypes.remove(st)
# remove commands that are not part of any vulkan version nor extension
# (SC specific commands are in vk.xml without any attribute identifying that they are SC specific)
def isFunctionUsed(featureList, extensionList, functionNameList):
for feature in featureList:
for requirement in feature.requirementsList:
for commandName in requirement.commandList:
if commandName in functionNameList:
return True
for ext in extensionList:
for requirement in ext.requirementsList:
for newCommand in requirement.newCommands:
if newCommand.name in functionNameList:
return isDependencyMeet(requirement.depends, extensionList)
return False
functionsToRemove = []
for fun in self.functions:
functionNameList = [fun.name] + fun.aliasList
if isFunctionUsed(self.features, self.extensions, functionNameList):
continue
functionsToRemove.append(fun)
for fun in functionsToRemove:
self.functions.remove(fun)
# remove handles that are not part of any vulkan command or structure
def isHandleUsed(structList, functionList, handleName):
for struct in structList:
for member in struct.members:
if handleName in member.type:
return True
for fun in functionList:
for arg in fun.arguments:
if handleName in arg.type:
return True
return False
handlesToRemove = []
for h in self.handles:
if isHandleUsed(self.compositeTypes, self.functions, h.name):
continue
handlesToRemove.append(h)
for h in handlesToRemove:
self.handles.remove(h)
# sort enumerators in enums
sortLambda = lambda enumerator: int(enumerator.bitpos) if enumerator.value is None else int(enumerator.value, 16 if 'x' in enumerator.value else 10)
for enum in self.enums:
# skip enums that have no items or just one in enumeratorList (e.g. VkQueryPoolCreateFlagBits)
if len(enum.enumeratorList) < 2:
continue
# construct list of enumerators in which value and bitpos are not None
enumeratorsToSort = [e for e in enum.enumeratorList if e.value != e.bitpos]
# construct list of enumerators in which value and bitpos are equal to None
remainingEnumerators = [e for e in enum.enumeratorList if e.value == e.bitpos]
# construct sorted enumerator list with aliases at the end
enum.enumeratorList = sorted(enumeratorsToSort, key=sortLambda)
enum.enumeratorList.extend(remainingEnumerators)
def prefixName (prefix, name):
name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name[2:])
name = re.sub(r'([a-zA-Z])([0-9])', r'\1_\2', name)
name = name.upper()
return prefix + name
def parseInt (value):
return int(value, 16 if ("0x" in value) else 10)
def getApiVariantIndexByName(variantName):
apiVariant = {
None : 0,
'' : 0,
'SC' : 1
}
return apiVariant[variantName]
def getApiVariantNameByIndex(variantIndex):
apiVariant = {
None : '',
0 : '',
1 : 'SC'
}
return apiVariant[variantIndex]
def readFile (filename):
with open(filename, 'rt') as f:
return f.read()
def getInterfaceName (functionName):
assert functionName[:2] == "vk"
return functionName[2].lower() + functionName[3:]
def getFunctionTypeName (functionName):
assert functionName[:2] == "vk"
return functionName[2:] + "Func"
def endsWith (str, postfix):
return str[-len(postfix):] == postfix
def writeHandleType (api, filename):
def getHandleName (name):
return prefixName("HANDLE_TYPE_", name)
def genHandles ():
yield "\t%s\t= 0," % getHandleName(api.handles[0].name)
for h in api.handles[1:]:
yield "\t%s," % getHandleName(h.name)
for h in api.handles:
if h.alias is not None:
yield "\t%s\t= %s," % (getHandleName(h.alias), getHandleName(h.name))
yield "\tHANDLE_TYPE_LAST\t= %s + 1" % (getHandleName(api.handles[-1].name))
def genHandlesBlock ():
yield "enum HandleType"
yield "{"
for line in indentLines(genHandles()):
yield line
yield "};"
yield ""
writeInlFile(filename, INL_HEADER, genHandlesBlock())
def getEnumValuePrefixAndPostfix (enum):
prefix = enum.name[0]
for i in range(1, len(enum.name)):
if enum.name[i].isupper() and not enum.name[i-1].isupper():
prefix += "_"
prefix += enum.name[i].upper()
for p in EXTENSION_POSTFIXES:
if prefix.endswith(p):
return prefix[:-len(p)-1], '_'+p
return prefix, ''
def genEnumSrc (enum):
yield "enum %s" % enum.name
yield "{"
lines = []
for ed in enum.enumeratorList:
if ed.value is not None:
lines.append(f"\t{ed.name}\t= {ed.value},")
for ed in enum.enumeratorList:
for alias in ed.aliasList:
lines.append(f"\t{alias}\t= {ed.name},")
# add *_LAST item when enum is linear
prefix, postfix = getEnumValuePrefixAndPostfix(enum)
if enum.areValuesLinear():
lines.append(f"\t{prefix}{postfix}_LAST,")
# add _MAX_ENUM item with the ext postifix at the end
lines.append(f"\t{prefix}_MAX_ENUM{postfix}\t= 0x7FFFFFFF")
for line in indentLines(lines):
yield line
yield "};"
def genBitfieldSrc (bitfield):
lines = []
for ev in bitfield.enumeratorList:
# bitfields may use mix of bitpos and values
if ev.bitpos is not None:
value = pow(2, int(ev.bitpos))
lines.append(f"\t{ev.name}\t= {value:#010x},")
if ev.value is not None:
lines.append(f"\t{ev.name}\t= {ev.value},")
for ev in bitfield.enumeratorList:
for alias in ev.aliasList:
lines.append(f"\t{alias}\t= {ev.name},")
# add _MAX_ENUM item
prefix, postfix = getEnumValuePrefixAndPostfix(bitfield)
lines.append(f"\t{prefix}_MAX_ENUM{postfix}\t= 0x7FFFFFFF")
yield f"enum {bitfield.name}"
yield "{"
for line in indentLines(lines):
yield line
yield "};"
def genBitfield64Src (bitfield64):
def generateEntry(lines, bitfieldName, entryName, bitpos, value):
if entryName is None:
return
# bitfields may use mix of bitpos and values
if ev.bitpos is not None:
v = pow(2, int(bitpos))
lines.append(f"static const {bitfieldName} {entryName}\t= {v:#010x}ULL;")
if value is not None:
lines.append(f"static const {bitfieldName} {entryName}\t= {value}ULL;")
yield f"typedef uint64_t {bitfield64.name};"
lines = []
for ev in bitfield64.enumeratorList:
generateEntry(lines, bitfield64.name, ev.name, ev.bitpos, ev.value)
for alias in ev.aliasList:
generateEntry(lines, bitfield64.name, alias, ev.bitpos, ev.value)
# write indented lines
for line in indentLines(lines):
yield line
yield ""
def genDefinesSrc (apiName, defines):
def genLines (defines):
for d in defines:
if d.alias is not None:
continue
defineType = DEFINITIONS.get(d.name, d.type)
yield f"#define {d.name}\t(static_cast<{defineType}>\t({d.value}))"
for line in indentLines(genLines(defines)):
yield line
# add VK_API_MAX_FRAMEWORK_VERSION
major, minor = api.features[-1].number.split('.')
yield f"#define VK{apiName}_API_MAX_FRAMEWORK_VERSION\tVK{apiName}_API_VERSION_{major}_{minor}"
def genHandlesSrc (handles):
def genLines (handles):
for h in handles:
handleType = h.type
handleObjtype = h.objtypeenum
if h.alias is not None:
# search for aliased handle
for searchedHandle in handles:
if h.alias == searchedHandle.name:
handleType = searchedHandle.type
handleObjtype = searchedHandle.objtypeenum
break
yield f"{handleType}\t({h.name},\tHANDLE{handleObjtype[9:]});"
for line in indentLines(genLines(handles)):
yield line
def genHandlesSrc (handles):
def genLines (handles):
for h in handles:
handleType = h.type
handleObjtype = h.objtypeenum
line = f"{handleType}\t({{}},\tHANDLE{handleObjtype[9:]});"
yield line.format(h.name)
if h.alias is not None:
yield line.format(h.alias)
for line in indentLines(genLines(handles)):
yield line
def writeBasicTypes (api, filename):
def gen ():
for line in genDefinesSrc("SC" if api.apiName == "vulkansc" else "", api.defines):
yield line
yield ""
for line in genHandlesSrc(api.handles):
yield line
yield ""
for enum in api.enums:
# skip empty enums only for vulkan
# vulkan_json_data.hpp and vulkan_json_parser.hpp in SC need many empty enums
if len(enum.enumeratorList) == 0 and api.apiName == "vulkan":
continue
if enum.type == "bitmask":
if enum.bitwidth == "32":
for line in genBitfieldSrc(enum):
yield line
else:
for line in genBitfield64Src(enum):
yield line
else:
for line in genEnumSrc(enum):
yield line
if enum.alias is not None:
yield f"typedef {enum.name} {enum.alias};"
yield ""
for bitmask in api.bitmasks:
plainType = api.basetypes[bitmask.type]
yield f"typedef {plainType} {bitmask.name};\n"
if bitmask.alias:
yield f"typedef {bitmask.name} {bitmask.alias};\n"
yield ""
for line in indentLines(["VK_DEFINE_PLATFORM_TYPE(%s,\t%s)" % (s[0], c) for n, s, c in PLATFORM_TYPES]):
yield line
yield ""
for ext in api.extensions:
firstRequirementEnums = ext.requirementsList[0].extendedEnums
for e in firstRequirementEnums:
if e.extends is None and e.value is not None:
yield "#define " + e.name + " " + e.value
writeInlFile(filename, INL_HEADER, gen())
def writeCompositeTypes (api, filename):
# function that returns definition of structure member
def memberAsString (member):
result = ''
if member.qualifiers:
result += member.qualifiers
result += member.type
if member.pointer:
result += member.pointer
result += '\t' + member.name
for size in member.arraySizeList:
result += f"[{size}]"
if member.fieldWidth:
result += f":{member.fieldWidth}"
return result
# function that prints single structure definition
def genCompositeTypeSrc (type):
structLines = "%s %s\n{\n" % (type.category, type.name)
for line in indentLines(['\t'+memberAsString(m)+';' for m in type.members]):
structLines += line + '\n'
return structLines + "};\n"
# function that prints all structure definitions and alias typedefs
def gen ():
# structures in xml are not ordered in a correct way for C++
# we need to save structures that are used in other structures first
allStructureNamesList = [s.name for s in api.compositeTypes]
commonTypesList = api.basicCTypes + ['VkStructureType']
savedStructureNamesList = []
delayedStructureObjectsList = []
# helper function that checks if all structure members were already saved
def canStructBeSaved(compositeObject):
for m in compositeObject.members:
# check first commonTypesList to speed up the algorithm
if m.type in commonTypesList:
continue
# make sure that member is not of same type as compositeObject
# (this hadles cases like VkBaseOutStructure)
if m.type == compositeObject.name:
continue
# if member is of compositeType that was not saved we cant save it now
if m.type in allStructureNamesList and m.type not in savedStructureNamesList:
return False
return True
# iterate over all composite types
lastDelayedComposite = None
for ct in api.compositeTypes:
# check if one of delayed structures can be saved
delayedButSaved = []
for dct in delayedStructureObjectsList:
if lastDelayedComposite != dct and canStructBeSaved(dct):
yield genCompositeTypeSrc(dct)
delayedButSaved.append(dct)
lastDelayedComposite = None
for dsct in delayedButSaved:
savedStructureNamesList.append(dsct.name)
delayedStructureObjectsList.remove(dsct)
# check if current structure can be saved
if canStructBeSaved(ct):
yield genCompositeTypeSrc(ct)
savedStructureNamesList.append(ct.name)
else:
delayedStructureObjectsList.append(ct)
# memorize structure that was delayed in last iteration to
# avoid calling for it canStructBeSaved in next iteration
lastDelayedComposite = ct
# save remaining delayed composite types (~4 video related structures)
while len(delayedStructureObjectsList) > 0:
for dct in delayedStructureObjectsList:
if canStructBeSaved(dct):
yield genCompositeTypeSrc(dct)
savedStructureNamesList.append(dct.name)
delayedStructureObjectsList.remove(dct)
break
# write all alias typedefs
for ct in api.compositeTypes:
for alias in ct.aliasList:
yield "typedef %s %s;" % (ct.name, alias)
yield ""
writeInlFile(filename, INL_HEADER, gen())
def argListToStr (args):
def argumentToString(arg):
# args can be instance of FunctionArgument or CompositeMember
# but CompositeMember has no arraySize atrribute nor secondPointerIsConst
workingOnFunctionArgument = True if hasattr(arg, 'arraySize') else False
result = ''
if arg.qualifiers:
result += arg.qualifiers
result += arg.type
if arg.pointer:
if workingOnFunctionArgument and arg.secondPointerIsConst:
result += '* const*'
else:
result += arg.pointer
result += ' ' + arg.name
if workingOnFunctionArgument:
if arg.arraySize:
result += arg.arraySize
return result
return ", ".join(argumentToString(arg) for arg in args)
def writeInterfaceDecl (api, filename, functionTypes, concrete):
def genProtos ():
postfix = "" if concrete else " = 0"
for function in api.functions:
if not function.getType() in functionTypes:
continue
yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments), postfix)
writeInlFile(filename, INL_HEADER, indentLines(genProtos()))
def writeFunctionPtrTypes (api, filename):
def genTypes ():
pattern = "typedef VKAPI_ATTR {}\t(VKAPI_CALL* {})\t({});"
for function in api.functions:
argList = argListToStr(function.arguments)
yield pattern.format(function.returnType, getFunctionTypeName(function.name), argList)
for alias in function.aliasList:
yield pattern.format(function.returnType, getFunctionTypeName(alias), argList)
writeInlFile(filename, INL_HEADER, indentLines(genTypes()))
def writeFunctionPointers (api, filename, functionTypes):
def FunctionsYielder ():
for function in api.functions:
if function.getType() in functionTypes:
interfaceName = getInterfaceName(function.name)
functionTypeName = getFunctionTypeName(function.name)
yield f"{functionTypeName}\t{interfaceName};"
if function.getType() == Function.TYPE_INSTANCE:
for alias in function.aliasList:
interfaceName = getInterfaceName(alias)
functionTypeName = getFunctionTypeName(alias)
yield f"{functionTypeName}\t{interfaceName};"
writeInlFile(filename, INL_HEADER, indentLines(FunctionsYielder()))
def getPromotedFunctions (api):
apiNum = 0 if api.apiName == "vulkan" else 1
promotedFunctions = collections.defaultdict(lambda: list())
for feature in api.features:
versionSplit = feature.name.split('_')
apiMajor = int(versionSplit[-2])
apiMinor = int(versionSplit[-1])
apiPrefix = '_'.join(versionSplit[:-2])
if apiNum == 0 and apiPrefix != 'VK_VERSION':
continue
if apiNum == 1 and apiPrefix == 'VK_VERSION':
# Map of "standard" Vulkan versions to VulkanSC version.
stdToSCMap = {
(1, 0): (1, 0),
(1, 1): (1, 0),
(1, 2): (1, 0),
}
mapKey = (apiMajor, apiMinor)
if mapKey not in stdToSCMap:
continue
(apiMajor, apiMinor) = stdToSCMap[mapKey]
apituple = (apiNum, apiMajor, apiMinor)
for featureRequirement in feature.requirementsList:
for promotedFun in featureRequirement.commandList:
promotedFunctions[promotedFun].append(apituple)
return promotedFunctions
def writeInitFunctionPointers (api, filename, functionTypes, cond = None):
promotedFunctions = getPromotedFunctions(api) if Function.TYPE_DEVICE in functionTypes else None
def makeInitFunctionPointers ():
for function in api.functions:
if function.getType() in functionTypes and (cond == None or cond(function)):
condition = ''
if function.getType() == Function.TYPE_DEVICE:
versionCheck = ''
if function.name in promotedFunctions:
for versionTuple in promotedFunctions[function.name]:
if len(versionCheck) > 0:
versionCheck += ' || '
versionCheck = 'usedApiVersion >= VK_MAKE_API_VERSION(%s, %s, %s, 0)' % versionTuple
if len(versionCheck) > 0:
condition = f"if ({versionCheck})\n "
interfaceName = getInterfaceName(function.name)
functionTypeName = getFunctionTypeName(function.name)
yield f"{condition}m_vk.{interfaceName} = ({functionTypeName}) GET_PROC_ADDR(\"{function.name}\");"
for alias in function.aliasList:
yield f"if (!m_vk.{interfaceName})"
yield f" m_vk.{interfaceName} = ({functionTypeName}) GET_PROC_ADDR(\"{alias}\");"
if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].type == "VkPhysicalDevice":
interfaceName = getInterfaceName(alias)
functionTypeName = getFunctionTypeName(alias)
yield f"m_vk.{interfaceName} = ({functionTypeName}) GET_PROC_ADDR(\"{alias}\");"
lines = makeInitFunctionPointers()
writeInlFile(filename, INL_HEADER, lines)
def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className):
def makeFuncPtrInterfaceImpl ():
for function in api.functions:
if function.getType() in functionTypes:
yield ""
yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function.name), argListToStr(function.arguments))
yield "{"
if function.name == "vkEnumerateInstanceVersion":
yield " if (m_vk.enumerateInstanceVersion)"
yield " return m_vk.enumerateInstanceVersion(pApiVersion);"
yield ""
yield " *pApiVersion = VK_API_VERSION_1_0;"
yield " return VK_SUCCESS;"
elif function.getType() == Function.TYPE_INSTANCE and function.arguments[0].type == "VkPhysicalDevice" and len(function.aliasList) > 0:
yield " vk::VkPhysicalDeviceProperties props;"
yield " m_vk.getPhysicalDeviceProperties(physicalDevice, &props);"
yield " if (props.apiVersion >= VK_API_VERSION_1_1)"
yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.name), ", ".join(a.name for a in function.arguments))
yield " else"
yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.aliasList[0]), ", ".join(a.name for a in function.arguments))
else:
yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.name), ", ".join(a.name for a in function.arguments))
yield "}"
writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl())
def writeFuncPtrInterfaceSCImpl (api, filename, functionTypes, className):
normFuncs = {
"createGraphicsPipelines" : "\t\treturn createGraphicsPipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
"createComputePipelines" : "\t\treturn createComputePipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
"createSampler" : "\t\treturn createSamplerHandlerNorm(device, pCreateInfo, pAllocator, pSampler);",
"createSamplerYcbcrConversion" : "\t\treturn createSamplerYcbcrConversionHandlerNorm(device, pCreateInfo, pAllocator, pYcbcrConversion);",
"createDescriptorSetLayout" : "\t\treturn createDescriptorSetLayoutHandlerNorm(device, pCreateInfo, pAllocator, pSetLayout);",
"createPipelineLayout" : "\t\treturn createPipelineLayoutHandlerNorm(device, pCreateInfo, pAllocator, pPipelineLayout);",
"createRenderPass" : "\t\treturn createRenderPassHandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);",
"createRenderPass2" : "\t\treturn createRenderPass2HandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);",
"createCommandPool" : "\t\treturn createCommandPoolHandlerNorm(device, pCreateInfo, pAllocator, pCommandPool);",
"resetCommandPool" : "\t\treturn resetCommandPoolHandlerNorm(device, commandPool, flags);",
"createFramebuffer" : "\t\treturn createFramebufferHandlerNorm(device, pCreateInfo, pAllocator, pFramebuffer);",
}
statFuncs = {
"destroyDevice" : "\t\tdestroyDeviceHandler(device, pAllocator);",
"createDescriptorSetLayout" : "\t\tcreateDescriptorSetLayoutHandlerStat(device, pCreateInfo, pAllocator, pSetLayout);",
"destroyDescriptorSetLayout" : "\t\tdestroyDescriptorSetLayoutHandler(device, descriptorSetLayout, pAllocator);",
"createImageView" : "\t\tcreateImageViewHandler(device, pCreateInfo, pAllocator, pView);",
"destroyImageView" : "\t\tdestroyImageViewHandler(device, imageView, pAllocator);",
"createSemaphore" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(semaphoreRequestCount,1);\n\t\t*pSemaphore = Handle<HANDLE_TYPE_SEMAPHORE>(m_resourceInterface->incResourceCounter());\n\t}",
"destroySemaphore" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(semaphore,semaphoreRequestCount,1);\n\t}",
"createFence" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(fenceRequestCount,1);\n\t\t*pFence = Handle<HANDLE_TYPE_FENCE>(m_resourceInterface->incResourceCounter());\n\t}",
"destroyFence" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(fence,fenceRequestCount,1);\n\t}",
"allocateMemory" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(deviceMemoryRequestCount,1);\n\t\t*pMemory = Handle<HANDLE_TYPE_DEVICE_MEMORY>(m_resourceInterface->incResourceCounter());\n\t}",
"createBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferRequestCount,1);\n\t\t*pBuffer = Handle<HANDLE_TYPE_BUFFER>(m_resourceInterface->incResourceCounter());\n\t}",
"destroyBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(buffer,bufferRequestCount,1);\n\t}",
"createImage" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(imageRequestCount,1);\n\t\t*pImage = Handle<HANDLE_TYPE_IMAGE>(m_resourceInterface->incResourceCounter());\n\t}",
"destroyImage" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(image,imageRequestCount,1);\n\t}",
"createEvent" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(eventRequestCount,1);\n\t\t*pEvent = Handle<HANDLE_TYPE_EVENT>(m_resourceInterface->incResourceCounter());\n\t}",
"destroyEvent" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(event,eventRequestCount,1);\n\t}",
"createQueryPool" : "\t\tcreateQueryPoolHandler(device, pCreateInfo, pAllocator, pQueryPool);",
"createBufferView" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferViewRequestCount,1);\n\t\t*pView = Handle<HANDLE_TYPE_BUFFER_VIEW>(m_resourceInterface->incResourceCounter());\n\t}",
"destroyBufferView" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(bufferView,bufferViewRequestCount,1);\n\t}",
"createPipelineLayout" : "\t\tcreatePipelineLayoutHandlerStat(device, pCreateInfo, pAllocator, pPipelineLayout);",
"destroyPipelineLayout" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineLayout,pipelineLayoutRequestCount,1);\n\t}",
"createRenderPass" : "\t\tcreateRenderPassHandlerStat(device, pCreateInfo, pAllocator, pRenderPass);",
"createRenderPass2" : "\t\tcreateRenderPass2HandlerStat(device, pCreateInfo, pAllocator, pRenderPass);",
"destroyRenderPass" : "\t\tdestroyRenderPassHandler(device, renderPass, pAllocator);",
"createGraphicsPipelines" : "\t\tcreateGraphicsPipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
"createComputePipelines" : "\t\tcreateComputePipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
"destroyPipeline" : "\t\tdestroyPipelineHandler(device, pipeline, pAllocator);",
"createSampler" : "\t\tcreateSamplerHandlerStat(device, pCreateInfo, pAllocator, pSampler);",
"destroySampler" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(sampler,samplerRequestCount,1);\n\t}",
"createDescriptorPool" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(descriptorPoolRequestCount,1);\n\t\t*pDescriptorPool = Handle<HANDLE_TYPE_DESCRIPTOR_POOL>(m_resourceInterface->incResourceCounter());\n\t}",
"resetDescriptorPool" : "\t\tresetDescriptorPoolHandlerStat(device, descriptorPool, flags);",
"allocateDescriptorSets" : "\t\tallocateDescriptorSetsHandlerStat(device, pAllocateInfo, pDescriptorSets);",
"freeDescriptorSets" : "\t\tfreeDescriptorSetsHandlerStat(device, descriptorPool, descriptorSetCount, pDescriptorSets);",
"createFramebuffer" : "\t\tcreateFramebufferHandlerStat(device, pCreateInfo, pAllocator, pFramebuffer);",
"destroyFramebuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(framebuffer,framebufferRequestCount,1);\n\t}",
"createCommandPool" : "\t\tcreateCommandPoolHandlerStat(device, pCreateInfo, pAllocator, pCommandPool);",
"resetCommandPool" : "\t\tresetCommandPoolHandlerStat(device, commandPool, flags);",
"allocateCommandBuffers" : "\t\tallocateCommandBuffersHandler(device, pAllocateInfo, pCommandBuffers);",
"freeCommandBuffers" : "\t\tfreeCommandBuffersHandler(device, commandPool, commandBufferCount, pCommandBuffers);",
"createSamplerYcbcrConversion" : "\t\tcreateSamplerYcbcrConversionHandlerStat(device, pCreateInfo, pAllocator, pYcbcrConversion);",
"destroySamplerYcbcrConversion" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(ycbcrConversion,samplerYcbcrConversionRequestCount,1);\n\t}",
"getDescriptorSetLayoutSupport" : "\t\tgetDescriptorSetLayoutSupportHandler(device, pCreateInfo, pSupport);",
# "" : "surfaceRequestCount",
# "" : "swapchainRequestCount",
# "" : "displayModeRequestCount"
"mapMemory" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tif(m_falseMemory.size() < (static_cast<std::size_t>(offset+size)))\n\t\t\tm_falseMemory.resize(static_cast<std::size_t>(offset+size));\n\t\t*ppData = (void*)m_falseMemory.data();\n\t}",
"getBufferMemoryRequirements" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}",
"getImageMemoryRequirements" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}",
"getBufferMemoryRequirements2" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->memoryRequirements.size = 1048576U;\n\t\tpMemoryRequirements->memoryRequirements.alignment = 1U;\n\t\tpMemoryRequirements->memoryRequirements.memoryTypeBits = ~0U;\n\t}",
"getImageMemoryRequirements2" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->memoryRequirements.size = 1048576U;\n\t\tpMemoryRequirements->memoryRequirements.alignment = 1U;\n\t\tpMemoryRequirements->memoryRequirements.memoryTypeBits = ~0U;\n\t}",
"getImageSubresourceLayout" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpLayout->offset = 0U;\n\t\tpLayout->size = 1048576U;\n\t\tpLayout->rowPitch = 0U;\n\t\tpLayout->arrayPitch = 0U;\n\t\tpLayout->depthPitch = 0U;\n\t}",
"createPipelineCache" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(pipelineCacheRequestCount,1);\n\t\t*pPipelineCache = Handle<HANDLE_TYPE_PIPELINE_CACHE>(m_resourceInterface->incResourceCounter());\n\t}",
"destroyPipelineCache" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineCache,pipelineCacheRequestCount,1);\n\t}",
"cmdUpdateBuffer" : "\t\tincreaseCommandBufferSize(commandBuffer, dataSize);",
"getDeviceQueue" : "\t\tm_vk.getDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);",
}
statReturns = {
"VkResult" : "return VK_SUCCESS;",
"VkDeviceAddress" : "return 0u;",
"uint64_t" : "return 0u;",
}
def makeFuncPtrInterfaceStatisticsImpl ():
for function in api.functions:
if function.getType() in functionTypes:
ifaceName = getInterfaceName(function.name)
yield ""
yield "%s %s::%s (%s) const" % (function.returnType, className, ifaceName, argListToStr(function.arguments))
yield "{"
if ( ifaceName in normFuncs ) or ( ifaceName in statFuncs ):
yield "\tstd::lock_guard<std::mutex> lock(functionMutex);"
if ifaceName != "getDeviceProcAddr" :
yield "\tif (m_normalMode)"
if ifaceName in normFuncs :
yield "%s" % ( normFuncs[ifaceName] )
else:
yield "\t\t%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", ifaceName, ", ".join(a.name for a in function.arguments))
if ifaceName in statFuncs :
yield "\telse"
yield "%s" % ( statFuncs[ifaceName] )
elif ifaceName[:3] == "cmd" :
yield "\telse"
yield "\t\tincreaseCommandBufferSize(commandBuffer, 0u);"
if function.returnType in statReturns:
yield "\t%s" % ( statReturns[function.returnType] )
yield "}"
writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceStatisticsImpl())
def writeStrUtilProto (api, filename):
def makeStrUtilProto ():
for line in indentLines(["const char*\tget%sName\t(%s value);" % (enum.name[2:], enum.name) for enum in api.enums if enum.type == "enum"]):
yield line
yield ""
for line in indentLines(["inline tcu::Format::Enum<%s>\tget%sStr\t(%s value)\t{ return tcu::Format::Enum<%s>(get%sName, value);\t}" % (e.name, e.name[2:], e.name, e.name, e.name[2:]) for e in api.enums if e.type == "enum"]):
yield line
yield ""
for line in indentLines(["inline std::ostream&\toperator<<\t(std::ostream& s, %s value)\t{ return s << get%sStr(value);\t}" % (e.name, e.name[2:]) for e in api.enums if e.type == "enum"]):
yield line
yield ""
for line in indentLines(["tcu::Format::Bitfield<%s>\tget%sStr\t(%s value);" % (("64" if b.type == "VkFlags64" else "32"), b.name[2:], b.name) for b in api.bitmasks]):
yield line
yield ""
for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.compositeTypes]):
yield line
writeInlFile(filename, INL_HEADER, makeStrUtilProto())
def writeStrUtilImpl (api, filename):
def makeStrUtilImpl ():
for line in indentLines(["template<> const char*\tgetTypeName<%s>\t(void) { return \"%s\";\t}" % (handle.name, handle.name) for handle in api.handles]):
yield line
yield ""
yield "namespace %s" % PLATFORM_TYPE_NAMESPACE
yield "{"
for line in indentLines("std::ostream& operator<< (std::ostream& s, %s\tv) { return s << tcu::toHex(v.internal); }" % ''.join(s) for n, s, c in PLATFORM_TYPES):
yield line
yield "}"
savedBitmasks = []
for enum in api.enums:
if enum.type == "enum":
yield ""
yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name)
yield "{"
yield "\tswitch (value)"
yield "\t{"
enumValues = []
lastValue = 0x7FFFFFFF
for e in enum.enumeratorList:
enumValues.append(f"\t\tcase {e.name}:\treturn \"{e.name}\";")
enumValues.append("\t\tdefault:\treturn DE_NULL;")
for line in indentLines(enumValues):
yield line
yield "\t}"
yield "}"
elif enum.type == "bitmask":
# find bitfield that uses those bitmasks
foundBitmask = None
for bitmask in api.bitmasks:
if bitmask.requires == enum.name or bitmask.bitvalues == enum.name:
foundBitmask = bitmask
break
if foundBitmask == None:
continue
savedBitmasks.append(foundBitmask.name)
bitSize = "64" if foundBitmask.type == "VkFlags64" else "32"
yield ""
yield f"tcu::Format::Bitfield<{bitSize}> get{bitmask.name[2:]}Str ({bitmask.name} value)"
yield "{"
yield "\tstatic const tcu::Format::BitDesc s_desc[] ="
yield "\t{"
if len(enum.enumeratorList) == 0:
# some bitfields in SC have no items
yield f"\t\ttcu::Format::BitDesc(0, \"0\")"
else:
for line in indentLines([f"\t\ttcu::Format::BitDesc({e.name},\t\"{e.name}\")," for e in enum.enumeratorList]):
yield line
yield "\t};"
yield f"\treturn tcu::Format::Bitfield<{bitSize}>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));"
yield "}"
for bitmask in api.bitmasks:
if bitmask.name not in savedBitmasks:
bitSize = "64" if bitmask.type == "VkFlags64" else "32"
yield ""
yield f"tcu::Format::Bitfield<{bitSize}> get{bitmask.name[2:]}Str ({bitmask.name} value)"
yield "{"
yield f"\treturn tcu::Format::Bitfield<{bitSize}>(value, DE_NULL, DE_NULL);"
yield "}"
bitfieldTypeNames = set([bitmask.name for bitmask in api.bitmasks])
for type in api.compositeTypes:
yield ""
yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % type.name
yield "{"
yield "\ts << \"%s = {\\n\";" % type.name
for member in type.members:
memberName = member.name
valFmt = None
newLine = ""
if member.type in bitfieldTypeNames:
operator = '*' if member.pointer == '*' else ''
valFmt = "get%sStr(%svalue.%s)" % (member.type[2:], operator, member.name)
elif member.type == "char" and member.pointer == '*':
valFmt = "getCharPtrStr(value.%s)" % member.name
elif member.type == PLATFORM_TYPE_NAMESPACE + "::Win32LPCWSTR":
valFmt = "getWStr(value.%s)" % member.name
elif len(member.arraySizeList) == 1:
if member.name in ["extensionName", "deviceName", "layerName", "description"]:
valFmt = "(const char*)value.%s" % member.name
elif member.type == 'char' or member.type == 'uint8_t':
newLine = "'\\n' << "
valFmt = "tcu::formatArray(tcu::Format::HexIterator<%s>(DE_ARRAY_BEGIN(value.%s)), tcu::Format::HexIterator<%s>(DE_ARRAY_END(value.%s)))" % (member.type, member.name, member.type, member.name)
else:
if member.name == "memoryTypes" or member.name == "memoryHeaps":
endIter = "DE_ARRAY_BEGIN(value.%s) + value.%sCount" % (member.name, member.name[:-1])
else:
endIter = "DE_ARRAY_END(value.%s)" % member.name
newLine = "'\\n' << "
valFmt = "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), %s)" % (member.name, endIter)
memberName = member.name
elif len(member.arraySizeList) > 1:
yield f"\ts << \"\\t{member.name} = \" << '\\n';"
dim = 0
index = ''
dimensionCount = len(member.arraySizeList)
while dim < dimensionCount-1:
yield f"\tfor(deUint32 i{dim} = 0 ; i{dim} < {member.arraySizeList[dim]} ; ++i{dim})"
index += f"[i{dim}]"
dim +=1
yield f"\t\ts << tcu::formatArray(DE_ARRAY_BEGIN(value.{member.name}{index}), DE_ARRAY_END(value.{member.name}{index})) << '\\n';"
# move to next member
continue
else:
valFmt = "value.%s" % member.name
yield ("\ts << \"\\t%s = \" << " % memberName) + newLine + valFmt + " << '\\n';"
yield "\ts << '}';"
yield "\treturn s;"
yield "}"
writeInlFile(filename, INL_HEADER, makeStrUtilImpl())
def writeObjTypeImpl (api, filename):
def makeObjTypeImpl ():
yield "namespace vk"
yield "{"
yield "template<typename T> VkObjectType getObjectType (void);"
for line in indentLines(["template<> inline VkObjectType\tgetObjectType<%s>\t(void) { return %s;\t}" % (handle.name, prefixName("VK_OBJECT_TYPE_", handle.name)) for handle in api.handles]):
yield line
yield "}"
writeInlFile(filename, INL_HEADER, makeObjTypeImpl())
class ConstructorFunction:
def __init__ (self, type, name, objectType, ifaceArgs, arguments):
self.type = type
self.name = name
self.objectType = objectType
self.ifaceArgs = ifaceArgs
self.arguments = arguments
def getConstructorFunctions (api):
funcs = []
ifacesDict = {
Function.TYPE_PLATFORM: [FunctionArgument("vk", "const ", "PlatformInterface&")],
Function.TYPE_INSTANCE: [FunctionArgument("vk", "const ", "InstanceInterface&")],
Function.TYPE_DEVICE: [FunctionArgument("vk", "const ", "DeviceInterface&")]}
for function in api.functions:
if (function.name[:8] == "vkCreate" or function.name == "vkAllocateMemory") and not "createInfoCount" in [a.name for a in function.arguments]:
if function.name == "vkCreateDisplayModeKHR":
continue # No way to delete display modes (bug?)
ifaceArgs = []
if function.name == "vkCreateDevice":
ifaceArgs = [FunctionArgument("vkp", "const ", "PlatformInterface&"),
FunctionArgument("instance", "", "VkInstance")]
ifaceArgs.extend(ifacesDict[function.getType()])
assert (function.arguments[-2].type == "VkAllocationCallbacks" and \
"const" in function.arguments[-2].qualifiers and \
function.arguments[-2].pointer == "*")
objectType = function.arguments[-1].type
arguments = function.arguments[:-1]
funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function.name), objectType, ifaceArgs, arguments))
return funcs
def addVersionDefines(versionSpectrum):
output = ["#define " + ver.getDefineName() + " " + ver.getInHex() for ver in versionSpectrum if not ver.isStandardVersion()]
return output
def writeRefUtilProto (api, filename):
functions = getConstructorFunctions(api)
def makeRefUtilProto ():
unindented = []
for line in indentLines(["Move<%s>\t%s\t(%s = DE_NULL);" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments)) for function in functions]):
yield line
writeInlFile(filename, INL_HEADER, makeRefUtilProto())
def writeRefUtilImpl (api, filename):
functions = getConstructorFunctions(api)
def makeRefUtilImpl ():
yield "namespace refdetails"
yield "{"
yield ""
for function in api.functions:
if function.getType() == Function.TYPE_DEVICE \
and (function.name[:9] == "vkDestroy" or function.name == "vkFreeMemory") \
and not function.name == "vkDestroyDevice":
objectType = function.arguments[-2].type
yield "template<>"
yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType)
yield "{"
yield "\tm_deviceIface->%s(m_device, obj, m_allocator);" % (getInterfaceName(function.name))
yield "}"
yield ""
yield "} // refdetails"
yield ""
dtorDict = {
Function.TYPE_PLATFORM: "object",
Function.TYPE_INSTANCE: "instance",
Function.TYPE_DEVICE: "device"
}
for function in functions:
deleterArgsString = ''
if function.name == "createDevice":
# createDevice requires two additional parameters to setup VkDevice deleter
deleterArgsString = "vkp, instance, object, " + function.arguments[-1].name
else:
deleterArgsString = "vk, %s, %s" % (dtorDict[function.type], function.arguments[-1].name)
yield "Move<%s> %s (%s)" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments))
yield "{"
yield "\t%s object = 0;" % function.objectType
yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"]))
yield "\treturn Move<%s>(check<%s>(object), Deleter<%s>(%s));" % (function.objectType, function.objectType, function.objectType, deleterArgsString)
yield "}"
yield ""
writeInlFile(filename, INL_HEADER, makeRefUtilImpl())
def writeStructTraitsImpl (api, filename):
def gen ():
for cType in api.compositeTypes:
if cType.category == "struct" and cType.members[0].name == "sType" and cType.name != "VkBaseOutStructure" and cType.name != "VkBaseInStructure":
yield "template<> VkStructureType getStructureType<%s> (void)" % cType.name
yield "{"
yield "\treturn %s;" % cType.members[0].values
yield "}"
yield ""
writeInlFile(filename, INL_HEADER, gen())
def writeNullDriverImpl (api, filename):
def genNullDriverImpl ():
specialFuncNames = [
"vkCreateGraphicsPipelines",
"vkCreateComputePipelines",
"vkCreateRayTracingPipelinesNV",
"vkCreateRayTracingPipelinesKHR",
"vkGetInstanceProcAddr",
"vkGetDeviceProcAddr",
"vkEnumeratePhysicalDevices",
"vkEnumerateInstanceExtensionProperties",
"vkEnumerateDeviceExtensionProperties",
"vkGetPhysicalDeviceFeatures",
"vkGetPhysicalDeviceFeatures2KHR",
"vkGetPhysicalDeviceProperties",
"vkGetPhysicalDeviceProperties2KHR",
"vkGetPhysicalDeviceQueueFamilyProperties",
"vkGetPhysicalDeviceMemoryProperties",
"vkGetPhysicalDeviceFormatProperties",
"vkGetPhysicalDeviceImageFormatProperties",
"vkGetDeviceQueue",
"vkGetBufferMemoryRequirements",
"vkGetBufferMemoryRequirements2KHR",
"vkGetImageMemoryRequirements",
"vkGetImageMemoryRequirements2KHR",
"vkAllocateMemory",
"vkMapMemory",
"vkUnmapMemory",
"vkAllocateDescriptorSets",
"vkFreeDescriptorSets",
"vkResetDescriptorPool",
"vkAllocateCommandBuffers",
"vkFreeCommandBuffers",
"vkCreateDisplayModeKHR",
"vkCreateSharedSwapchainsKHR",
"vkGetPhysicalDeviceExternalBufferPropertiesKHR",
"vkGetPhysicalDeviceImageFormatProperties2KHR",
"vkGetMemoryAndroidHardwareBufferANDROID",
"vkCreateShadersEXT",
]
specialFuncs = [f for f in api.functions if f.name in specialFuncNames]
createFuncs = [f for f in api.functions if (f.name[:8] == "vkCreate" or f.name == "vkAllocateMemory") and not f in specialFuncs]
destroyFuncs = [f for f in api.functions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs]
dummyFuncs = [f for f in api.functions if f not in specialFuncs + createFuncs + destroyFuncs]
def getHandle (name):
for handle in api.handles:
if handle.name == name:
return handle
raise Exception("No such handle: %s" % name)
for function in createFuncs:
objectType = function.arguments[-1].type
argsStr = ", ".join([a.name for a in function.arguments[:-1]])
yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments))
yield "{"
yield "\tDE_UNREF(%s);" % function.arguments[-2].name
if function.arguments[-1].len != None:
yield "\tVK_NULL_RETURN((allocateNonDispHandleArray<%s, %s>(%s, %s)));" % (objectType[2:], objectType, argsStr, function.arguments[-1].name)
else:
if getHandle(objectType).type == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr)
else:
yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr)
yield "}"
yield ""
for function in destroyFuncs:
objectArg = function.arguments[-2]
yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments))
yield "{"
for arg in function.arguments[:-2]:
yield "\tDE_UNREF(%s);" % arg.name
if getHandle(objectArg.type).type == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name)
else:
yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name)
yield "}"
yield ""
for function in dummyFuncs:
yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments))
yield "{"
for arg in function.arguments:
yield "\tDE_UNREF(%s);" % arg.name
if function.returnType != "void":
yield "\treturn VK_SUCCESS;"
yield "}"
yield ""
def genFuncEntryTable (type, name):
entries = []
pattern = "\tVK_NULL_FUNC_ENTRY(%s,\t%s),"
for f in api.functions:
if f.getType() != type:
continue
entries.append(pattern % (f.name, getInterfaceName(f.name)))
yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name
yield "{"
for line in indentLines(entries):
yield line
yield "};"
yield ""
# Func tables
for line in genFuncEntryTable(Function.TYPE_PLATFORM, "s_platformFunctions"):
yield line
for line in genFuncEntryTable(Function.TYPE_INSTANCE, "s_instanceFunctions"):
yield line
for line in genFuncEntryTable(Function.TYPE_DEVICE, "s_deviceFunctions"):
yield line
writeInlFile(filename, INL_HEADER, genNullDriverImpl())
def writeTypeUtil (api, filename):
# Structs filled by API queries are not often used in test code
QUERY_RESULT_TYPES = set([
"VkPhysicalDeviceFeatures",
"VkPhysicalDeviceLimits",
"VkFormatProperties",
"VkImageFormatProperties",
"VkPhysicalDeviceSparseProperties",
"VkQueueFamilyProperties",
"VkMemoryType",
"VkMemoryHeap",
"StdVideoH264SpsVuiFlags",
"StdVideoH264SpsFlags",
"StdVideoH264PpsFlags",
"StdVideoDecodeH264PictureInfoFlags",
"StdVideoDecodeH264ReferenceInfoFlags",
"StdVideoEncodeH264SliceHeaderFlags",
"StdVideoEncodeH264PictureInfoFlags",
"StdVideoEncodeH264ReferenceInfoFlags",
"StdVideoEncodeH264ReferenceInfoFlags",
"StdVideoH265HrdFlags",
"StdVideoH265VpsFlags",
"StdVideoH265SpsVuiFlags",
"StdVideoH265SpsFlags",
"StdVideoH265PpsFlags",
"StdVideoDecodeH265PictureInfoFlags",
"StdVideoDecodeH265ReferenceInfoFlags",
"StdVideoEncodeH265PictureInfoFlags",
"StdVideoEncodeH265ReferenceInfoFlags",
"StdVideoEncodeH265SliceSegmentHeaderFlags",
"StdVideoH265ProfileTierLevelFlags",
"StdVideoH265ShortTermRefPicSetFlags",
"StdVideoEncodeH264ReferenceListsInfoFlags",
"StdVideoEncodeH265ReferenceListsInfoFlags",
])
def isSimpleStruct (type):
def hasArrayMember (type):
for member in type.members:
if len(member.arraySizeList) > 0:
return True
return False
def hasCompositeMember (type):
for member in type.members:
if member.pointer is not None and '*' not in member.pointer:
match = [c for c in api.compositeTypes if member.type == c.name]
if len(match) > 0:
return True
return False
return type.category == "struct" and \
type.members[0].type != "VkStructureType" and \
not type.name in QUERY_RESULT_TYPES and \
not hasArrayMember(type) and \
not hasCompositeMember(type)
def gen ():
for type in api.compositeTypes:
if not isSimpleStruct(type):
continue
name = type.name[2:] if type.name[:2].lower() == "vk" else type.name
yield ""
yield "inline %s make%s (%s)" % (type.name, name, argListToStr(type.members))
yield "{"
yield "\t%s res;" % type.name
for line in indentLines(["\tres.%s\t= %s;" % (m.name, m.name) for m in type.members]):
yield line
yield "\treturn res;"
yield "}"
writeInlFile(filename, INL_HEADER, gen())
def writeDriverIds(api, filename):
driverIdsString = []
driverIdsString.append("static const struct\n"
"{\n"
"\tstd::string driver;\n"
"\tuint32_t id;\n"
"} driverIds [] =\n"
"{")
driverItems = dict()
driverIdEnum = [enum for enum in api.enums if enum.name == 'VkDriverId'][0]
for enumerator in driverIdEnum.enumeratorList:
driverIdsString.append(f"\t{{\"{enumerator.name}\", {enumerator.value}}},")
driverItems[enumerator.name] = enumerator.value
for enumerator in driverIdEnum.enumeratorList:
if len(enumerator.aliasList) > 0:
driverIdsString.append(f"\t{{\"{enumerator.aliasList[0]}\", {enumerator.value}}},\t// {enumerator.name}")
driverIdsString.append("\t{\"VK_DRIVER_ID_MAX_ENUM\", 0x7FFFFFFF}")
driverIdsString.append("};")
writeInlFile(filename, INL_HEADER, driverIdsString)
def writeSupportedExtensions(api, filename):
def writeExtensionsForVersions(map):
result = []
for version in map:
result.append(" if (coreVersion >= " + str(version) + ")")
result.append(" {")
for extension in map[version]:
result.append(' dst.push_back("' + extension.name + '");')
result.append(" }")
if not map:
result.append(" DE_UNREF(coreVersion);")
return result
isSC = api.apiName == 'vulkansc'
instanceMap = {}
deviceMap = {}
for ext in api.extensions:
if ext.promotedto is None or "VK_VERSION" not in ext.promotedto:
continue
# skip partialy promoted extensions
if ext.partiallyPromoted is True:
continue
major = int(ext.promotedto[-3])
minor = int(ext.promotedto[-1])
currVersion = "VK_API_VERSION_" + ext.promotedto[-3:]
# VulkanSC is based on Vulkan 1.2. Any Vulkan version greater than 1.2 should be excluded
if isSC and major==1 and minor>2:
continue
if ext.type == 'instance':
list = instanceMap.get(currVersion)
instanceMap[currVersion] = list + [ext] if list else [ext]
else:
list = deviceMap.get(currVersion)
deviceMap[currVersion] = list + [ext] if list else [ext]
# add list of extensions missing in Vulkan SC specification
if isSC:
for extensionName, data in api.additionalExtensionData:
# make sure that this extension was registered
if 'register_extension' not in data.keys():
continue
# save array containing 'device' or 'instance' string followed by the optional vulkan version in which this extension is core;
# note that register_extension section is also required for partialy promoted extensions like VK_EXT_extended_dynamic_state2
# but those extensions should not fill 'core' tag
match = re.match("(\d).(\d).(\d).(\d)", data['register_extension']['core'])
if match == None:
continue
major = int(match.group(2))
minor = int(match.group(3))
if major==1 and minor>2:
continue
currVersion = f"VK_API_VERSION_{major}_{minor}"
ext = Extension(extensionName, 0, 0, 0, 0, 0, 0, 0)
if data['register_extension']['type'] == 'instance':
list = instanceMap.get(currVersion)
instanceMap[currVersion] = list + [ext] if list else [ext]
else:
list = deviceMap.get(currVersion)
deviceMap[currVersion] = list + [ext] if list else [ext]
lines = [
"",
"void getCoreDeviceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(deviceMap) != 0 or isSC else ""),
"{"] + writeExtensionsForVersions(deviceMap) + [
"}",
"",
"void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(instanceMap) != 0 or isSC else ""),
"{"] + writeExtensionsForVersions(instanceMap) + [
"}",
""]
writeInlFile(filename, INL_HEADER, lines)
def writeExtensionFunctions (api, filename):
def writeExtensionNameArrays ():
instanceExtensionNames = [f"\t\"{ext.name}\"," for ext in api.extensions if ext.type == "instance"]
deviceExtensionNames = [f"\t\"{ext.name}\"," for ext in api.extensions if ext.type == "device"]
yield '::std::string instanceExtensionNames[] =\n{'
for instanceExtName in instanceExtensionNames:
yield instanceExtName
yield '};\n'
yield '::std::string deviceExtensionNames[] =\n{'
for deviceExtName in deviceExtensionNames:
yield deviceExtName
yield '};'
def writeExtensionFunctions (functionType):
isFirstWrite = True
dg_list = [] # Device groups functions need special casing, as Vulkan 1.0 keeps them in VK_KHR_device_groups whereas 1.1 moved them into VK_KHR_swapchain
if functionType == Function.TYPE_INSTANCE:
yield 'void getInstanceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{'
dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"]
elif functionType == Function.TYPE_DEVICE:
yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{'
dg_list = ["vkGetDeviceGroupPresentCapabilitiesKHR", "vkGetDeviceGroupSurfacePresentModesKHR", "vkAcquireNextImage2KHR"]
for ext in api.extensions:
funcNames = []
for requirement in ext.requirementsList:
for requiredCommand in requirement.newCommands:
commandName = requiredCommand.name
# find function that has specified name
func = None
funcList = [f for f in api.functions if f.name == commandName]
# if name was not found check if this is alias
if len(funcList) == 0:
for f in api.functions:
for aliasName in f.aliasList:
if aliasName == commandName:
func = f
break
if func:
break
else:
func = funcList[0]
if func == None:
if api.apiName == "vulkansc":
continue
# something went wrong, for "vulkan" func should always be found
assert(False)
if func.getType() == functionType:
# only add functions with same vendor as extension
# this is a workaround for entrypoints requiring more
# than one extension and lack of the dependency in vk.xml
vendor = ext.name.split('_')[1]
if commandName.endswith(vendor):
funcNames.append(commandName)
if ext.name:
yield '\tif (extName == "%s")' % ext.name
yield '\t{'
for funcName in funcNames:
if funcName in dg_list:
yield '\t\tif(apiVersion >= VK_API_VERSION_1_1) functions.push_back("%s");' % funcName
else:
yield '\t\tfunctions.push_back("%s");' % funcName
if ext.name == "VK_KHR_device_group":
for dg_func in dg_list:
yield '\t\tif(apiVersion < VK_API_VERSION_1_1) functions.push_back("%s");' % dg_func
yield '\t\treturn;'
yield '\t}'
isFirstWrite = False
if not isFirstWrite:
yield '\tDE_FATAL("Extension name not found");'
yield '}'
lines = ['']
for line in writeExtensionFunctions(Function.TYPE_INSTANCE):
lines += [line]
lines += ['']
for line in writeExtensionFunctions(Function.TYPE_DEVICE):
lines += [line]
lines += ['']
for line in writeExtensionNameArrays():
lines += [line]
writeInlFile(filename, INL_HEADER, lines)
def writeCoreFunctionalities(api, filename):
functionOriginValues = ["FUNCTIONORIGIN_PLATFORM", "FUNCTIONORIGIN_INSTANCE", "FUNCTIONORIGIN_DEVICE"]
functionNamesPerApiVersionDict = {}
for feature in api.features:
apiVersion = "VK_API_VERSION_" + feature.number.replace('.', '_')
functionNamesPerApiVersionDict[apiVersion] = []
for r in feature.requirementsList:
functionNamesPerApiVersionDict[apiVersion].extend(r.commandList)
lines = [
"",
'enum FunctionOrigin', '{'] + [line for line in indentLines([
'\t' + functionOriginValues[0] + '\t= 0,',
'\t' + functionOriginValues[1] + ',',
'\t' + functionOriginValues[2]])] + [
"};",
"",
"typedef ::std::pair<const char*, FunctionOrigin> FunctionInfo;",
"typedef ::std::vector<FunctionInfo> FunctionInfosList;",
"typedef ::std::map<uint32_t, FunctionInfosList> ApisMap;",
"",
"void initApisMap (ApisMap& apis)",
"{",
" apis.clear();"] + [
" apis.insert(::std::pair<uint32_t, FunctionInfosList>(" + v + ", FunctionInfosList()));" for v in functionNamesPerApiVersionDict] + [
""]
apiVersions = []
functionLines = []
for apiVersion in functionNamesPerApiVersionDict:
# iterate over names of functions added with api
for functionName in functionNamesPerApiVersionDict[apiVersion]:
# search for data of this function in all functions list
functionData = None
for f in api.functions:
if functionName == f.name or functionName in f.aliasList:
functionData = f
break
if functionData == None:
if api.apiName == "vulkansc":
continue
# something went wrong, for "vulkan" functionData should always be found
assert(False)
# add line coresponding to this function
functionLines.append('\tapis[{0}].push_back(FunctionInfo("' + functionName + '",\t' + functionOriginValues[functionData.getType()] + '));')
# functions for every api version should also include all functions from previous versions
specializedLines = [line.format(apiVersion) for line in functionLines]
# indent all functions of specified api and add them to main list
lines = lines + [line for line in indentLines(specializedLines)] + [""]
lines = lines + ["}"]
writeInlFile(filename, INL_HEADER, lines)
def camelToSnake(name):
name = re.sub('([a-z])([23])D([A-Z])', r'\1_\2d\3', name)
name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()
def writeDeviceFeatures2(api, filename):
def structInAPI(compositeObject):
for c in api.compositeTypes:
if c.name == compositeObject.name:
return True
return False
# helper class used to encapsulate all data needed during generation
class StructureDetail:
def __init__ (self, compositeObject):
self.nameList = [compositeObject.name] + compositeObject.aliasList
self.sType = compositeObject.members[0].values
self.instanceName = 'd' + compositeObject.name[11:]
self.flagName = 'is' + compositeObject.name[16:]
self.extension = None
self.api = None
self.major = None
self.minor = None
structureMembers = compositeObject.members[2:]
self.members = [m.name for m in structureMembers]
# helper extension class used in algorith below
class StructureFoundContinueToNextOne(Exception):
pass
# find structures that extend VkPhysicalDeviceFeatures2
structures = [c for c in api.compositeTypes if c.structextends is not None and 'VkPhysicalDeviceFeatures2' in c.structextends]
# remove structures that were added by extensions other than KHR and EXT
testedStructures = []
for s in structures:
if all([postfix not in s.name for postfix in EXTENSION_POSTFIXES_VENDOR]):
testedStructures.append(s)
existingStructures = list(filter(structInAPI, testedStructures)) # remove features not found in API ( important for Vulkan SC )
testedStructureDetail = [StructureDetail(struct) for struct in existingStructures]
# iterate over all searched structures and find extensions that enabled them
for structureDetail in testedStructureDetail:
try:
# iterate over all extensions
for extension in api.extensions:
for requirement in extension.requirementsList:
for extensionStructure in requirement.newTypes:
if extensionStructure.name in structureDetail.nameList:
structureDetail.extension = extension.name
if extension.promotedto is not None and extension.partiallyPromoted is False:
# check if extension was promoted to vulkan version or other extension
if 'VK_VERSION' in extension.promotedto:
versionSplit = extension.promotedto.split('_')
structureDetail.api = 0 if api.apiName == "vulkan" else 1
structureDetail.major = versionSplit[-2]
structureDetail.minor = versionSplit[-1]
else:
structureDetail.extension = extension.promotedto
raise StructureFoundContinueToNextOne
except StructureFoundContinueToNextOne:
continue
structureDetailToRemove = []
for structureDetail in testedStructureDetail:
if structureDetail.major is not None:
continue
# if structure was not added with extension then check if
# it was added directly with one of vulkan versions
structureName = structureDetail.nameList[0]
for feature in api.features:
for requirement in feature.requirementsList:
if structureName in requirement.typeList:
if api.apiName == "vulkansc" and int(feature.number[-1]) > 2:
structureDetailToRemove.append(structureDetail)
else:
versionSplit = feature.name.split('_')
structureDetail.api = 0 if api.apiName == "vulkan" else 1
structureDetail.major = versionSplit[-2]
structureDetail.minor = versionSplit[-1]
break
if structureDetail.major is not None:
break
# remove structures that should not be tested for given api version
for sd in structureDetailToRemove:
testedStructureDetail.remove(sd)
# generate file content
structureDefinitions = []
featureEnabledFlags = []
clearStructures = []
structureChain = []
logStructures = []
verifyStructures = []
for index, structureDetail in enumerate(testedStructureDetail):
structureName = structureDetail.nameList[0]
# create two instances of each structure
nameSpacing = '\t'
structureDefinitions.append(structureName + nameSpacing + structureDetail.instanceName + '[count];')
# create flags that check if proper extension or vulkan version is available
condition = ''
extension = structureDetail.extension
major = structureDetail.major
if extension is not None:
condition = ' checkExtension(properties, "' + extension + '")'
if major is not None:
condition = ' ' if condition == '' else condition + ' || '
condition += 'context.contextSupports(vk::ApiVersion(' + str(structureDetail.api) + ', ' + str(major) + ', ' + str(structureDetail.minor) + ', 0))'
if condition == '':
condition = ' true'
condition += ';'
nameSpacing = '\t' * int((len(structureName) - 4) / 4)
featureEnabledFlags.append('const bool' + nameSpacing + structureDetail.flagName + ' =' + condition)
# clear memory of each structure
clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx], 0xFF * ndx, sizeof(' + structureName + '));')
# construct structure chain
nextInstanceName = 'DE_NULL';
if index < len(testedStructureDetail)-1:
nextInstanceName = '&' + testedStructureDetail[index+1].instanceName + '[ndx]'
structureChain.append([
'\t\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.flagName + ' ? ' + structureDetail.sType + ' : VK_STRUCTURE_TYPE_MAX_ENUM;',
'\t\t' + structureDetail.instanceName + '[ndx].pNext = DE_NULL;'])
# construct log section
logStructures.append([
'\tif (' + structureDetail.flagName + ')',
'\t\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;'
])
#construct verification section
verifyStructure = []
verifyStructure.append('\tif (' + structureDetail.flagName + ' &&')
for index, m in enumerate(structureDetail.members):
prefix = '\t\t(' if index == 0 else '\t\t '
postfix = '))' if index == len(structureDetail.members)-1 else ' ||'
verifyStructure.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix)
if len(structureDetail.members) == 0:
verifyStructure.append('\t\tfalse)')
verifyStructure.append('\t{\n\t\tTCU_FAIL("Mismatch between ' + structureName + '");\n\t}')
verifyStructures.append(verifyStructure)
# construct file content
stream = []
# individual test functions
for n, x in enumerate(testedStructureDetail):
stream.append("tcu::TestStatus testPhysicalDeviceFeature" + x.instanceName[len('device'):]+" (Context& context)")
stream.append("""{
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
const CustomInstance instance (createCustomInstanceWithExtension(context, "VK_KHR_get_physical_device_properties2"));
const InstanceDriver& vki (instance.getDriver());
const int count = 2u;
TestLog& log = context.getTestContext().getLog();
VkPhysicalDeviceFeatures2 extFeatures;
vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL);
""")
stream.append("\t"+structureDefinitions[n])
stream.append("\t"+featureEnabledFlags[n])
stream.append('')
stream.append('\tfor (int ndx = 0; ndx < count; ++ndx)\n\t{')
stream.append("\t" + clearStructures[n])
stream.extend(structureChain[n])
stream.append('')
stream.append(
'\t\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n'
'\t\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n'
'\t\textFeatures.pNext = &' + testedStructureDetail[n].instanceName + '[ndx];\n\n'
'\t\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);')
stream.append('\t}\n')
stream.extend(logStructures[n])
stream.append('')
stream.extend(verifyStructures[n])
stream.append('\treturn tcu::TestStatus::pass("Querying succeeded");')
stream.append("}\n")
allApiVersions = [f.number for f in api.features]
promotedTests = []
if api.apiName == "vulkan":
for feature in api.features:
major = feature.number[0]
minor = feature.number[-1]
promotedFeatures = []
if feature.name == 'VK_VERSION_1_0':
continue
for requirement in feature.requirementsList:
for type in requirement.typeList:
matchedStructType = re.search(f'VkPhysicalDevice(\w+)Features', type, re.IGNORECASE)
matchedCoreStructType = re.search(f'VkPhysicalDeviceVulkan(\d+)Features', type, re.IGNORECASE)
if matchedStructType and not matchedCoreStructType:
promotedFeatures.append(type)
if promotedFeatures:
testName = "createDeviceWithPromoted" + feature.number.replace('.', '') + "Structures"
promotedTests.append(testName)
stream.append("tcu::TestStatus " + testName + " (Context& context)")
stream.append("{")
stream.append(
' if (!context.contextSupports(vk::ApiVersion(0, ' + major + ', ' + minor + ', 0)))\n'
' TCU_THROW(NotSupportedError, "Vulkan ' + major + '.' + minor + ' is not supported");')
stream.append("""
const PlatformInterface& platformInterface = context.getPlatformInterface();
const CustomInstance instance (createCustomInstanceFromContext(context));
const InstanceDriver& instanceDriver (instance.getDriver());
const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine());
const deUint32 queueFamilyIndex = 0;
const deUint32 queueCount = 1;
const deUint32 queueIndex = 0;
const float queuePriority = 1.0f;
const vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
DE_NULL,
(VkDeviceQueueCreateFlags)0u,
queueFamilyIndex, //queueFamilyIndex;
queueCount, //queueCount;
&queuePriority, //pQueuePriorities;
};
""")
lastFeature = ''
usedFeatures = []
for feature in promotedFeatures:
for struct in testedStructureDetail:
if (struct.instanceName in usedFeatures):
continue
if feature in struct.nameList:
if lastFeature:
stream.append("\t" + feature + " " + struct.instanceName + " = initVulkanStructure(&" + lastFeature + ");")
else:
stream.append("\t" + feature + " " + struct.instanceName + " = initVulkanStructure();")
lastFeature = struct.instanceName
usedFeatures.append(struct.instanceName)
break
stream.append("\tVkPhysicalDeviceFeatures2 extFeatures = initVulkanStructure(&" + lastFeature + ");")
stream.append("""
instanceDriver.getPhysicalDeviceFeatures2 (physicalDevice, &extFeatures);
const VkDeviceCreateInfo deviceCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
&extFeatures, //pNext;
(VkDeviceCreateFlags)0u,
1, //queueRecordCount;
&deviceQueueCreateInfo, //pRequestedQueues;
0, //layerCount;
DE_NULL, //ppEnabledLayerNames;
0, //extensionCount;
DE_NULL, //ppEnabledExtensionNames;
DE_NULL, //pEnabledFeatures;
};
const Unique<VkDevice> device (createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), platformInterface, instance, instanceDriver, physicalDevice, &deviceCreateInfo));
const DeviceDriver deviceDriver (platformInterface, instance, device.get(), context.getUsedApiVersion());
const VkQueue queue = getDeviceQueue(deviceDriver, *device, queueFamilyIndex, queueIndex);
VK_CHECK(deviceDriver.queueWaitIdle(queue));
return tcu::TestStatus::pass("Pass");
}
""")
# function to create tests
stream.append("void addSeparateFeatureTests (tcu::TestCaseGroup* testGroup)\n{")
for x in testedStructureDetail:
stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x.instanceName[len('device'):]) + '", "' + x.nameList[0] + '", testPhysicalDeviceFeature' + x.instanceName[len('device'):] + ');')
for x in promotedTests:
stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x) + '", "", ' + x + ');')
stream.append('}\n')
# write out
writeInlFile(filename, INL_HEADER, stream)
def generateDeviceFeaturesOrPropertiesDefs(api, FeaturesOrProperties):
assert(FeaturesOrProperties in ['Features', 'Properties'])
defs = []
foundStructureEnums = []
structureEnumPattern = f'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_{FeaturesOrProperties.upper()}(\w+)'
structureEnumPatternNotExtension = structureEnumPattern[:-5] + '$'
structureTypePattern = f'VkPhysicalDevice(\w+){FeaturesOrProperties}(\w+)'
structureTypePatternNotExtension = structureTypePattern[:-5] + '$'
structureTypeToSkipPattern = f'VkPhysicalDeviceVulkan\d\d{FeaturesOrProperties}'
structureExtendsPattern = f'VkPhysicalDevice{FeaturesOrProperties}2'
# iterate over all extensions to find extension that adds enum value matching pattern;
# this will always be in first requirement section
for ext in api.extensions:
# skip extensions that were promoted to other extensions (not vk version)
if ext.promotedto is not None and "VK_VERSION" not in ext.promotedto:
continue
allExtendedEnums = ext.requirementsList[0].extendedEnums
for extendedEnum in allExtendedEnums:
matchedStructEnum = re.search(structureEnumPattern, extendedEnum.name, re.IGNORECASE)
if matchedStructEnum:
# find feature/property structure type name
structureTypeName = ""
for stRequirement in ext.requirementsList[0].newTypes:
stName = stRequirement.name
matchedStructType = re.search(structureTypePattern, stName, re.IGNORECASE)
if matchedStructType:
structureTypeName = stName
break
# iterate over all composite types to check if structureTypeName is not alias
# this handles case where extension was promoted and with it feature/property structure
structureType = None
for ct in api.compositeTypes:
if structureTypeName == ct.name: