# -*- 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 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 = versionSplit[-2] apiMinor = versionSplit[-1] 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(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(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(m_resourceInterface->incResourceCounter());\n\t}", "createBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferRequestCount,1);\n\t\t*pBuffer = Handle(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(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(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(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(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(offset+size)))\n\t\t\tm_falseMemory.resize(static_cast(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(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 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 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&%s)" % (" dst" if len(deviceMap) != 0 or isSC else ""), "{"] + writeExtensionsForVersions(deviceMap) + [ "}", "", "void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector&%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& functions)\n{' dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"] elif functionType == Function.TYPE_DEVICE: yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector& 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 FunctionInfo;", "typedef ::std::vector FunctionInfosList;", "typedef ::std::map ApisMap;", "", "void initApisMap (ApisMap& apis)", "{", " apis.clear();"] + [ " apis.insert(::std::pair(" + 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 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 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 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'):]) + '", 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: structureType = ct break elif structureTypeName in ct.aliasList: structureType = ct structureTypeName = structureType.name break # use data in structextends to skip structures that should not be passed to vkGetPhysicalDeviceProperties(/Features)2 function if structureType is None or structureType.structextends is None or structureExtendsPattern not in structureType.structextends: continue # meke sure that structure was not added earlier - this handles special # cases like VkPhysicalDeviceIDPropertiesKHR added by 3 extensions if len([d for d in defs if d[3] == structureTypeName]) > 0: continue # there are cases like VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD # where 2 is after PROPERTIES - to handle this we need to split suffix to two parts sSuffix = matchedStructEnum.group(2) sVerSuffix = '' sExtSuffix = sSuffix suffixStart = sSuffix.rfind('_') if suffixStart > 0: sVerSuffix = sSuffix[:suffixStart] sExtSuffix = sSuffix[suffixStart:] foundStructureEnums.append(matchedStructEnum.group(1)) defs.append( (matchedStructEnum.group(1), sVerSuffix, sExtSuffix, structureTypeName,\ ext.name, allExtendedEnums[1].name, allExtendedEnums[0].name) ) # accept single feature/property structure per extension - this also handles cases # like VK_KHR_variable_pointers which specify feature structure and its alias break # iterate over all structures to find Feature/Property structures that were not added with extension # but with vulkan version; to do that we need to skip extension part from pattern for ct in api.compositeTypes: matchedStructType = re.search(structureTypePatternNotExtension, ct.name, re.IGNORECASE) if matchedStructType: if ct.members[0].name != "sType": continue if ct.structextends is None or structureExtendsPattern not in ct.structextends: continue matchedStructEnum = re.search(structureEnumPatternNotExtension, ct.members[0].values, re.IGNORECASE) if (matchedStructEnum.group(1) not in foundStructureEnums) and (re.match(structureTypeToSkipPattern, ct.name) == None): defs.append( (matchedStructEnum.group(1), '', '', ct.name, None, None, '0') ) return defs def writeDeviceFeatures(api, dfDefs, filename): # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs # and construct dictionary with all of their attributes blobMembers = {} blobStructs = {} blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") for structureType in api.compositeTypes: match = blobPattern.match(structureType.name) if match: allMembers = [member.name for member in structureType.members] vkVersion = match.group(1) blobMembers[vkVersion] = allMembers[2:] blobStructs[vkVersion] = set() initFromBlobDefinitions = [] emptyInitDefinitions = [] # iterate over all feature structures allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*") nonExtFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*$") for structureType in api.compositeTypes: # skip structures that are not feature structures if not allFeaturesPattern.match(structureType.name): continue # skip structures that were previously identified as blobs if blobPattern.match(structureType.name): continue # skip sType and pNext and just grab third and next attributes structureMembers = structureType.members[2:] notPartOfBlob = True if nonExtFeaturesPattern.match(structureType.name): # check if this member is part of any of the blobs for blobName, blobMemberList in blobMembers.items(): # if just one member is not part of this blob go to the next blob # (we asume that all members are part of blob - no need to check all) if structureMembers[0].name not in blobMemberList: continue # add another feature structure name to this blob blobStructs[blobName].add(structureType) # add specialization for this feature structure memberCopying = "" for member in structureMembers: memberCopying += "\tfeatureType.{0} = allFeaturesBlobs.vk{1}.{0};\n".format(member.name, blobName) wholeFunction = \ "template<> void initFeatureFromBlob<{0}>({0}& featureType, const AllFeaturesBlobs& allFeaturesBlobs)\n" \ "{{\n" \ "{1}" \ "}}".format(structureType.name, memberCopying) initFromBlobDefinitions.append(wholeFunction) notPartOfBlob = False # assuming that all members are part of blob, goto next break # add empty template definition as on Fedora there are issue with # linking using just generic template - all specializations are needed if notPartOfBlob: emptyFunction = "template<> void initFeatureFromBlob<{0}>({0}&, const AllFeaturesBlobs&) {{}}" emptyInitDefinitions.append(emptyFunction.format(structureType.name)) extensionDefines = [] makeFeatureDescDefinitions = [] featureStructWrappers = [] for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extName, extNameDef, specVersionDef) in enumerate(dfDefs): extensionNameDefinition = extNameDef if not extensionNameDefinition: extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) extensionDefines.append(f'#define {extensionNameDefinition} "core_feature"') # construct makeFeatureDesc template function definitions sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sVerSuffix + sExtSuffix) makeFeatureDescDefinitions.append("template<> FeatureDesc makeFeatureDesc<{0}>(void) " \ "{{ return FeatureDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVersionDef, len(dfDefs)-idx)) # construct CreateFeatureStruct wrapper block featureStructWrappers.append("\t{{ createFeatureStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVersionDef)) # construct function that will check for which vk version structure sType is part of blob blobChecker = "deUint32 getBlobFeaturesVersion (VkStructureType sType)\n{\n" \ "\tconst std::map sTypeBlobMap\n" \ "\t{\n" # iterate over blobs with list of structures for blobName in sorted(blobStructs.keys()): blobChecker += "\t\t// Vulkan{0}\n".format(blobName) # iterate over all feature structures in current blob structuresList = list(blobStructs[blobName]) structuresList = sorted(structuresList, key=lambda s: s.name) for structType in structuresList: # find definition of this structure in dfDefs structDef = None allNamesToCheck = [structType.name] if len(structType.aliasList) > 0: allNamesToCheck.extend(structType.aliasList) for structName in allNamesToCheck: structDefList = [s for s in dfDefs if s[3] == structName] if len(structDefList) > 0: structDef = structDefList[0] break sType = structDef[0] sSuffix = structDef[1] + structDef[2] sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix) tabs = "\t" * int((88 - len(sTypeName)) / 4) blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) blobChecker += "\t};\n\n" \ "\tauto it = sTypeBlobMap.find(sType);\n" \ "\tif(it == sTypeBlobMap.end())\n" \ "\t\treturn 0;\n" \ "\treturn it->second;\n" \ "}\n" # combine all definition lists stream = [ '#include "vkDeviceFeatures.hpp"\n', 'namespace vk\n{'] stream.extend(extensionDefines) stream.append('\n') stream.extend(initFromBlobDefinitions) stream.append('\n// generic template is not enough for some compilers') stream.extend(emptyInitDefinitions) stream.append('\n') stream.extend(makeFeatureDescDefinitions) stream.append('\n') stream.append('static const FeatureStructCreationData featureStructCreationArray[]\n{') stream.extend(featureStructWrappers) stream.append('};\n') stream.append(blobChecker) stream.append('} // vk\n') writeInlFile(filename, INL_HEADER, stream) def writeDeviceFeatureTest(api, filename): coreFeaturesPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") featureItems = [] testFunctions = [] # iterate over all feature structures allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*") for structureType in api.compositeTypes: # skip structures that are not feature structures if not allFeaturesPattern.match(structureType.name): continue # skip sType and pNext and just grab third and next attributes structureMembers = structureType.members[2:] items = [] for member in structureMembers: items.append(" FEATURE_ITEM ({0}, {1}),".format(structureType.name, member.name)) testBlock = """ tcu::TestStatus createDeviceWithUnsupportedFeaturesTest{4} (Context& context) {{ const PlatformInterface& vkp = context.getPlatformInterface(); tcu::TestLog& log = context.getTestContext().getLog(); tcu::ResultCollector resultCollector (log); const CustomInstance instance (createCustomInstanceWithExtensions(context, context.getInstanceExtensions(), DE_NULL, true)); const InstanceDriver& instanceDriver (instance.getDriver()); const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); const deUint32 queueFamilyIndex = 0; const deUint32 queueCount = 1; const float queuePriority = 1.0f; const DeviceFeatures deviceFeaturesAll (context.getInstanceInterface(), context.getUsedApiVersion(), physicalDevice, context.getInstanceExtensions(), context.getDeviceExtensions(), DE_TRUE); const VkPhysicalDeviceFeatures2 deviceFeatures2 = deviceFeaturesAll.getCoreFeatures2(); int numErrors = 0; bool isSubProcess = context.getTestContext().getCommandLine().isSubProcess(); {6} VkPhysicalDeviceFeatures emptyDeviceFeatures; deMemset(&emptyDeviceFeatures, 0, sizeof(emptyDeviceFeatures)); // Only non-core extensions will be used when creating the device. const auto& extensionNames = context.getDeviceCreationExtensions(); DE_UNREF(extensionNames); // In some cases this is not used. if (const void* featuresStruct = findStructureInChain(const_cast(deviceFeatures2.pNext), getStructureType<{0}>())) {{ static const Feature features[] = {{ {1} }}; auto* supportedFeatures = reinterpret_cast(featuresStruct); checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures, {5}, context.getUsedApiVersion()); }} if (numErrors > 0) return tcu::TestStatus(resultCollector.getResult(), "Enabling unsupported features didn't return VK_ERROR_FEATURE_NOT_PRESENT."); else return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage()); }} """ additionalParams = ( 'memReservationStatMax, isSubProcess' if api.apiName == 'vulkansc' else 'isSubProcess' ) additionalDefs = ( ' VkDeviceObjectReservationCreateInfo memReservationStatMax = context.getResourceInterface()->getStatMax();' if apiName == 'vulkansc' else '') featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("DE_NULL" if coreFeaturesPattern.match(structureType.name) else "&extensionNames"), structureType.name[len('VkPhysicalDevice'):], additionalParams, additionalDefs)) testFunctions.append("createDeviceWithUnsupportedFeaturesTest" + structureType.name[len('VkPhysicalDevice'):]) stream = [''] stream.extend(featureItems) stream.append(""" void addSeparateUnsupportedFeatureTests (tcu::TestCaseGroup* testGroup) { """) for x in testFunctions: stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x[len('createDeviceWithUnsupportedFeaturesTest'):]) + '", ' + x + ');') stream.append('}\n') writeInlFile(filename, INL_HEADER, stream) def writeDeviceProperties(api, dpDefs, filename): # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs # and construct dictionary with all of their attributes blobMembers = {} blobStructs = {} blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Properties[0-9]*$") for structureType in api.compositeTypes: match = blobPattern.match(structureType.name) if match: allMembers = [member.name for member in structureType.members] vkVersion = match.group(1) blobMembers[vkVersion] = allMembers[2:] blobStructs[vkVersion] = set() initFromBlobDefinitions = [] emptyInitDefinitions = [] # iterate over all property structures allPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*") nonExtPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*$") for structureType in api.compositeTypes: # skip structures that are not property structures if not allPropertiesPattern.match(structureType.name): continue # skip structures that were previously identified as blobs if blobPattern.match(structureType.name): continue # skip sType and pNext and just grab third and next attributes structureMembers = structureType.members[2:] notPartOfBlob = True if nonExtPropertiesPattern.match(structureType.name): # check if this member is part of any of the blobs for blobName, blobMemberList in blobMembers.items(): # if just one member is not part of this blob go to the next blob # (we asume that all members are part of blob - no need to check all) if structureMembers[0].name not in blobMemberList: continue # add another property structure name to this blob blobStructs[blobName].add(structureType) # add specialization for this property structure memberCopying = "" for member in structureMembers: if len(member.arraySizeList) == 0: # handle special case if structureType.name == "VkPhysicalDeviceSubgroupProperties" and "subgroup" not in member.name : blobMemberName = "subgroup" + member.name[0].capitalize() + member.name[1:] memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{2};\n".format(member.name, blobName, blobMemberName) # end handling special case else: memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{0};\n".format(member.name, blobName) else: memberCopying += "\tmemcpy(propertyType.{0}, allPropertiesBlobs.vk{1}.{0}, sizeof({2}) * {3});\n".format(member.name, blobName, member.type, member.arraySizeList[0]) wholeFunction = \ "template<> void initPropertyFromBlob<{0}>({0}& propertyType, const AllPropertiesBlobs& allPropertiesBlobs)\n" \ "{{\n" \ "{1}" \ "}}".format(structureType.name, memberCopying) initFromBlobDefinitions.append(wholeFunction) notPartOfBlob = False # assuming that all members are part of blob, goto next break # add empty template definition as on Fedora there are issue with # linking using just generic template - all specializations are needed if notPartOfBlob: emptyFunction = "template<> void initPropertyFromBlob<{0}>({0}&, const AllPropertiesBlobs&) {{}}" emptyInitDefinitions.append(emptyFunction.format(structureType.name)) extensionDefines = [] makePropertyDescDefinitions = [] propertyStructWrappers = [] for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extName, extNameDef, specVersionDef) in enumerate(dpDefs): extensionNameDefinition = extNameDef if not extensionNameDefinition: extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) extensionDefines.append(f'#define {extensionNameDefinition} "core_property"') # construct makePropertyDesc template function definitions sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sVerSuffix + sExtSuffix) makePropertyDescDefinitions.append("template<> PropertyDesc makePropertyDesc<{0}>(void) " \ "{{ return PropertyDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVersionDef, len(dpDefs)-idx)) # construct CreateProperty struct wrapper block propertyStructWrappers.append("\t{{ createPropertyStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVersionDef)) # construct method that will check if structure sType is part of blob blobChecker = "deUint32 getBlobPropertiesVersion (VkStructureType sType)\n{\n" \ "\tconst std::map sTypeBlobMap\n" \ "\t{\n" # iterate over blobs with list of structures for blobName in sorted(blobStructs.keys()): blobChecker += "\t\t// Vulkan{0}\n".format(blobName) # iterate over all feature structures in current blob structuresList = list(blobStructs[blobName]) structuresList = sorted(structuresList, key=lambda s: s.name) for structType in structuresList: # find definition of this structure in dpDefs structName = structType.name structDef = None foundDefs = [s for s in dpDefs if s[3] == structName] if len(foundDefs) > 0: structDef = foundDefs[0] else: for alias in structType.aliasList: foundDefs = [s for s in dpDefs if s[3] == alias] if len(foundDefs) > 0: structDef = foundDefs[0] break sType = structDef[0] sSuffix = structDef[1] + structDef[2] sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sSuffix) tabs = "\t" * int((80 - len(sTypeName)) / 4) blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) blobChecker += "\t};\n\n" \ "\tauto it = sTypeBlobMap.find(sType);\n" \ "\tif(it == sTypeBlobMap.end())\n" \ "\t\treturn 0;\n" \ "\treturn it->second;\n" \ "}\n" # combine all definition lists stream = [ '#include "vkDeviceProperties.hpp"\n', 'namespace vk\n{'] stream.extend(extensionDefines) stream.append('\n') stream.extend(initFromBlobDefinitions) stream.append('\n// generic template is not enough for some compilers') stream.extend(emptyInitDefinitions) stream.append('\n') stream.extend(makePropertyDescDefinitions) stream.append('\n') stream.append('static const PropertyStructCreationData propertyStructCreationArray[] =\n{') stream.extend(propertyStructWrappers) stream.append('};\n') stream.append(blobChecker) stream.append('} // vk\n') writeInlFile(filename, INL_HEADER, stream) UNSUFFIXED_STRUCTURES = [ "CornerSampledImage", "ShaderSMBuiltins", "ShadingRateImage", "RayTracing", "RepresentativeFragmentTest", "ComputeShaderDerivatives", "MeshShader", "ShaderImageFootprint", "ExclusiveScissor", "DedicatedAllocationImageAliasing", "CoverageReductionMode", "DeviceGeneratedCommands", "InheritedViewportScissor", "PresentBarrier", "DiagnosticsConfig", "FragmentShadingRateEnums", "RayTracingMotionBlur", "ExternalMemoryRDMA", "CopyMemoryIndirect", "MemoryDecompression", "LinearColorAttachment", "OpticalFlow", "RayTracingInvocationReorder", "DisplacementMicromap"] def deviceFeaturesOrPropertiesGetter(name): result = name[16:] # Remove VkPhysicalDevice prefix if result[-3:] == "KHR": result = result[0:-3] elif result[-2:] == "NV": suffix = result[-2:] result = result[0:-2] if result[-8:] == "Features": infix = result[-8:] result = result[0:-8] elif result[-10:] == "Properties": infix = result[-10:] result = result[0:-10] if (result in UNSUFFIXED_STRUCTURES): suffix = "" result = result + infix + suffix return result def genericDeviceFeaturesWriter(dfDefs, pattern, filename): stream = [] for _, _, _, extStruct, _, _, _ in dfDefs: nameSubStr = deviceFeaturesOrPropertiesGetter(extStruct) stream.append(pattern.format(extStruct, nameSubStr)) writeInlFile(filename, INL_HEADER, indentLines(stream)) def writeDeviceFeaturesDefaultDeviceDefs(dfDefs, filename): pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceFeatures.getFeatureType<{0}>();\t}}" genericDeviceFeaturesWriter(dfDefs, pattern, filename) def writeDeviceFeaturesContextDecl(dfDefs, filename): pattern = "const vk::{0}&\tget{1}\t(void) const;" genericDeviceFeaturesWriter(dfDefs, pattern, filename) def writeDeviceFeaturesContextDefs(dfDefs, filename): pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}" genericDeviceFeaturesWriter(dfDefs, pattern, filename) def genericDevicePropertiesWriter(dfDefs, pattern, filename): stream = [] for _, _, _, extStruct, _, _, _ in dfDefs: nameSubStr = deviceFeaturesOrPropertiesGetter(extStruct) stream.append(pattern.format(extStruct, nameSubStr)) writeInlFile(filename, INL_HEADER, indentLines(stream)) def writeDevicePropertiesDefaultDeviceDefs(dfDefs, filename): pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceProperties.getPropertyType<{0}>();\t}}" genericDevicePropertiesWriter(dfDefs, pattern, filename) def writeDevicePropertiesContextDecl(dfDefs, filename): pattern = "const vk::{0}&\tget{1}\t(void) const;" genericDevicePropertiesWriter(dfDefs, pattern, filename) def writeDevicePropertiesContextDefs(dfDefs, filename): pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}" genericDevicePropertiesWriter(dfDefs, pattern, filename) def writeMandatoryFeatures(api, filename): def structInAPI(name): for c in api.compositeTypes: if c.name == name: return True for alias in c.aliasList: if alias == name: return True return False stream = [] dictStructs = {} dictData = [] extData = [] usedFeatureStructs = {} for _, data in api.additionalExtensionData: if 'mandatory_features' in data.keys(): # sort to have same results for py2 and py3 listStructFeatures = sorted(data['mandatory_features'].items(), key=lambda tup: tup[0]) for structure, featuresList in listStructFeatures: for featureData in featuresList: # allow for featureless VKSC only extensions if not 'features' in featureData.keys() or 'requirements' not in featureData.keys(): continue requirements = featureData['requirements'] mandatory_variant = '' try: mandatory_variant = featureData['mandatory_variant'] except KeyError: mandatory_variant = '' dictData.append( [ structure, featureData['features'], requirements, mandatory_variant] ) if structure == 'VkPhysicalDeviceFeatures': continue # if structure is not in dict construct name of variable and add is as a first item if (structure not in dictStructs): dictStructs[structure] = ([structure[2:3].lower() + structure[3:]], mandatory_variant) # add first requirement if it is unique if requirements and (requirements[0] not in dictStructs[structure][0]): dictStructs[structure][0].append(requirements[0]) usedFeatureStructs[structure] = [] if requirements: for req in requirements: if '.' in req: req = req.split('.')[0] reqStruct = 'Vk' + req[0].upper() + req[1:] usedFeatureStructs[reqStruct] = [] if 'mandatory_extensions' in data: mandatoryExtensions = [] for mandatoryExt in data['mandatory_extensions']: if 'extension' in mandatoryExt: extName = mandatoryExt.pop('extension') mandatoryExtensions.append((extName, mandatoryExt)) for extension, extensionData in mandatoryExtensions: # requirements are actually mandatory. if 'requirements' not in extensionData: continue requirements = extensionData['requirements'] mandatory_variant = '' if 'mandatory_variant' not in extensionData else extensionData['mandatory_variant'] extData.append((extension, requirements, mandatory_variant)) for req in requirements: if '.' in req: req = req.split('.')[0] reqStruct = 'Vk' + req[0].upper() + req[1:] usedFeatureStructs[reqStruct] = [] stream.extend(['bool canUseFeaturesStruct (const vector& deviceExtensions, uint32_t usedApiVersion, const char* extension)', '{', '\treturn (isExtensionStructSupported(deviceExtensions, RequiredExtension(extension))', '\t\t\t|| isCoreDeviceExtension(usedApiVersion, extension));', '}', '', 'bool checkMandatoryFeatures(const vkt::Context& context)\n{', '\tif (!context.isInstanceFunctionalitySupported("VK_KHR_get_physical_device_properties2"))', '\t\tTCU_THROW(NotSupportedError, "Extension VK_KHR_get_physical_device_properties2 is not present");', '', '\tVkPhysicalDevice\t\t\t\t\tphysicalDevice\t\t= context.getPhysicalDevice();', '\tconst InstanceInterface&\t\t\tvki\t\t\t\t\t= context.getInstanceInterface();', '\tconst vector\tdeviceExtensions\t= enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL);', '\tconst uint32_t\t\t\t\t\t\tusedApiVersion\t\t= context.getUsedApiVersion();', '', '\ttcu::TestLog& log = context.getTestContext().getLog();', '\tvk::VkPhysicalDeviceFeatures2 coreFeatures;', '\tdeMemset(&coreFeatures, 0, sizeof(coreFeatures));', '\tcoreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;', '\tvoid** nextPtr = &coreFeatures.pNext;', '']) # Find the extensions that added the required feature structs. class StructFoundContinue(Exception): pass for usedStruct in usedFeatureStructs: for compType in api.compositeTypes: nameList = [compType.name] + compType.aliasList if usedStruct in nameList: # Found the official name list for the struct. for extension in api.extensions: try: for requirement in extension.requirementsList: for extensionStructure in requirement.newTypes: if extensionStructure.name in nameList: # Found extension for the struct. usedFeatureStructs[usedStruct].append(extension.name) raise StructFoundContinue except StructFoundContinue: pass structList = sorted(usedFeatureStructs.items(), key=lambda tup: tup[0]) # sort to have same results for py2 and py3 apiStructs = list( filter(lambda x : structInAPI(x[0]), structList)) # remove items not defined in current API for structName, extensions in apiStructs: metaCondition = '' if structName in dictStructs: mandatoryVariantList = dictStructs[structName][1] if len(mandatoryVariantList) > 0: mandatoryVariant = mandatoryVariantList[0] metaCondition = 'defined(CTS_USES_' + mandatoryVariant.upper() + ')' stream.append('#if ' + metaCondition) # The variable name will be the structure name without the Vk prefix and starting in lowercase. newVar = structName[2].lower() + structName[3:] stream.extend(['\tvk::' + structName + ' ' + newVar + ';', '\tdeMemset(&' + newVar + ', 0, sizeof(' + newVar + '));', '']) if len(extensions) > 0: canUseCond = '\tif (' for (i, extName) in enumerate(extensions): canUseCond += ' ' if i == 0 else ' || ' canUseCond += 'canUseFeaturesStruct(deviceExtensions, usedApiVersion, "' + extName + '")' canUseCond += ' )' stream.append(canUseCond) elif api.apiName == "vulkan" and structName in dictStructs: #reqs = v[0][1:] reqs = dictStructs[structName][0][1:] cond = 'if ( ' for i, req in enumerate(reqs): if i > 0: cond = cond + ' || ' if (req.startswith("ApiVersion")): cond = cond + 'context.contextSupports(vk::' + req + ')' cond = cond + ' )' stream.append('\t' + cond) stream.extend(['\t{', '\t\t' + newVar + '.sType = getStructureType<' + structName + '>();', '\t\t*nextPtr = &' + newVar + ';', '\t\tnextPtr = &' + newVar + '.pNext;', '\t}']) if len(metaCondition) > 0: stream.append('#endif // ' + metaCondition) stream.append('') stream.extend(['\tcontext.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &coreFeatures);', '\tbool result = true;', '']) for v in dictData: if not structInAPI(v[0]): # remove items not defined in current API ( important for Vulkan SC ) continue structType = v[0]; structName = 'coreFeatures.features'; metaCondition = '' if len(v) == 4 and v[3] != '': # for x in v[3].split('_'): metaCondition = metaCondition + ' || defined(CTS_USES_' + v[3][0].upper() + ')' stream.extend(['#if ' + metaCondition[4:]]) if v[0] != 'VkPhysicalDeviceFeatures' : structName = dictStructs[v[0]][0][0] if len(v[2]) > 0 : condition = 'if ( ' for i, req in enumerate(v[2]) : if (req.startswith("ApiVersion")): condition = condition + 'context.contextSupports(vk::' + req + ')' elif '.' in req: condition = condition + req else: condition = condition + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))' if i+1 < len(v[2]) : condition = condition + ' && ' condition = condition + ' )' stream.append('\t' + condition) stream.append('\t{') # Don't need to support an AND case since that would just be another line in the .txt if len(v[1]) == 1: stream.append('\t\tif ( ' + structName + '.' + v[1][0] + ' == VK_FALSE )') else: condition = 'if ( ' for i, feature in enumerate(v[1]): if i != 0: condition = condition + ' && ' condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )' condition = condition + ' )' stream.append('\t\t' + condition) featureSet = " or ".join(v[1]) stream.extend(['\t\t{', '\t\t\tlog << tcu::TestLog::Message << "Mandatory feature ' + featureSet + ' not supported" << tcu::TestLog::EndMessage;', '\t\t\tresult = false;', '\t\t}', '\t}']) if metaCondition != '': stream.extend(['#endif // ' + metaCondition[4:], '']) else: stream.extend(['']) for extension, requirements, mandatory_variant in extData: metaCondition = '' if mandatory_variant != '': metaCondition = metaCondition + ' || defined(CTS_USES_' + mandatory_variant[0].upper() + ')' stream.extend(['#if ' + metaCondition[4:]]) if len(requirements) > 0 : condition = 'if ( ' for i, req in enumerate(requirements) : if (req.startswith("ApiVersion")): condition = condition + 'context.contextSupports(vk::' + req + ')' elif '.' in req: condition = condition + req else: condition = condition + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))' if i+1 < len(requirements) : condition = condition + ' && ' condition = condition + ' )' stream.append('\t' + condition) stream.append('\t{') stream.extend(['\t\tif (!(isExtensionStructSupported(deviceExtensions, RequiredExtension("' + extension + '")) || isCoreDeviceExtension(usedApiVersion, "' + extension + '")))', '\t\t{', '\t\t\tlog << tcu::TestLog::Message << "Mandatory extension ' + extension + ' not supported" << tcu::TestLog::EndMessage;', '\t\t\tresult = false;', '\t\t}', '\t}']) if metaCondition != '': stream.extend(['#endif // ' + metaCondition[4:], '']) else: stream.append('') stream.append('\treturn result;') stream.append('}\n') writeInlFile(filename, INL_HEADER, stream) def writeExtensionList(api, filename, extensionType): extensionList = [] for extensionName, data in api.additionalExtensionData: # make sure extension name starts with VK_KHR if not extensionName.startswith('VK_KHR'): continue # make sure that this extension was registered if 'register_extension' not in data.keys(): continue # make sure extension is intended for the vulkan variant is_sc_only = False if api.apiName != 'vulkansc': if 'mandatory_features' in data.keys(): for structure, listStruct in data['mandatory_features'].items(): for featureData in listStruct: mandatory_variant = '' try: mandatory_variant = featureData['mandatory_variant'] except KeyError: mandatory_variant = '' # VKSC only if 'vulkansc' in mandatory_variant: is_sc_only = True if is_sc_only: continue # make sure extension has proper type if extensionType == data['register_extension']['type']: extensionList.append(extensionName) extensionList.sort() # write list of all found extensions stream = [] stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(extensionType.title())) for n in extensionList: stream.append('\t"' + n + '",') stream.append('};\n') writeInlFile(filename, INL_HEADER, stream) def writeApiExtensionDependencyInfo(api, filename): def genHelperFunctions(): yield 'using namespace tcu;' yield 'using ExtPropVect = std::vector;' yield 'using IsSupportedFun = bool (*)(const tcu::UVec2&, const ExtPropVect&, const ExtPropVect&);' yield 'using DependencyCheckVect = std::vector >;\n' yield 'bool isCompatibile(deUint32 major, deUint32 minor, const tcu::UVec2& testedApiVersion)' yield '{' yield '\t// return true when tested api version is greater' yield '\t// or equal to version represented by two uints' yield '\tif (major == testedApiVersion.x())' yield '\t\treturn minor <= testedApiVersion.y();' yield '\treturn major < testedApiVersion.x();' yield '}\n' yield 'bool isSupported(const ExtPropVect& extensions, const char* ext)' yield '{' yield '\treturn isExtensionStructSupported(extensions, vk::RequiredExtension(ext));' yield '}\n' def genExtDepArray(extType): extensionList = [] maxExtLength = 0 extVector = 'vIEP' othVector = 'vDEP' if extType == 'device': extVector, othVector = othVector, extVector # swap # iterate over all extension that are of specified type and that have requirements for ext in api.extensions: if ext.type != extType: continue if ext.depends is None: continue # memorize extension name and dependencies for future vector generation extensionList.append(ext.name) # memorize max extension name and dependency length maxExtLength = max(maxExtLength, len(ext.name)) # generate check function for this extension yield f'bool check_{ext.name}(const tcu::UVec2& v, const ExtPropVect& vIEP, const ExtPropVect& vDEP)' yield '{' # check if extension was promoted; for SC we need to check vulkan version as sc10 is based on vk12 if ext.promotedto is not None and 'VK_VERSION' in ext.promotedto: p = ext.promotedto yield f'\tif (isCompatibile({p[-3]}, {p[-1]}, v))' yield '\t\treturn true;\n' else: yield '\tDE_UNREF(v);' # there is a high chance that other vector won't be used yield f'\tDE_UNREF({othVector});' # check if extension is supported yield f'\n\tif (!isSupported({extVector}, "{ext.name}"))' yield '\t\treturn true;\n' # replace dependent extensions/versions with proper conditions depList = re.split(r'(\W+)', ext.depends) for idx, depPart in enumerate(depList): if ',' in depPart: depList[idx] = depList[idx].replace(',', ' || ') elif '+' in depPart: depList[idx] = depList[idx].replace('+', ' && ') elif 'VK_' in depPart: if 'VK_VERSION' in depPart: if idx > 0 and ' || ' in depList[idx-1]: # some vk.xml entries include "promoted to" version preceded by logical OR operator in the extension "depends" attribute # script don't rely on this optional information and will find "promoted to" versions for all dependencies of all extensions in the below code # accordingly the one from vk.xml is ignored to avoid redundant isCompatibile() checks depList[idx-1] = depList[idx-1].replace(' || ', '') depList[idx] = '' continue # when dependency is vulkan version then replace it with proper condition depList[idx] = f'isCompatibile({depPart[-3]}, {depPart[-1]}, v)' else: # when dependency is extension check if it was promoted extNotFound = True for dExt in api.extensions: if depPart == dExt.name: depExtVector = 'vDEP' if dExt.type == 'device' else 'vIEP' isSupportedCheck = f'isSupported({depExtVector}, "{depPart}")' if dExt.promotedto is not None: p = dExt.promotedto # check if dependency was promoted to vulkan version or other extension if 'VK_VERSION' in p: depList[idx] = f'(isCompatibile({p[-3]}, {p[-1]}, v) || {isSupportedCheck})' else: depList[idx] = f'(isSupported({depExtVector}, "{p}") || {isSupportedCheck})' else: depList[idx] = isSupportedCheck extNotFound = False break # for SC when extension was not found try checking also not supported # extensions and see if this extension is part of core if extNotFound and api.apiName == "vulkansc": for dExt in api.notSupportedExtensions: if depPart == dExt.name: p = dExt.promotedto if p is None: break if int(p[-1]) > 2: break extNotFound = False depList[idx] = "true" if extNotFound: assert False, f"{depPart} from dependencies not found" yield f'\t// depends attribute in xml: {ext.depends}' finalConditon = ''.join(depList) yield f'\treturn {finalConditon};' yield '}\n' # save list of all device/instance extensions yield 'static const DependencyCheckVect {}ExtensionDependencies'.format(extType) yield '{' for ext in extensionList: extTabCount = (maxExtLength - len(ext)) / 4 eTabs = '\t'*int(round(extTabCount+1.49)) yield f'\tstd::make_pair("{ext}",{eTabs}&check_{ext}),' yield '};\n' def genApiVersions(): yield 'static const std::tuple\treleasedApiVersions[]\t=' yield '{' for f in reversed(api.features): apiVariant = '0' if f.api == 'vulkan' else '1' major, minor = f.number.split('.') version = (int(apiVariant) << 29) | (int(major) << 22) | (int(minor) << 12) yield '\tstd::make_tuple({}, {}, {}, {}),'.format(version, apiVariant, major, minor) yield '};' def parseExtensionDependencies(extDeps, ext): major, minor = 1, 0 requiredVerFound = False; # return in case nothing more left to be processed if extDeps is None or extDeps == "": return major, minor, requiredVerFound ungrpPartLen = 0 versionPattern = "[A-Z]+_VERSION_([0-9]+)_([0-9]+)" ungroupedPattern = r"^.*?\(+|^.*?$" # look for non-grouped part, it may include the required vulkan version ungroupPart = re.search(ungroupedPattern, extDeps) if ungroupPart is not None and ungroupPart[0].replace(r"(", "") != "": ungrpPartLen = len(ungroupPart[0].replace(r"(", "")) # is specific version explicitly requested? match = re.search(versionPattern, ungroupPart[0]) if match is not None: if len(match[0]) != len(extDeps): # there is more than just a version; check if it's accompanied by AND operator(s) ext_pattern = ".*\+*"+versionPattern+"\++.*|.*\++"+versionPattern+"\+*.*" match = re.search(ext_pattern, ungroupPart[0]) if match is not None: # specific version is explicitly requested major, minor = int(match[1]), int(match[2]) return major, minor, True # no explicit version is requested, continue parsing the remaining part extDeps = extDeps[ungrpPartLen:] groupedPattern = r"(.*)\+|(.*)$" match = re.search(groupedPattern, extDeps) if match is not None and match[0] != "": # groups may include the dependency "promoted to" versions accompanied by OR operator # but they don't include the extension explicit required version; continue parsing the remaining part groupLength = len(match[0]) major, minor, requiredVerFound = parseExtensionDependencies(extDeps[groupLength:], ext) return major, minor, requiredVerFound def genRequiredCoreVersions(): yield 'static const std::tuple\textensionRequiredCoreVersion[]\t =' yield '{' versionPattern = "[A-Z]+_VERSION_([0-9]+)_([0-9]+)" for ext in api.extensions: # skip video extensions if 'vulkan_video_' in ext.name: continue major, minor = 1, 0 if ext.depends is not None: major, minor, requiredVerFound = parseExtensionDependencies(ext.depends, ext) if not requiredVerFound: # find all extensions that are dependencies of this one matches = re.findall("VK_\w+", ext.depends, re.M) for m in matches: for de in api.extensions: if de.name == m: if de.depends is not None: # check if the dependency states explicitly the required vulkan version and pick the higher one newMajor, newMinor, requiredVerFound = parseExtensionDependencies(de.depends, de) if requiredVerFound: if newMajor > major: major, minor = newMajor, newMinor elif newMajor == major and newMinor > minor: minor = newMinor break yield '\tstd::make_tuple({}, {}, "{}"),'.format(major, minor, ext.name) yield '};' stream = [] stream.extend(genHelperFunctions()) stream.extend(genExtDepArray('instance')) stream.extend(genExtDepArray('device')) stream.extend(genApiVersions()) stream.extend(genRequiredCoreVersions()) writeInlFile(filename, INL_HEADER, stream) def writeEntryPointValidation(api, filename): # keys are instance extension names and value is list of device-level functions instExtDeviceFunDict = {} # iterate over all extensions and find instance extensions for ext in api.extensions: if ext.type == "instance": # iterate over all functions instance extension adds for requirement in ext.requirementsList: for extCommand in requirement.newCommands: # to get a type of command we need to find this command definition in list of all functions for command in api.functions: if extCommand.name == command.name or extCommand.name in command.aliasList: # check if this is device-level entry-point if command.getType() == Function.TYPE_DEVICE: if ext.name not in instExtDeviceFunDict: instExtDeviceFunDict[ext.name] = [] instExtDeviceFunDict[ext.name].append(extCommand.name) stream = ['std::map > instExtDeviceFun', '{'] for extName in instExtDeviceFunDict: stream.append(f'\t{{ "{extName}",\n\t\t{{') for fun in instExtDeviceFunDict[extName]: stream.append(f'\t\t\t"{fun}",') stream.append('\t\t}\n\t},') stream.append('};') writeInlFile(filename, INL_HEADER, stream) def writeGetDeviceProcAddr(api, filename): testBlockStart = '''tcu::TestStatus testGetDeviceProcAddr (Context& context) { tcu::TestLog& log (context.getTestContext().getLog()); const PlatformInterface& platformInterface = context.getPlatformInterface(); const auto validationEnabled = context.getTestContext().getCommandLine().isValidationEnabled(); 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 float queuePriority = 1.0f; const std::vector queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice); const VkDeviceQueueCreateInfo deviceQueueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkDeviceQueueCreateFlags)0u, // VkDeviceQueueCreateFlags flags; queueFamilyIndex, // deUint32 queueFamilyIndex; queueCount, // deUint32 queueCount; &queuePriority, // const float* pQueuePriorities; }; const VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkDeviceCreateFlags)0u, // VkDeviceCreateFlags flags; 1u, // deUint32 queueCreateInfoCount; &deviceQueueCreateInfo, // const VkDeviceQueueCreateInfo* pQueueCreateInfos; 0u, // deUint32 enabledLayerCount; DE_NULL, // const char* const* ppEnabledLayerNames; 0u, // deUint32 enabledExtensionCount; DE_NULL, // const char* const* ppEnabledExtensionNames; DE_NULL, // const VkPhysicalDeviceFeatures* pEnabledFeatures; }; const Unique device (createCustomDevice(validationEnabled, platformInterface, instance, instanceDriver, physicalDevice, &deviceCreateInfo)); const DeviceDriver deviceDriver (platformInterface, instance, device.get(), context.getUsedApiVersion()); const std::vector loaderExceptions{ "vkSetDebugUtilsObjectNameEXT", "vkSetDebugUtilsObjectTagEXT", "vkQueueBeginDebugUtilsLabelEXT", "vkQueueEndDebugUtilsLabelEXT", "vkQueueInsertDebugUtilsLabelEXT", "vkCmdBeginDebugUtilsLabelEXT", "vkCmdEndDebugUtilsLabelEXT", "vkCmdInsertDebugUtilsLabelEXT", }; const std::vector functions{''' testBlockEnd = ''' }; bool fail = false; for (const auto& function : functions) { if (std::find(loaderExceptions.begin(), loaderExceptions.end(), function) != loaderExceptions.end()) { continue; } if (deviceDriver.getDeviceProcAddr(device.get(), function.c_str()) != DE_NULL) { fail = true; log << tcu::TestLog::Message << "Function " << function << " is not NULL" << tcu::TestLog::EndMessage; } } if (fail) return tcu::TestStatus::fail("Fail"); return tcu::TestStatus::pass("All functions are NULL"); } ''' def functions(functionType): for ext in api.extensions: for requirement in ext.requirementsList: for requiredCommand in requirement.newCommands: yield '\t\t"' + requiredCommand.name + '",' stream = [] stream.append('#include "tcuCommandLine.hpp"') stream.append('#include "vktTestCase.hpp"') stream.append('#include "vkPlatform.hpp"') stream.append('#include "vkDeviceUtil.hpp"') stream.append('#include "vkQueryUtil.hpp"') stream.append('#include "vktCustomInstancesDevices.hpp"') stream.append('#include "vktTestCase.hpp"') stream.append('#include "vktTestCaseUtil.hpp"') stream.append('\nnamespace vkt\n{\n') stream.append('using namespace vk;\n') stream.append(testBlockStart) stream.extend(functions(api)) stream.append(testBlockEnd) # function to create tests stream.append("void addGetDeviceProcAddrTests (tcu::TestCaseGroup* testGroup)\n{") stream.append('\taddFunctionCase(testGroup, "non_enabled", testGetDeviceProcAddr);') stream.append('}\n') stream.append('}\n') writeInlFile(filename, INL_HEADER, stream) def writeConformanceVersions(filename): # get list of all vulkan/vulkansc tags from git listOfTags = os.popen("git ls-remote -t").read() vkMatches = re.findall("vulkan-cts-(\d).(\d).(\d).(\d)", listOfTags, re.M) scMatches = re.findall("vulkansc-cts-(\d).(\d).(\d).(\d)", listOfTags, re.M) if len(vkMatches) == 0 or len(scMatches) == 0: return # read all text files in doc folder and find withdrawn cts versions (branches) withdrawnVkBranches = set() withdrawnScBranches = set() today = datetime.date.today() for fileName in glob.glob(os.path.join(os.path.dirname(__file__), "..", "doc", "*.txt")): if "withdrawal" not in fileName: continue fileContent = readFile(fileName) # get date when releases are withdrawn match = re.search(r"(20\d\d)-(\d\d)-(\d\d).+ withdrawn", fileContent, re.IGNORECASE) if match is not None: # check if announcement refers to date in the past if today > datetime.date(int(match[1]), int(match[2]), int(match[3])): # get names of withdrawn branches vkBranchMatches = re.findall("vulkan(\w\w)?-cts-(\d).(\d).(\d).(\d)", fileContent, re.M) for v in vkBranchMatches: selectedSet = withdrawnScBranches if v[0] == "sc" else withdrawnVkBranches selectedSet.add((v[1], v[2], v[3], v[4])) if len(withdrawnVkBranches) == 0: print(f"Warning: unable to read content of doc folder, skipping generation of {os.path.basename(filename)}") return # define helper function that will be used to add entries for both vk and sc def appendToStream(stream, versionsToAdd, maxWithdrawnVersion): addedVersions = set() for v in reversed(versionsToAdd): # add only unique versions; ignore duplicates (e.g. with "-rc1", "-rc2" postfix); # also add versions that are greater then maximal withdrawn version if v in addedVersions or v <= maxWithdrawnVersion: continue addedVersions.add(v) stream.append(f'\tmakeConformanceVersion({v[0]}, {v[1]}, {v[2]}, {v[3]}),') # save array with versions stream = ['static const VkConformanceVersion knownConformanceVersions[]',\ '{',\ '#ifndef CTS_USES_VULKANSC'] appendToStream(stream, vkMatches, max(withdrawnVkBranches)) stream.append('#else') appendToStream(stream, scMatches, tuple('0'*4) if len(withdrawnScBranches) == 0 else max(withdrawnScBranches)) stream.append('#endif // CTS_USES_VULKANSC') stream.append('};') writeInlFile(filename, INL_HEADER, stream) def parseCmdLineArgs(): parser = argparse.ArgumentParser(description = "Generate Vulkan INL files", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-a", "--api", dest="api", default="", help="Choose between Vulkan and Vulkan SC") parser.add_argument("-o", "--outdir", dest="outdir", default="", help="Choose output directory") return parser.parse_args() if __name__ == "__main__": args = parseCmdLineArgs() # if argument was specified it is interpreted as a path to which .inl files will be written outputPath = DEFAULT_OUTPUT_DIR[args.api] if args.outdir == '' else args.outdir vkTree = etree.parse(os.path.join(VULKAN_XML_DIR, "vk.xml")) apiName = "vulkansc" if args.api == 'SC' else "vulkan" stripNonmatchingAPIs(vkTree.getroot(), apiName, actuallyDelete = True) # Read vk.xml and generate vulkan headers from it api = API(apiName) api.build(vkTree) api.postProcess() # Read video.xml if args.api != 'SC': api.build( etree.parse(os.path.join(VULKAN_XML_DIR, "video.xml")) ) platformFuncs = [Function.TYPE_PLATFORM] instanceFuncs = [Function.TYPE_INSTANCE] deviceFuncs = [Function.TYPE_DEVICE] dfd = generateDeviceFeaturesOrPropertiesDefs(api, 'Features') writeDeviceFeatures (api, dfd, os.path.join(outputPath, "vkDeviceFeatures.inl")) writeDeviceFeaturesDefaultDeviceDefs (dfd, os.path.join(outputPath, "vkDeviceFeaturesForDefaultDeviceDefs.inl")) writeDeviceFeaturesContextDecl (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDecl.inl")) writeDeviceFeaturesContextDefs (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDefs.inl")) writeDeviceFeatureTest (api, os.path.join(outputPath, "vkDeviceFeatureTest.inl")) dpd = generateDeviceFeaturesOrPropertiesDefs(api, 'Properties') writeDeviceProperties (api, dpd, os.path.join(outputPath, "vkDeviceProperties.inl")) writeDevicePropertiesDefaultDeviceDefs (dpd, os.path.join(outputPath, "vkDevicePropertiesForDefaultDeviceDefs.inl")) writeDevicePropertiesContextDecl (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDecl.inl")) writeDevicePropertiesContextDefs (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDefs.inl")) writeHandleType (api, os.path.join(outputPath, "vkHandleType.inl")) writeBasicTypes (api, os.path.join(outputPath, "vkBasicTypes.inl")) writeCompositeTypes (api, os.path.join(outputPath, "vkStructTypes.inl")) writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualPlatformInterface.inl"), platformFuncs, False) writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualInstanceInterface.inl"), instanceFuncs, False) writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualDeviceInterface.inl"), deviceFuncs, False) writeInterfaceDecl (api, os.path.join(outputPath, "vkConcretePlatformInterface.inl"), platformFuncs, True) writeInterfaceDecl (api, os.path.join(outputPath, "vkConcreteInstanceInterface.inl"), instanceFuncs, True) writeInterfaceDecl (api, os.path.join(outputPath, "vkConcreteDeviceInterface.inl"), deviceFuncs, True) writeFunctionPtrTypes (api, os.path.join(outputPath, "vkFunctionPointerTypes.inl")) writeFunctionPointers (api, os.path.join(outputPath, "vkPlatformFunctionPointers.inl"), platformFuncs) writeFunctionPointers (api, os.path.join(outputPath, "vkInstanceFunctionPointers.inl"), instanceFuncs) writeFunctionPointers (api, os.path.join(outputPath, "vkDeviceFunctionPointers.inl"), deviceFuncs) writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitPlatformFunctionPointers.inl"), platformFuncs, lambda f: f.name != "vkGetInstanceProcAddr") writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitInstanceFunctionPointers.inl"), instanceFuncs) writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitDeviceFunctionPointers.inl"), deviceFuncs) writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkPlatformDriverImpl.inl"), platformFuncs, "PlatformDriver") writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkInstanceDriverImpl.inl"), instanceFuncs, "InstanceDriver") writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkDeviceDriverImpl.inl"), deviceFuncs, "DeviceDriver") if args.api=='SC': writeFuncPtrInterfaceSCImpl (api, os.path.join(outputPath, "vkDeviceDriverSCImpl.inl"), deviceFuncs, "DeviceDriverSC") writeStrUtilProto (api, os.path.join(outputPath, "vkStrUtil.inl")) writeStrUtilImpl (api, os.path.join(outputPath, "vkStrUtilImpl.inl")) writeRefUtilProto (api, os.path.join(outputPath, "vkRefUtil.inl")) writeRefUtilImpl (api, os.path.join(outputPath, "vkRefUtilImpl.inl")) writeStructTraitsImpl (api, os.path.join(outputPath, "vkGetStructureTypeImpl.inl")) writeNullDriverImpl (api, os.path.join(outputPath, "vkNullDriverImpl.inl")) writeTypeUtil (api, os.path.join(outputPath, "vkTypeUtil.inl")) writeSupportedExtensions (api, os.path.join(outputPath, "vkSupportedExtensions.inl")) writeCoreFunctionalities (api, os.path.join(outputPath, "vkCoreFunctionalities.inl")) writeExtensionFunctions (api, os.path.join(outputPath, "vkExtensionFunctions.inl")) writeDeviceFeatures2 (api, os.path.join(outputPath, "vkDeviceFeatures2.inl")) writeMandatoryFeatures (api, os.path.join(outputPath, "vkMandatoryFeatures.inl")) writeExtensionList (api, os.path.join(outputPath, "vkInstanceExtensions.inl"), 'instance') writeExtensionList (api, os.path.join(outputPath, "vkDeviceExtensions.inl"), 'device') writeDriverIds (api, os.path.join(outputPath, "vkKnownDriverIds.inl")) writeObjTypeImpl (api, os.path.join(outputPath, "vkObjTypeImpl.inl")) writeApiExtensionDependencyInfo (api, os.path.join(outputPath, "vkApiExtensionDependencyInfo.inl")) writeEntryPointValidation (api, os.path.join(outputPath, "vkEntryPointValidation.inl")) writeGetDeviceProcAddr (api, os.path.join(outputPath, "vkGetDeviceProcAddr.inl")) writeConformanceVersions ( os.path.join(outputPath, "vkKnownConformanceVersions.inl")) # NOTE: when new files are generated then they should also be added to the # vk-gl-cts\external\vulkancts\framework\vulkan\CMakeLists.txt outputs list