#!/usr/bin/python # -*- 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 copy from itertools import chain from collections import OrderedDict sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts")) from build.common import DEQP_DIR, execute from khr_util.format import indentLines, writeInlFile VULKAN_HEADERS_INCLUDE_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "include") VULKAN_SRC_DIR = os.path.join(os.path.dirname(__file__), "src") INL_HEADER = """\ /* WARNING: This is auto-generated file. Do not modify, since changes will * be lost! Modify the generating script instead. */\ """ 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*"), # VK_OpenHarmony_OHOS_surface (["NativeWindow", "*"], ["OhosNativeWindowPtr"], "void*"), ] PLATFORM_TYPE_NAMESPACE = "pt" TYPE_SUBSTITUTIONS = [ # Platform-specific ("DWORD", "uint32_t"), ("HANDLE*", PLATFORM_TYPE_NAMESPACE + "::" + "Win32Handle*"), ] EXTENSION_POSTFIXES = ["KHR", "EXT", "NV", "NVX", "KHX", "NN", "MVK", "FUCHSIA", "GGP", "AMD", "QNX", "OpenHarmony"] EXTENSION_POSTFIXES_STANDARD = ["KHR", "EXT"] def prefixName (prefix, name): if name=="VkOHOSNativeBufferUsageOpenHarmony": return "VK_STRUCTURE_TYPE_OHOS_NATIVE_BUFFER_USAGE_OPENHARMONY" if name=="VkOHOSNativeBufferPropertiesOpenHarmony": return "VK_STRUCTURE_TYPE_OHOS_NATIVE_BUFFER_PROPERTIES_OPENHARMONY" if name=="VkOHOSNativeBufferFormatPropertiesOpenHarmony": return "VK_STRUCTURE_TYPE_OHOS_NATIVE_BUFFER_FORMAT_PROPERTIES_OPENHARMONY" if name=="VkImportOHOSNativeBufferInfoOpenHarmony": return "VK_STRUCTURE_TYPE_IMPORT_OHOS_NATIVE_BUFFER_INFO_OPENHARMONY" if name=="VkMemoryGetOHOSNativeBufferInfoOpenHarmony": return "VK_STRUCTURE_TYPE_MEMORY_GET_OHOS_NATIVE_BUFFER_INFO_OPENHARMONY" if name=="VkExternalFormatOpenHarmony": return "VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OPENHARMONY" if name=="VkOHOSSurfaceCreateInfoOpenHarmony": return "VK_STRUCTURE_TYPE_OHOS_SURFACE_CREATE_INFO_OPENHARMONY" 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() name = name.replace("YCB_CR_", "YCBCR_") name = name.replace("WIN_32_", "WIN32_") name = name.replace("8_BIT_", "8BIT_") name = name.replace("16_BIT_", "16BIT_") name = name.replace("INT_64_", "INT64_") name = name.replace("D_3_D_12_", "D3D12_") name = name.replace("IOSSURFACE_", "IOS_SURFACE_") name = name.replace("MAC_OS", "MACOS_") name = name.replace("TEXTURE_LOD", "TEXTURE_LOD_") name = name.replace("VIEWPORT_W", "VIEWPORT_W_") name = name.replace("_IDPROPERTIES", "_ID_PROPERTIES") name = name.replace("PHYSICAL_DEVICE_SHADER_FLOAT_16_INT_8_FEATURES", "PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES") name = name.replace("PHYSICAL_DEVICE_RGBA_10_X_6_FORMATS_FEATURES_EXT", "PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT") name = name.replace("_PCIBUS_", "_PCI_BUS_") name = name.replace("ASTCD", "ASTC_D") name = name.replace("AABBNV", "AABB_NV") name = name.replace("IMAGE_PIPE", "IMAGEPIPE") name = name.replace("SMBUILTINS", "SM_BUILTINS") name = name.replace("ASTCHDRFEATURES", "ASTC_HDR_FEATURES") name = name.replace("UINT_8", "UINT8") name = name.replace("VULKAN_11_FEATURES", "VULKAN_1_1_FEATURES") name = name.replace("VULKAN_11_PROPERTIES", "VULKAN_1_1_PROPERTIES") name = name.replace("VULKAN_12_FEATURES", "VULKAN_1_2_FEATURES") name = name.replace("VULKAN_12_PROPERTIES", "VULKAN_1_2_PROPERTIES") name = name.replace("INT_8_", "INT8_") name = name.replace("AABBNV", "AABB_NV") name = name.replace("_H_264_", "_H264_") name = name.replace("_H_265_", "_H265_") name = name.replace("RDMAFEATURES", "RDMA_FEATURES") name = name.replace("RGBA_10_X_6", "RGBA10X6") return prefix + name class Version: def __init__ (self, versionTuple): self.major = versionTuple[0] self.minor = versionTuple[1] self.patch = versionTuple[2] def getInHex (self): if self.patch == 0: return "VK_API_VERSION_%d_%d" % (self.major, self.minor) return '0x%Xu' % (hash(self)) def isStandardVersion (self): if self.patch != 0: return False if self.major != 1: return False return True def getBestRepresentation (self): if self.isStandardVersion(): return self.getInHex() return self.getDefineName() def getDefineName (self): return 'VERSION_%d_%d_%d' % (self.major, self.minor, self.patch) def __hash__ (self): return (self.major << 22) | (self.minor << 12) | self.patch def __eq__ (self, other): return self.major == other.major and self.minor == other.minor and self.patch == other.patch def __str__ (self): return self.getBestRepresentation() class Handle: TYPE_DISP = 0 TYPE_NONDISP = 1 def __init__ (self, type, name): self.type = type self.name = name self.alias = None self.isAlias = False def getHandleType (self): return prefixName("HANDLE_TYPE_", self.name) def checkAliasValidity (self): pass def __repr__ (self): return '%s (%s, %s)' % (self.name, self.alias, self.isAlias) class Definition: def __init__ (self, type, name, value): self.type = type self.name = name self.value = value self.alias = None self.isAlias = False def __repr__ (self): return '%s = %s (%s)' % (self.name, self.value, self.type) class Enum: def __init__ (self, name, values): self.name = name self.values = values self.alias = None self.isAlias = False def checkAliasValidity (self): if self.alias != None: if len(self.values) != len(self.alias.values): raise Exception("%s has different number of flags than its alias %s." % (self.name, self.alias.name)) for index, value in enumerate(self.values): aliasVal = self.alias.values[index] if value[1] != aliasVal[1] or not (value[0].startswith(aliasVal[0]) or aliasVal[0].startswith(value[0])): raise Exception("Flag %s of %s has different value than %s of %s." % (self.alias.values[index], self.alias.name, value, self.name)) def __repr__ (self): return '%s (%s) %s' % (self.name, self.alias, self.values) class Bitfield: def __init__ (self, name, values): self.name = name self.values = values self.alias = None self.isAlias = False def checkAliasValidity (self): if self.alias != None: if len(self.values) != len(self.alias.values): raise Exception("%s has different number of flags than its alias %s." % (self.name, self.alias.name)) for index, value in enumerate(self.values): aliasVal = self.alias.values[index] if value[1] != aliasVal[1] or not (value[0].startswith(aliasVal[0]) or aliasVal[0].startswith(value[0])): raise Exception("Flag %s of %s has different value than %s of %s." % (self.alias.values[index], self.alias.name, value, self.name)) def __repr__ (self): return '%s (%s)' % (self.name, self.alias) class Variable: def __init__ (self, type, name, arraySizeOrFieldWidth): type = type.replace('*',' *').replace('&',' &') for src, dst in TYPE_SUBSTITUTIONS: type = type.replace(src, dst) self.type = type.split(' ') for platformType, substitute, compat in PLATFORM_TYPES: range = self.contains(self.type, platformType) if range != None: self.type = self.type[:range[0]]+[PLATFORM_TYPE_NAMESPACE + '::' + substitute[0]] + substitute[1:] + self.type[range[1]:] break self.name = name if len(arraySizeOrFieldWidth) > 0 and arraySizeOrFieldWidth[0] == ':': self.arraySize = '' self.fieldWidth = arraySizeOrFieldWidth else: self.arraySize = arraySizeOrFieldWidth self.fieldWidth = '' def contains(self, big, small): for i in range(len(big)-len(small)+1): for j in range(len(small)): if big[i+j] != small[j]: break else: return i, i+len(small) return None def getType (self): return ' '.join(self.type).replace(' *','*').replace(' &','&') def getAsString (self, separator): return '%s%s%s%s%s' % (self.getType(), separator, self.name, self.arraySize, self.fieldWidth) def getAsStringForArgumentList (self, separator): return '%s%s%s%s' % (self.getType(), separator, self.name, self.arraySize) def __repr__ (self): return '<%s> <%s> <%s>' % (self.type, self.name, self.arraySize) def __eq__ (self, other): if len(self.type) != len(other.type): return False for index, type in enumerate(self.type): if "*" == type or "&" == type or "const" == type or "volatile" == type: if type != other.type[index]: return False elif type != other.type[index] and \ type not in map(lambda ext: other.type[index] + ext, EXTENSION_POSTFIXES_STANDARD) and \ other.type[index] not in map(lambda ext: type + ext, EXTENSION_POSTFIXES_STANDARD): return False return self.arraySize == other.arraySize def __ne__ (self, other): return not self == other class CompositeType: CLASS_STRUCT = 0 CLASS_UNION = 1 def __init__ (self, typeClass, name, members, apiVersion = None): self.typeClass = typeClass self.name = name self.members = members self.alias = None self.isAlias = False self.apiVersion = apiVersion def getClassName (self): names = {CompositeType.CLASS_STRUCT: 'struct', CompositeType.CLASS_UNION: 'union'} return names[self.typeClass] def checkAliasValidity (self): if self.alias != None: if len(self.members) != len(self.alias.members): raise Exception("%s has different number of members than its alias %s." % (self.name, self.alias.name)) for index, member in enumerate(self.members ): break #if member != self.alias.members[index]: #raise Exception("Member %s of %s is different than core member %s in %s." % (self.alias.members[index], self.alias.name, member, self.name)) #raise Exception("Member ",str(self.alias.members[index])," of ", str(self.alias.name)," is different than core member ", str(member)," in ", str(self.name),".") def __repr__ (self): return '%s (%s)' % (self.name, self.alias) 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, arguments, apiVersion = None): self.name = name self.returnType = returnType self.arguments = arguments self.alias = None self.isAlias = False self.apiVersion = apiVersion def getType (self): # Special functions if self.name == "vkGetInstanceProcAddr": return Function.TYPE_PLATFORM assert len(self.arguments) > 0 firstArgType = self.arguments[0].getType() if firstArgType in ["VkInstance", "VkPhysicalDevice"]: return Function.TYPE_INSTANCE elif firstArgType in ["VkDevice", "VkCommandBuffer", "VkQueue"]: return Function.TYPE_DEVICE else: return Function.TYPE_PLATFORM def checkAliasValidity (self): if self.alias != None: if len(self.arguments) != len(self.alias.arguments): raise Exception("%s has different number of arguments than its alias %s." % (self.name, self.alias.name)) if self.returnType != self.alias.returnType or not (self.returnType.startswith(self.alias.returnType) or self.alias.returnType.startswith(self.returnType)): raise Exception("%s has different return value's type than its alias %s." % (self.name, self.alias.name)) for index, argument in enumerate(self.arguments): if argument != self.alias.arguments[index]: raise Exception("argument %s: \"%s\" of %s is different than \"%s\" of %s." % (index, self.alias.arguments[index].getAsString(' '), self.alias.name, argument.getAsString(' '), self.name)) def __repr__ (self): return '%s (%s)' % (self.name, self.alias) class Extension: def __init__ (self, name, handles, enums, bitfields, compositeTypes, functions, definitions, additionalDefinitions, typedefs, versionInCore): self.name = name self.definitions = definitions self.additionalDefs = additionalDefinitions self.handles = handles self.enums = enums self.bitfields = bitfields self.compositeTypes = compositeTypes self.functions = functions self.typedefs = typedefs self.versionInCore = versionInCore def __repr__ (self): return 'EXT:\n%s ->\nENUMS:\n%s\nCOMPOS:\n%s\nFUNCS:\n%s\nBITF:\n%s\nHAND:\n%s\nDEFS:\n%s\n' % (self.name, self.enums, self.compositeTypes, self.functions, self.bitfields, self.handles, self.definitions, self.versionInCore) class API: def __init__ (self, versions, definitions, handles, enums, bitfields, bitfields64, compositeTypes, functions, extensions): self.versions = versions self.definitions = definitions self.handles = handles self.enums = enums self.bitfields = bitfields self.bitfields64 = bitfields64 self.compositeTypes = compositeTypes self.functions = functions # \note contains extension functions as well self.extensions = extensions def readFile (filename): with open(filename, 'rt') as f: return f.read() IDENT_PTRN = r'[a-zA-Z_][a-zA-Z0-9_]*' WIDTH_PTRN = r'[:0-9]*' TYPE_PTRN = r'[a-zA-Z_][a-zA-Z0-9_ \t*&]*' def getInterfaceName (function): assert function.name[:2] == "vk" return function.name[2].lower() + function.name[3:] def getFunctionTypeName (function): assert function.name[:2] == "vk" return function.name[2:] + "Func" def endsWith (str, postfix): return str[-len(postfix):] == postfix def splitNameExtPostfix (name): knownExtPostfixes = EXTENSION_POSTFIXES for postfix in knownExtPostfixes: if endsWith(name, postfix): return (name[:-len(postfix)], postfix) return (name, "") def getBitEnumNameForBitfield (bitfieldName): bitfieldName, postfix = splitNameExtPostfix(bitfieldName) assert bitfieldName[-1] == "s" return bitfieldName[:-1] + "Bits" + postfix def getBitfieldNameForBitEnum (bitEnumName): bitEnumName, postfix = splitNameExtPostfix(bitEnumName) assert bitEnumName[-4:] == "Bits" return bitEnumName[:-4] + "s" + postfix def parsePreprocDefinedValue (src, name): value = parsePreprocDefinedValueOptional(src, name) if value is None: raise Exception("No such definition: %s" % name) return value def parsePreprocDefinedValueOptional (src, name): definition = re.search(r'#\s*define\s+' + name + r'\s+([^\n]+)\n', src) if definition is None: return None value = definition.group(1).strip() if value == "UINT32_MAX": value = "(~0u)" return value def parseEnum (name, src): keyValuePtrn = '(' + IDENT_PTRN + r')\s*=\s*([^\s,\n}]+)\s*[,\n}]' return Enum(name, re.findall(keyValuePtrn, src)) # \note Parses raw enums, some are mapped to bitfields later def parseEnums (src): matches = re.findall(r'typedef enum(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src) enums = [] for enumname, contents, typename in matches: enums.append(parseEnum(typename, contents)) return enums def parseCompositeType (type, name, src): typeNamePtrn = r'(' + TYPE_PTRN + r')(\s+' + IDENT_PTRN + r')((\[[^\]]+\]|\s*:\s*[0-9]+)*)\s*;' matches = re.findall(typeNamePtrn, src) members = [Variable(t.strip(), n.strip(), a.replace(' ', '')) for t, n, a, _ in matches] return CompositeType(type, name, members) def parseCompositeTypes (src): typeMap = { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION } matches = re.findall(r'typedef (struct|union)(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src) types = [] for type, structname, contents, typename in matches: types.append(parseCompositeType(typeMap[type], typename, contents)) return types def parseCompositeTypesByVersion (src, versionsData): # find occurence of extension is a place where # we cant assign apiVersion to found structures extPtrn = r'#define\s+[A-Z0-9_]+_EXTENSION_NAME\s+"([^"]+)"' versionEnd = re.search(extPtrn, src) versions = [Version((v[2], v[3], 0)) for v in versionsData] versions.append(None) # construct list of locations where version definitions start, and add the end of the file to it sectionLocations = [versionDef[1] for versionDef in versionsData] sectionLocations.append(versionEnd.start()) sectionLocations.append(len(src)) # construct function declaration pattern ptrn = r'typedef (struct|union)(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;' regPtrn = re.compile(ptrn) types = [] typeMap = { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION } # iterate over all versions and find all structure definitions for index, v in enumerate(versions): matches = regPtrn.findall(src, sectionLocations[index], sectionLocations[index+1]) for type, structname, contents, typename in matches: compositeType = parseCompositeType(typeMap[type], typename, contents) compositeType.apiVersion = v types.append(compositeType) return types def parseVersions (src): # returns list of tuples each with four items: # 1. string with version token (without ' 1' at the end) # 2. starting point off version specific definitions in vulkan.h.in # 3. major version number # 4. minor version number return [(m.group()[:-2], m.start(), int(m.group(1)), int(m.group(2))) for m in re.finditer('VK_VERSION_([1-9])_([0-9]) 1', src)] def parseHandles (src): matches = re.findall(r'VK_DEFINE(_NON_DISPATCHABLE|)_HANDLE\((' + IDENT_PTRN + r')\)[ \t]*[\n\r]', src) handles = [] typeMap = {'': Handle.TYPE_DISP, '_NON_DISPATCHABLE': Handle.TYPE_NONDISP} for type, name in matches: handle = Handle(typeMap[type], name) handles.append(handle) return handles def parseArgList (src): typeNamePtrn = r'(' + TYPE_PTRN + r')(\s+' + IDENT_PTRN + r')((\[[^\]]+\])*)\s*' args = [] for rawArg in src.split(','): m = re.search(typeNamePtrn, rawArg) args.append(Variable(m.group(1).strip(), m.group(2).strip(), m.group(3))) return args def removeTypeExtPostfix (name): for extPostfix in EXTENSION_POSTFIXES_STANDARD: if endsWith(name, extPostfix): return name[0:-len(extPostfix)] return None def populateExtensionAliases(allObjects, extensionObjects): for object in extensionObjects: withoutPostfix = removeTypeExtPostfix(object.name) if withoutPostfix != None and withoutPostfix in allObjects: # max 1 alias is assumed by functions in this file assert allObjects[withoutPostfix].alias == None allObjects[withoutPostfix].alias = object object.isAlias = True for object in extensionObjects: object.checkAliasValidity() def populateAliasesWithTypedefs (objects, src): objectsByName = {} for object in objects: objectsByName[object.name] = object ptrn = r'\s*typedef\s+' + object.name + r'\s+([^;]+)' stash = re.findall(ptrn, src) if len(stash) == 1: objExt = copy.deepcopy(object) objExt.name = stash[0] object.alias = objExt objExt.isAlias = True objects.append(objExt) def removeAliasedValues (enum): valueByName = {} for name, value in enum.values: valueByName[name] = value def removeDefExtPostfix (name): for extPostfix in EXTENSION_POSTFIXES: if endsWith(name, "_" + extPostfix): return name[0:-(len(extPostfix)+1)] return None newValues = [] for name, value in enum.values: withoutPostfix = removeDefExtPostfix(name) if withoutPostfix != None and withoutPostfix in valueByName and valueByName[withoutPostfix] == value: continue newValues.append((name, value)) enum.values = newValues def parseFunctions (src): ptrn = r'VKAPI_ATTR\s+(' + TYPE_PTRN + ')\s+VKAPI_CALL\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;' matches = re.findall(ptrn, src) functions = [] for returnType, name, argList in matches: functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList))) return functions def parseFunctionsByVersion (src, versions): # construct list of locations where version definitions start, and add the end of the file to it sectionLocations = [versionDef[1] for versionDef in versions] sectionLocations.append(len(src)) # construct function declaration pattern ptrn = r'VKAPI_ATTR\s+(' + TYPE_PTRN + ')\s+VKAPI_CALL\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;' regPtrn = re.compile(ptrn) functions = [] # iterate over all versions and find all function definitions for index, v in enumerate(versions): matches = regPtrn.findall(src, sectionLocations[index], sectionLocations[index+1]) for returnType, name, argList in matches: functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList), v[0])) return functions def splitByExtension (src): ptrn = r'#define\s+[A-Z0-9_]+_EXTENSION_NAME\s+"([^"]+)"' # Construct long pattern that will be used to split whole source by extensions match = "#define\s+(" for part in re.finditer(ptrn, src): match += part.group(1)+"|" match = match[:-1] + ")\s+1" parts = re.split(match, src) # First part is core, following tuples contain extension name and all its definitions byExtension = [(None, parts[0])] for ndx in range(1, len(parts), 2): byExtension.append((parts[ndx], parts[ndx+1])) return byExtension def parseDefinitions (extensionName, src): def skipDefinition (extensionName, definition): if extensionName == None: return True extNameUpper = extensionName.upper() extNameUpper = extNameUpper.replace("VK_KHR_SYNCHRONIZATION2", "VK_KHR_SYNCHRONIZATION_2") extNameUpper = extNameUpper.replace("VK_INTEL_SHADER_INTEGER_FUNCTIONS2", "VK_INTEL_SHADER_INTEGER_FUNCTIONS_2") extNameUpper = extNameUpper.replace("VK_EXT_ROBUSTNESS2", "VK_EXT_ROBUSTNESS_2") extNameUpper = extNameUpper.replace("VK_EXT_FRAGMENT_DENSITY_MAP2", "VK_EXT_FRAGMENT_DENSITY_MAP_2") extNameUpper = extNameUpper.replace("VK_EXT_SHADER_ATOMIC_FLOAT2", "VK_EXT_SHADER_ATOMIC_FLOAT_2") extNameUpper = extNameUpper.replace("VK_AMD_SHADER_CORE_PROPERTIES2", "VK_AMD_SHADER_CORE_PROPERTIES_2") extNameUpper = extNameUpper.replace("VK_EXT_EXTENDED_DYNAMIC_STATE2", "VK_EXT_EXTENDED_DYNAMIC_STATE_2") # SPEC_VERSION enums if definition[0].startswith(extNameUpper) and definition[1].isdigit(): return False if definition[0].startswith(extNameUpper): return True if definition[0].endswith("_H_"): return True return False ptrn = r'#define\s+([^\s]+)\s+([^\r\n]+)' matches = re.findall(ptrn, src) return [Definition(None, match[0], match[1]) for match in matches if not skipDefinition(extensionName, match)] def parseTypedefs (src): ptrn = r'typedef\s+([^\s]+)\s+([^\r\n]+);' matches = re.findall(ptrn, src) return [Definition(None, match[0], match[1]) for match in matches] def parseExtensions (src, versions, allFunctions, allCompositeTypes, allEnums, allBitfields, allHandles, allDefinitions): def getCoreVersion (extensionName, extensionsData): # returns None when extension was not added to core for any Vulkan version # returns array containing DEVICE or INSTANCE string followed by the vulkan version in which this extension is core # note that this function is also called for vulkan 1.0 source for which extName is None if not extensionName: return None ptrn = extensionName + r'\s+(DEVICE|INSTANCE)\s+([0-9_]+)' coreVersion = re.search(ptrn, extensionsData, re.I) if coreVersion != None: return [coreVersion.group(1)] + [int(number) for number in coreVersion.group(2).split('_')[:3]] return None extensionsData = readFile(os.path.join(VULKAN_SRC_DIR, "extensions_data.txt")) splitSrc = splitByExtension(src) extensions = [] functionsByName = {function.name: function for function in allFunctions} compositeTypesByName = {compType.name: compType for compType in allCompositeTypes} enumsByName = {enum.name: enum for enum in allEnums} bitfieldsByName = {bitfield.name: bitfield for bitfield in allBitfields} handlesByName = {handle.name: handle for handle in allHandles} definitionsByName = {definition.name: definition for definition in allDefinitions} for extensionName, extensionSrc in splitSrc: definitions = [Definition("uint32_t", v.getInHex(), parsePreprocDefinedValueOptional(extensionSrc, v.getInHex())) for v in versions] definitions.extend([Definition(type, name, parsePreprocDefinedValueOptional(extensionSrc, name)) for name, type in DEFINITIONS]) definitions = [definition for definition in definitions if definition.value != None] additionalDefinitions = parseDefinitions(extensionName, extensionSrc) handles = parseHandles(extensionSrc) functions = parseFunctions(extensionSrc) compositeTypes = parseCompositeTypes(extensionSrc) rawEnums = parseEnums(extensionSrc) bitfieldNames = parseBitfieldNames(extensionSrc) typedefs = parseTypedefs(extensionSrc) enumBitfieldNames = [getBitEnumNameForBitfield(name) for name in bitfieldNames] enums = [enum for enum in rawEnums if enum.name not in enumBitfieldNames] extCoreVersion = getCoreVersion(extensionName, extensionsData) extFunctions = [functionsByName[function.name] for function in functions] extCompositeTypes = [compositeTypesByName[compositeType.name] for compositeType in compositeTypes] extEnums = [enumsByName[enum.name] for enum in enums] extBitfields = [bitfieldsByName[bitfieldName] for bitfieldName in bitfieldNames] extHandles = [handlesByName[handle.name] for handle in handles] extDefinitions = [definitionsByName[definition.name] for definition in definitions] if extCoreVersion != None: populateExtensionAliases(functionsByName, extFunctions) populateExtensionAliases(handlesByName, extHandles) populateExtensionAliases(enumsByName, extEnums) populateExtensionAliases(bitfieldsByName, extBitfields) populateExtensionAliases(compositeTypesByName, extCompositeTypes) extensions.append(Extension(extensionName, extHandles, extEnums, extBitfields, extCompositeTypes, extFunctions, extDefinitions, additionalDefinitions, typedefs, extCoreVersion)) return extensions def parseBitfieldNames (src): ptrn = r'typedef\s+VkFlags\s(' + IDENT_PTRN + r')\s*;' matches = re.findall(ptrn, src) return matches def parse64bitBitfieldNames (src): ptrn = r'typedef\s+VkFlags64\s(' + IDENT_PTRN + r')\s*;' matches = re.findall(ptrn, src) return matches def parse64bitBitfieldValues (src, bitfieldNamesList): bitfields64 = [] for bitfieldName in bitfieldNamesList: ptrn = r'static const ' + bitfieldName + r'\s*(' + IDENT_PTRN + r')\s*=\s*([a-zA-Z0-9_]+)\s*;' matches = re.findall(ptrn, src) bitfields64.append(Bitfield(bitfieldName, matches)) return bitfields64 def parseAPI (src): versionsData = parseVersions(src) versions = [Version((v[2], v[3], 0)) for v in versionsData] definitions = [Definition("uint32_t", v.getInHex(), parsePreprocDefinedValue(src, v.getInHex())) for v in versions] +\ [Definition(type, name, parsePreprocDefinedValue(src, name)) for name, type in DEFINITIONS] handles = parseHandles(src) rawEnums = parseEnums(src) bitfieldNames = parseBitfieldNames(src) bitfieldEnums = set([getBitEnumNameForBitfield(n) for n in bitfieldNames if getBitEnumNameForBitfield(n) in [enum.name for enum in rawEnums]]) bitfield64Names = parse64bitBitfieldNames(src) bitfields64 = parse64bitBitfieldValues(src, bitfield64Names) enums = [] bitfields = [] compositeTypes = parseCompositeTypesByVersion(src, versionsData) allFunctions = parseFunctionsByVersion(src, versionsData) for enum in rawEnums: if enum.name in bitfieldEnums: bitfields.append(Bitfield(getBitfieldNameForBitEnum(enum.name), enum.values)) else: enums.append(enum) for bitfieldName in bitfieldNames: if not bitfieldName in [bitfield.name for bitfield in bitfields]: # Add empty bitfield bitfields.append(Bitfield(bitfieldName, [])) extensions = parseExtensions(src, versions, allFunctions, compositeTypes, enums, bitfields, handles, definitions) # Populate alias fields populateAliasesWithTypedefs(compositeTypes, src) populateAliasesWithTypedefs(enums, src) populateAliasesWithTypedefs(bitfields, src) populateAliasesWithTypedefs(handles, src) for enum in enums: removeAliasedValues(enum) # Make generator to create Deleter for f in allFunctions: if (f.name == 'vkDestroyAccelerationStructureNV'): f.arguments[1].type[0] = 'VkAccelerationStructureNV' # Dealias handles VkAccelerationStructureNV and VkAccelerationStructureKHR for handle in handles: if handle.name == 'VkAccelerationStructureKHR': handle.alias = None if handle.name == 'VkAccelerationStructureNV': handle.isAlias = False return API( versions = versions, definitions = definitions, handles = handles, enums = enums, bitfields = bitfields, bitfields64 = bitfields64, compositeTypes = compositeTypes, functions = allFunctions, extensions = extensions) def splitUniqueAndDuplicatedEntries (handles): listOfUniqueHandles = [] duplicates = OrderedDict() for handle in handles: if handle.alias != None: duplicates[handle.alias] = handle if not handle.isAlias: listOfUniqueHandles.append(handle) return listOfUniqueHandles, duplicates def writeHandleType (api, filename): uniqeHandles, duplicatedHandles = splitUniqueAndDuplicatedEntries(api.handles) def genHandles (): yield "\t%s\t= 0," % uniqeHandles[0].getHandleType() for handle in uniqeHandles[1:]: yield "\t%s," % handle.getHandleType() for duplicate in duplicatedHandles: yield "\t%s\t= %s," % (duplicate.getHandleType(), duplicatedHandles[duplicate].getHandleType()) yield "\tHANDLE_TYPE_LAST\t= %s + 1" % (uniqeHandles[-1].getHandleType()) def genHandlesBlock (): yield "enum HandleType" yield "{" for line in indentLines(genHandles()): yield line yield "};" yield "" writeInlFile(filename, INL_HEADER, genHandlesBlock()) def getEnumValuePrefix (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() return prefix def parseInt (value): if value[:2] == "0x": return int(value, 16) else: return int(value, 10) def areEnumValuesLinear (enum): curIndex = 0 for name, value in enum.values: if value[:2] != "VK": intValue = parseInt(value) if intValue != curIndex: # consider enums containing *_MAX_ENUM = 0x7FFFFFFF as linear if intValue == 0x7FFFFFFF: return True return False curIndex += 1 return True def genEnumSrc (enum): yield "enum %s" % enum.name yield "{" lines = [] if areEnumValuesLinear(enum): hasMaxItem = parseInt(enum.values[-1][1]) == 0x7FFFFFFF values = enum.values[:-1] if hasMaxItem else enum.values lastItem = "\t%s_LAST," % getEnumValuePrefix(enum) # linear values first, followed by *_LAST lines += ["\t%s\t= %s," % v for v in values if v[1][:2] != "VK"] lines.append(lastItem) # equivalence enums and *_MAX_ENUM lines += ["\t%s\t= %s," % v for v in values if v[1][:2] == "VK"] if hasMaxItem: lines.append("\t%s\t= %s," % enum.values[-1]) else: lines += ["\t%s\t= %s," % v for v in enum.values] for line in indentLines(lines): yield line yield "};" def genBitfieldSrc (bitfield): if len(bitfield.values) > 0: yield "enum %s" % getBitEnumNameForBitfield(bitfield.name) yield "{" for line in indentLines(["\t%s\t= %s," % v for v in bitfield.values]): yield line yield "};" yield "typedef uint32_t %s;" % bitfield.name def genBitfield64Src (bitfield64): yield "typedef uint64_t %s;" % bitfield64.name if len(bitfield64.values) > 0: ptrn = "static const " + bitfield64.name + " %s\t= %s;" for line in indentLines([ptrn % v for v in bitfield64.values]): yield line yield "" def genCompositeTypeSrc (type): yield "%s %s" % (type.getClassName(), type.name) yield "{" for line in indentLines(['\t'+m.getAsString('\t')+';' for m in type.members]): yield line yield "};" def genHandlesSrc (handles): uniqeHandles, duplicatedHandles = splitUniqueAndDuplicatedEntries(handles) def genLines (handles): for handle in uniqeHandles: if handle.type == Handle.TYPE_DISP: yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType()) elif handle.type == Handle.TYPE_NONDISP: yield "VK_DEFINE_NON_DISPATCHABLE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType()) for duplicate in duplicatedHandles: if duplicate.type == Handle.TYPE_DISP: yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (duplicate.name, duplicatedHandles[duplicate].getHandleType()) elif duplicate.type == Handle.TYPE_NONDISP: yield "VK_DEFINE_NON_DISPATCHABLE_HANDLE\t(%s,\t%s);" % (duplicate.name, duplicatedHandles[duplicate].getHandleType()) for line in indentLines(genLines(handles)): yield line def stripTrailingComment(str): index = str.find("//") if index == -1: return str return str[:index] def genDefinitionsSrc (definitions): for line in ["#define %s\t(static_cast<%s>\t(%s))" % (definition.name, definition.type, stripTrailingComment(definition.value)) for definition in definitions]: yield line def genDefinitionsAliasSrc (definitions): for line in ["#define %s\t%s" % (definition.name, definitions[definition].name) for definition in definitions]: if definition.value != definitions[definition].value and definition.value != definitions[definition].name: raise Exception("Value of %s (%s) is different than core definition value %s (%s)." % (definition.name, definition.value, definitions[definition].name, definitions[definition].value)) yield line def genMaxFrameworkVersion (definitions): maxApiVersionMajor = 1 maxApiVersionMinor = 0 for definition in definitions: match = re.match("VK_API_VERSION_(\d+)_(\d+)", definition.name) if match: apiVersionMajor = int(match.group(1)) apiVersionMinor = int(match.group(2)) if apiVersionMajor > maxApiVersionMajor: maxApiVersionMajor = apiVersionMajor maxApiVersionMinor = apiVersionMinor elif apiVersionMajor == maxApiVersionMajor and apiVersionMinor > maxApiVersionMinor: maxApiVersionMinor = apiVersionMinor yield "#define VK_API_MAX_FRAMEWORK_VERSION\tVK_API_VERSION_%d_%d" % (maxApiVersionMajor, maxApiVersionMinor) def writeBasicTypes (api, filename): def gen (): definitionsCore, definitionDuplicates = splitUniqueAndDuplicatedEntries(api.definitions) for line in indentLines(chain(genDefinitionsSrc(definitionsCore), genMaxFrameworkVersion(definitionsCore), genDefinitionsAliasSrc(definitionDuplicates))): yield line yield "" for line in genHandlesSrc(api.handles): yield line yield "" for enum in api.enums: if not enum.isAlias: for line in genEnumSrc(enum): yield line else: for enum2 in api.enums: if enum2.alias == enum: yield "typedef %s %s;" % (enum2.name, enum.name) yield "" for bitfield in api.bitfields: if not bitfield.isAlias: for line in genBitfieldSrc(bitfield): yield line else: for bitfield2 in api.bitfields: if bitfield2.alias == bitfield: yield "typedef %s %s;" % (bitfield2.name, bitfield.name) yield "" for bitfield64 in api.bitfields64: for line in genBitfield64Src(bitfield64): yield line for line in indentLines(["VK_DEFINE_PLATFORM_TYPE(%s,\t%s)" % (s[0], c) for n, s, c in PLATFORM_TYPES]): yield line for ext in api.extensions: if ext.additionalDefs != None: for definition in ext.additionalDefs: yield "#define " + definition.name + " " + definition.value writeInlFile(filename, INL_HEADER, gen()) def writeCompositeTypes (api, filename): def gen (): for type in api.compositeTypes: type.checkAliasValidity() if not type.isAlias: for line in genCompositeTypeSrc(type): yield line else: for type2 in api.compositeTypes: if type2.alias == type: yield "typedef %s %s;" % (type2.name, type.name) yield "" writeInlFile(filename, INL_HEADER, gen()) def argListToStr (args): return ", ".join(v.getAsStringForArgumentList(' ') for v 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 if not function.isAlias: yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments), postfix) writeInlFile(filename, INL_HEADER, indentLines(genProtos())) def writeFunctionPtrTypes (api, filename): def genTypes (): for function in api.functions: yield "typedef VKAPI_ATTR %s\t(VKAPI_CALL* %s)\t(%s);" % (function.returnType, getFunctionTypeName(function), argListToStr(function.arguments)) writeInlFile(filename, INL_HEADER, indentLines(genTypes())) def writeFunctionPointers (api, filename, functionTypes): def FunctionsYielder (): for function in api.functions: if function.getType() in functionTypes: if function.isAlias: if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice": yield "%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function)) else: yield "%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function)) writeInlFile(filename, INL_HEADER, indentLines(FunctionsYielder())) def writeInitFunctionPointers (api, filename, functionTypes, cond = None): def makeInitFunctionPointers (): for function in api.functions: if function.getType() in functionTypes and (cond == None or cond(function)): interfaceName = getInterfaceName(function) if function.isAlias: if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice": yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name) else: yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name) if function.alias != None: yield "if (!m_vk.%s)" % (getInterfaceName(function)) yield " m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.alias.name) lines = [line.replace(' ', '\t') for line in indentLines(makeInitFunctionPointers())] writeInlFile(filename, INL_HEADER, lines) def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className): def makeFuncPtrInterfaceImpl (): for function in api.functions: if function.getType() in functionTypes and not function.isAlias: yield "" yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), 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].getType() == "VkPhysicalDevice" and function.alias != None: 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), ", ".join(a.name for a in function.arguments)) yield " else" yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.alias), ", ".join(a.name for a in function.arguments)) else: yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments)) yield "}" writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl()) 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 not enum.isAlias]): 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 not e.isAlias]): 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 not e.isAlias]): yield line yield "" for line in indentLines(["tcu::Format::Bitfield<32>\tget%sStr\t(%s value);" % (bitfield.name[2:], bitfield.name) for bitfield in api.bitfields if not bitfield.isAlias or bitfield.name=='VkBuildAccelerationStructureFlagsNV']): yield line yield "" for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.compositeTypes if not s.isAlias]): 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 if not handle.isAlias]): 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 "}" for enum in api.enums: if enum.isAlias: continue yield "" yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name) yield "{" yield "\tswitch (value)" yield "\t{" for line in indentLines(["\t\tcase %s:\treturn \"%s\";" % (n, n) for n, v in enum.values if v[:2] != "VK"] + ["\t\tdefault:\treturn DE_NULL;"]): yield line yield "\t}" yield "}" for bitfield in api.bitfields: if bitfield.isAlias: if bitfield.name != 'VkBuildAccelerationStructureFlagsNV': continue yield "" yield "tcu::Format::Bitfield<32> get%sStr (%s value)" % (bitfield.name[2:], bitfield.name) yield "{" if len(bitfield.values) > 0: yield "\tstatic const tcu::Format::BitDesc s_desc[] =" yield "\t{" for line in indentLines(["\t\ttcu::Format::BitDesc(%s,\t\"%s\")," % (n, n) for n, v in bitfield.values]): yield line yield "\t};" yield "\treturn tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));" else: yield "\treturn tcu::Format::Bitfield<32>(value, DE_NULL, DE_NULL);" yield "}" bitfieldTypeNames = set([bitfield.name for bitfield in api.bitfields]) for type in api.compositeTypes: if not type.isAlias: 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.getType() in bitfieldTypeNames: valFmt = "get%sStr(value.%s)" % (member.getType()[2:], member.name) elif member.getType() == "const char*" or member.getType() == "char*": valFmt = "getCharPtrStr(value.%s)" % member.name elif member.getType() == PLATFORM_TYPE_NAMESPACE + "::Win32LPCWSTR": valFmt = "getWStr(value.%s)" % member.name elif member.arraySize != '': singleDimensional = not '][' in member.arraySize if member.name in ["extensionName", "deviceName", "layerName", "description"]: valFmt = "(const char*)value.%s" % member.name elif singleDimensional and (member.getType() == 'char' or member.getType() == '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.getType(), member.name, member.getType(), 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 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 if not handle.isAlias]): 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: [Variable("const PlatformInterface&", "vk", "")], Function.TYPE_INSTANCE: [Variable("const InstanceInterface&", "vk", "")], Function.TYPE_DEVICE: [Variable("const DeviceInterface&", "vk", "")] } for function in api.functions: if function.isAlias: continue 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?) # \todo [pyry] Rather hacky ifaceArgs = ifacesDict[function.getType()] if function.name == "vkCreateDevice": ifaceArgs = [Variable("const PlatformInterface&", "vkp", ""), Variable("VkInstance", "instance", "")] + ifaceArgs assert (function.arguments[-2].type == ["const", "VkAllocationCallbacks", "*"]) objectType = function.arguments[-1].type[0] #not getType() but type[0] on purpose arguments = function.arguments[:-1] funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function), 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 removeVersionDefines(versionSpectrum): output = ["#undef " + ver.getDefineName() 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" \ and not function.isAlias: objectType = function.arguments[-2].getType() yield "template<>" yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType) yield "{" yield "\tm_deviceIface->%s(m_device, obj, m_allocator);" % (getInterfaceName(function)) 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 type in api.compositeTypes: if type.getClassName() == "struct" and type.members[0].name == "sType" and not type.isAlias and type.name != "VkBaseOutStructure" and type.name != "VkBaseInStructure": yield "template<> VkStructureType getStructureType<%s> (void)" % type.name yield "{" yield "\treturn %s;" % prefixName("VK_STRUCTURE_TYPE_", type.name) 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", ] coreFunctions = [f for f in api.functions if not f.isAlias] specialFuncs = [f for f in coreFunctions if f.name in specialFuncNames] createFuncs = [f for f in coreFunctions if (f.name[:8] == "vkCreate" or f.name == "vkAllocateMemory") and not f in specialFuncs] destroyFuncs = [f for f in coreFunctions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs] dummyFuncs = [f for f in coreFunctions if f not in specialFuncs + createFuncs + destroyFuncs] def getHandle (name): for handle in api.handles: if handle.name == name[0]: return handle raise Exception("No such handle: %s" % name) for function in createFuncs: objectType = function.arguments[-1].type[:-1] argsStr = ", ".join([a.name for a in function.arguments[:-1]]) yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments)) yield "{" yield "\tDE_UNREF(%s);" % function.arguments[-2].name if getHandle(objectType).type == Handle.TYPE_NONDISP: yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[0][2:], objectType[0], argsStr) else: yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[0][2:], objectType[0], argsStr) yield "}" yield "" for function in destroyFuncs: objectArg = function.arguments[-2] yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments)) yield "{" for arg in function.arguments[:-2]: yield "\tDE_UNREF(%s);" % arg.name if getHandle(objectArg.type).type == Handle.TYPE_NONDISP: yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.getType()[2:], objectArg.getType(), objectArg.name, function.arguments[-1].name) else: yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.getType()[2:], objectArg.getType(), objectArg.name, function.arguments[-1].name) yield "}" yield "" for function in dummyFuncs: yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), 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): funcs = [f for f in api.functions if f.getType() == type] refFuncs = {} for f in api.functions: if f.alias != None: refFuncs[f.alias] = f yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name yield "{" for line in indentLines(["\tVK_NULL_FUNC_ENTRY(%s,\t%s)," % (function.name, getInterfaceName(function if not function.isAlias else refFuncs[function])) for function in funcs]): 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", "StdVideoDecodeH264MvcElementFlags", "StdVideoEncodeH264SliceHeaderFlags", "StdVideoEncodeH264PictureInfoFlags", "StdVideoEncodeH264RefMgmtFlags", "StdVideoH265HrdFlags", "StdVideoH265VpsFlags", "StdVideoH265SpsVuiFlags", "StdVideoH265SpsFlags", "StdVideoH265PpsFlags", "StdVideoDecodeH265PictureInfoFlags", "StdVideoDecodeH265ReferenceInfoFlags", "StdVideoEncodeH265PictureInfoFlags", "StdVideoEncodeH265SliceHeaderFlags", "StdVideoEncodeH265ReferenceModificationFlags", "StdVideoEncodeH265ReferenceInfoFlags", ]) COMPOSITE_TYPES = set([t.name for t in api.compositeTypes if not t.isAlias]) def isSimpleStruct (type): def hasArrayMember (type): for member in type.members: if member.arraySize != '': return True return False def hasCompositeMember (type): for member in type.members: if member.getType() in COMPOSITE_TYPES: return True return False return type.typeClass == CompositeType.CLASS_STRUCT and \ type.members[0].getType() != "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) or type.isAlias: 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(filename): driverIdsString = [] driverIdsString.append("static const struct\n" "{\n" "\tstd::string driver;\n" "\tuint32_t id;\n" "} driverIds [] =\n" "{") vulkanCore = readFile(os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "vulkan", "vulkan_core.h")) items = re.search(r'(?:typedef\s+enum\s+VkDriverId\s*{)((.*\n)*)(?:}\s*VkDriverId\s*;)', vulkanCore).group(1).split(',') driverItems = dict() for item in items: item.strip() splitted = item.split('=') key = splitted[0].strip() value_str = splitted[1].strip() try: # is this previously defined value? value = driverItems[value_str] except: value = value_str value_str = "" if value_str: value_str = "\t// " + value_str driverItems[key] = value if not item == items[-1]: driverIdsString.append("\t{\"" + key + "\"" + ", " + value + "}," + value_str) else: driverIdsString.append("\t{\"" + key + "\"" + ", " + value + "}" + value_str) driverItems[key] = value driverIdsString.append("};") writeInlFile(filename, INL_HEADER, driverIdsString) def writeSupportedExtenions(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(" }") return result instanceMap = {} deviceMap = {} versionSet = set() for ext in api.extensions: if ext.versionInCore != None: if ext.versionInCore[0] == 'INSTANCE': list = instanceMap.get(Version(ext.versionInCore[1:])) instanceMap[Version(ext.versionInCore[1:])] = list + [ext] if list else [ext] else: list = deviceMap.get(Version(ext.versionInCore[1:])) deviceMap[Version(ext.versionInCore[1:])] = list + [ext] if list else [ext] versionSet.add(Version(ext.versionInCore[1:])) lines = addVersionDefines(versionSet) + [ "", "void getCoreDeviceExtensionsImpl (uint32_t coreVersion, ::std::vector&%s)" % (" dst" if len(deviceMap) != 0 else ""), "{"] + writeExtensionsForVersions(deviceMap) + [ "}", "", "void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector&%s)" % (" dst" if len(instanceMap) != 0 else ""), "{"] + writeExtensionsForVersions(instanceMap) + [ "}", ""] + removeVersionDefines(versionSet) writeInlFile(filename, INL_HEADER, lines) def writeExtensionFunctions (api, filename): def isInstanceExtension (ext): if ext.name and ext.functions: if ext.functions[0].getType() == Function.TYPE_INSTANCE: return True else: return False def isDeviceExtension (ext): if ext.name and ext.functions: if ext.functions[0].getType() == Function.TYPE_DEVICE: return True else: return False def writeExtensionNameArrays (): instanceExtensionNames = [] deviceExtensionNames = [] for ext in api.extensions: if ext.name and isInstanceExtension(ext): instanceExtensionNames += [ext.name] elif ext.name and isDeviceExtension(ext): deviceExtensionNames += [ext.name] yield '::std::string instanceExtensionNames[] =\n{' for instanceExtName in instanceExtensionNames: if (instanceExtName == instanceExtensionNames[len(instanceExtensionNames) - 1]): yield '\t"%s"' % instanceExtName else: yield '\t"%s",' % instanceExtName yield '};\n' yield '::std::string deviceExtensionNames[] =\n{' for deviceExtName in deviceExtensionNames: if (deviceExtName == deviceExtensionNames[len(deviceExtensionNames) - 1]): yield '\t"%s"' % deviceExtName else: yield '\t"%s",' % 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 = [] if ext.name: for func in ext.functions: if func.getType() == functionType: # only add functions with same vendor as extension # this is a workaroudn for entrypoints requiring more # than one excetions and lack of the dependency in vulkan_core.h vendor = ext.name.split('_')[1] if func.name.endswith(vendor): funcNames.append(func.name) 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"] lines = addVersionDefines(api.versions) + [ "", '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(" + str(v) + ", FunctionInfosList()));" for v in api.versions] + [ ""] apiVersions = [] for index, v in enumerate(api.versions): funcs = [] apiVersions.append("VK_VERSION_{0}_{1}".format(v.major, v.minor)) # iterate over all functions that are core in latest vulkan version # note that first item in api.extension array are actually all definitions that are in vulkan.h.in before section with extensions for fun in api.extensions[0].functions: if fun.apiVersion in apiVersions: funcs.append(' apis[' + str(v) + '].push_back(FunctionInfo("' + fun.name + '",\t' + functionOriginValues[fun.getType()] + '));') lines = lines + [line for line in indentLines(funcs)] + [""] lines = lines + ["}", ""] + removeVersionDefines(api.versions) writeInlFile(filename, INL_HEADER, lines) def writeDeviceFeatures2(api, filename): # list of structures that should be tested with getPhysicalDeviceFeatures2 # this is not posible to determine from vulkan_core.h, if new feature structures # are added they should be manualy added to this list testedStructures = [ 'VkPhysicalDeviceConditionalRenderingFeaturesEXT', 'VkPhysicalDeviceScalarBlockLayoutFeatures', 'VkPhysicalDevicePerformanceQueryFeaturesKHR', 'VkPhysicalDevice16BitStorageFeatures', 'VkPhysicalDeviceMultiviewFeatures', 'VkPhysicalDeviceProtectedMemoryFeatures', 'VkPhysicalDeviceSamplerYcbcrConversionFeatures', 'VkPhysicalDeviceVariablePointersFeatures', 'VkPhysicalDevice8BitStorageFeatures', 'VkPhysicalDeviceShaderAtomicInt64Features', 'VkPhysicalDeviceShaderFloat16Int8Features', 'VkPhysicalDeviceBufferDeviceAddressFeaturesEXT', 'VkPhysicalDeviceBufferDeviceAddressFeatures', 'VkPhysicalDeviceDescriptorIndexingFeatures', 'VkPhysicalDeviceTimelineSemaphoreFeatures', 'VkPhysicalDeviceFragmentDensityMapFeaturesEXT', 'VkPhysicalDeviceFragmentDensityMap2FeaturesEXT', 'VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR', ] # helper class used to encapsulate all data needed during generation class StructureDetail: def __init__ (self, name): nameResult = re.search('(.*)Features(.*)', name[len('VkPhysicalDevice'):]) nameSplitUp = '' # generate structure type name from structure name # note that sometimes digits are separated with '_': # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT # but mostly they are not: # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES if (nameResult.group(1) == 'FragmentDensityMap2'): nameSplitUp = ['FRAGMENT', 'DENSITY', 'MAP', '2', 'FEATURES'] else: nameSplit = re.findall(r'[1-9A-Z]+(?:[a-z1-9]+|[A-Z]*(?=[A-Z]|$))', nameResult.group(1)) nameSplitUp = map(str.upper, nameSplit) nameSplitUp = list(nameSplitUp) + ['FEATURES'] # check if there is extension suffix if (len(nameResult.group(2)) != 0): nameSplitUp.append(nameResult.group(2)) self.name = name self.sType = 'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_' + '_'.join(nameSplitUp) self.instanceName = 'd' + name[11:] self.flagName = 'is' + name[16:] self.extension = None self.major = None self.minor = None self.members = [] # helper extension class used in algorith below class StructureFoundContinueToNextOne(Exception): pass testedStructureDetail = [StructureDetail(struct) for struct in testedStructures] # iterate over all searched structures and find extensions that enable them for structureDetail in testedStructureDetail: try: # iterate over all extensions for extension in api.extensions[1:]: # check composite types and typedefs in case extension is part of core for structureList in [extension.compositeTypes, extension.typedefs]: # iterate over all structures added by extension for extensionStructure in structureList: # compare checked structure name to name of structure from extension if structureDetail.name == extensionStructure.name: structureDetail.extension = extension.name if extension.versionInCore is not None: structureDetail.major = extension.versionInCore[1] structureDetail.minor = extension.versionInCore[2] raise StructureFoundContinueToNextOne except StructureFoundContinueToNextOne: continue for structureDetail in testedStructureDetail: for compositeType in api.compositeTypes: if structureDetail.name != compositeType.name: continue structureMembers = compositeType.members[2:] structureDetail.members = [m.name for m in structureMembers] if structureDetail.major is not None: break # if structure was not added with extension then check if # it was added directly with one of vulkan versions apiVersion = compositeType.apiVersion if apiVersion is None: continue structureDetail.major = apiVersion.major structureDetail.minor = apiVersion.minor break # generate file content structureDefinitions = [] featureEnabledFlags = [] clearStructures = [] structureChain = [] logStructures = [] verifyStructures = [] for index, structureDetail in enumerate(testedStructureDetail): # create two instances of each structure nameSpacing = '\t' * int((55 - len(structureDetail.name)) / 4) structureDefinitions.append(structureDetail.name + 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: if condition != '': condition += '\t' * int((39 - len(extension)) / 4) + '|| ' else: condition += '\t' * 17 + ' ' condition += 'context.contextSupports(vk::ApiVersion(' + str(major) + ', ' + str(structureDetail.minor) + ', 0))' condition += ';' nameSpacing = '\t' * int((40 - len(structureDetail.flagName)) / 4) featureEnabledFlags.append('const bool ' + structureDetail.flagName + nameSpacing + '=' + condition) # clear memory of each structure nameSpacing = '\t' * int((43 - len(structureDetail.instanceName)) / 4) clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx],' + nameSpacing + '0xFF * ndx, sizeof(' + structureDetail.name + '));') # construct structure chain nextInstanceName = 'DE_NULL'; if index < len(testedStructureDetail)-1: nextInstanceName = '&' + testedStructureDetail[index+1].instanceName + '[ndx]' structureChain.append('\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.sType + ';') structureChain.append('\t' + structureDetail.instanceName + '[ndx].pNext = ' + nextInstanceName + ';\n') # construct log section logStructures.append('if (' + structureDetail.flagName + ')') logStructures.append('\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;') #construct verification section verifyStructures.append('if (' + structureDetail.flagName + ' &&') for index, m in enumerate(structureDetail.members): prefix = '\t(' if index == 0 else '\t ' postfix = '))' if index == len(structureDetail.members)-1 else ' ||' verifyStructures.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix) verifyStructures.append('{\n\t\tTCU_FAIL("Mismatch between ' + structureDetail.name + '");\n}') # construct file content stream = [] stream.extend(structureDefinitions) stream.append('') stream.extend(featureEnabledFlags) stream.append('\nfor (int ndx = 0; ndx < count; ++ndx)\n{') stream.extend(clearStructures) stream.append('') stream.extend(structureChain) stream.append('\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n' '\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n' '\textFeatures.pNext = &' + testedStructureDetail[0].instanceName + '[ndx];\n' '\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);\n}\n') stream.extend(logStructures) stream.append('') stream.extend(verifyStructures) writeInlFile(filename, INL_HEADER, stream) def generateDeviceFeaturesDefs(src): # look for definitions ptrnSType = r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_FEATURES(\w*)\s*=' matches = re.findall(ptrnSType, src, re.M) matches = sorted(matches, key=lambda m: m[0]) # construct final list defs = [] for sType, sSuffix in matches: structName = re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '') ptrnStructName = r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Features' + sSuffix.replace('_', '') + ')' matchStructName = re.search(ptrnStructName, src, re.IGNORECASE) if matchStructName: # handle special cases if sType == "EXCLUSIVE_SCISSOR": sType = "SCISSOR_EXCLUSIVE" elif sType == "ASTC_DECODE": sType = "ASTC_DECODE_MODE" if sType in {'VULKAN_1_1', 'VULKAN_1_2'}: continue # skip cases that have const pNext pointer if sType == 'RASTERIZATION_ORDER_ATTACHMENT_ACCESS': continue # end handling special cases ptrnExtensionName = r'^\s*#define\s+(\w+' + sSuffix + '_' + sType + '_EXTENSION_NAME).+$' matchExtensionName = re.search(ptrnExtensionName, src, re.M) ptrnSpecVersion = r'^\s*#define\s+(\w+' + sSuffix + '_' + sType + '_SPEC_VERSION).+$' matchSpecVersion = re.search(ptrnSpecVersion, src, re.M) defs.append( (sType, '', sSuffix, matchStructName.group(1), \ matchExtensionName.group(0) if matchExtensionName else None, matchExtensionName.group(1) if matchExtensionName else None, matchSpecVersion.group(1) if matchSpecVersion else '0') ) return defs def generateDevicePropertiesDefs(src): # look for definitions ptrnSType = r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_PROPERTIES(\w*)\s*=' matches = re.findall(ptrnSType, src, re.M) matches = sorted(matches, key=lambda m: m[0]) # construct final list defs = [] for sType, sSuffix in matches: # handle special cases if sType in {'VULKAN_1_1', 'VULKAN_1_2', 'GROUP', 'MEMORY_BUDGET', 'MEMORY', 'TOOL'}: 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 sVerSuffix = '' sExtSuffix = sSuffix suffixStart = sSuffix.rfind('_') if suffixStart > 0: sVerSuffix = sSuffix[:suffixStart] sExtSuffix = sSuffix[suffixStart:] # handle special case if sType == "ID": structName = sType else: structName = re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '') ptrnStructName = r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Properties' + sSuffix.replace('_', '') + ')' matchStructName = re.search(ptrnStructName, src, re.M) if matchStructName: extType = sType if extType == "DISCARD_RECTANGLE": extType = "DISCARD_RECTANGLES" elif extType == "DRIVER": extType = "DRIVER_PROPERTIES" elif extType == "POINT_CLIPPING": extType = "MAINTENANCE_2" elif extType == "SHADER_CORE": extType = "SHADER_CORE_PROPERTIES" elif extType == "DRM": extType = "PHYSICAL_DEVICE_DRM" # end handling special cases ptrnExtensionName = r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix +'[_0-9]*_EXTENSION_NAME).+$' matchExtensionName = re.search(ptrnExtensionName, src, re.M) ptrnSpecVersion = r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix + '[_0-9]*_SPEC_VERSION).+$' matchSpecVersion = re.search(ptrnSpecVersion, src, re.M) defs.append( (sType, sVerSuffix, sExtSuffix, matchStructName.group(1), \ matchExtensionName.group(0) if matchExtensionName else None, matchExtensionName.group(1) if matchExtensionName else None, matchSpecVersion.group (1) if matchSpecVersion else '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 if structureType.isAlias: 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, extLine, extName, specVer) in enumerate(dfDefs): extensionNameDefinition = extName if not extensionNameDefinition: extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) # construct defines with names if extLine: extensionDefines.append(extLine) else: extensionDefines.append('#define {0} "not_existent_feature"'.format(extensionNameDefinition)) # handle special cases if sType == "SCISSOR_EXCLUSIVE": sType = "EXCLUSIVE_SCISSOR" elif sType == "ASTC_DECODE_MODE": sType = "ASTC_DECODE" # end handling special cases # 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, specVer, len(dfDefs)-idx)) # construct CreateFeatureStruct wrapper block featureStructWrappers.append("\t{{ createFeatureStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVer)) # construct method that will check if structure sType is part of blob blobChecker = "bool isPartOfBlobFeatures (VkStructureType sType)\n{\n" \ "\tconst std::vector sTypeVect =" \ "\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 structName = structType.name # handle special cases if structName == 'VkPhysicalDeviceShaderDrawParameterFeatures': structName = 'VkPhysicalDeviceShaderDrawParametersFeatures' # end handling special cases structDef = [s for s in dfDefs if s[3] == structName][0] sType = structDef[0] sSuffix = structDef[1] + structDef[2] # handle special cases if sType == "SCISSOR_EXCLUSIVE": sType = "EXCLUSIVE_SCISSOR" # end handling special cases sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix) blobChecker += "\t\t{0},\n".format(sTypeName) blobChecker += "\t};\n" \ "\treturn de::contains(sTypeVect.begin(), sTypeVect.end(), sType);\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 = [] # 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 alias structures if structureType.isAlias: 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 = \ "if (const void* featuresStruct = findStructureInChain(const_cast(deviceFeatures2.pNext), getStructureType<{0}>()))\n" \ "{{\n" \ " static const Feature features[] =\n" \ " {{\n" \ "{1}\n" \ " }};\n" \ " auto* supportedFeatures = reinterpret_cast(featuresStruct);\n" \ " checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures);\n" \ "}}\n" featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("DE_NULL" if coreFeaturesPattern.match(structureType.name) else "&extensionNames"))) stream = [''] stream.extend(featureItems) 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 if structureType.isAlias: 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 not member.arraySize: # 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[0], member.arraySize[1:-1]) 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, extLine, extName, specVer) in enumerate(dpDefs): extensionNameDefinition = extName if not extensionNameDefinition: extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) # construct defines with names if extLine: extensionDefines.append(extLine) else: extensionDefines.append('#define {0} "core_property"'.format(extensionNameDefinition)) # 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, specVer, len(dpDefs)-idx)) # construct CreateProperty struct wrapper block propertyStructWrappers.append("\t{{ createPropertyStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVer)) # construct method that will check if structure sType is part of blob blobChecker = "bool isPartOfBlobProperties (VkStructureType sType)\n{\n" \ "\tconst std::vector sTypeVect =" \ "\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 = [s for s in dpDefs if s[3] == structName][0] sType = structDef[0] sSuffix = structDef[1] + structDef[2] sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sSuffix) blobChecker += "\t\t{0},\n".format(sTypeName) blobChecker += "\t};\n" \ "\treturn de::contains(sTypeVect.begin(), sTypeVect.end(), sType);\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) def genericDeviceFeaturesWriter(dfDefs, pattern, filename): stream = [] for _, _, _, extStruct, _, _, _ in dfDefs: nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "") 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 = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "") if extStruct == "VkPhysicalDeviceRayTracingPropertiesNV": nameSubStr += "NV" 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 splitWithQuotation(line): result = [] splitted = re.findall(r'[^"\s]\S*|".+?"', line) for s in splitted: result.append(s.replace('"', '')) return result def writeMandatoryFeatures(filename): stream = [] pattern = r'\s*([\w]+)\s+FEATURES\s+\((.*)\)\s+REQUIREMENTS\s+\((.*)\)' mandatoryFeatures = readFile(os.path.join(VULKAN_SRC_DIR, "mandatory_features.txt")) matches = re.findall(pattern, mandatoryFeatures) dictStructs = {} dictData = [] for m in matches: allRequirements = splitWithQuotation(m[2]) dictData.append( [ m[0], m[1].strip(), allRequirements ] ) if m[0] != 'VkPhysicalDeviceFeatures' : if (m[0] not in dictStructs): dictStructs[m[0]] = [m[0][2:3].lower() + m[0][3:]] if (allRequirements[0]): if (allRequirements[0] not in dictStructs[m[0]][1:]): dictStructs[m[0]].append(allRequirements[0]) stream.extend(['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);', '', '\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;', '']) listStruct = sorted(dictStructs.items(), key=lambda tup: tup[0]) # sort to have same results for py2 and py3 for k, v in listStruct: if (v[1].startswith("ApiVersion")): cond = '\tif (context.contextSupports(vk::' + v[1] + '))' else: cond = '\tif (vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "' + v[1] + '"))' stream.extend(['\tvk::' + k + ' ' + v[0]+ ';', '\tdeMemset(&' + v[0] + ', 0, sizeof(' + v[0] + '));', '']) reqs = v[1:] if len(reqs) > 0 : cond = 'if ( ' for i, req in enumerate(reqs) : if (req.startswith("ApiVersion")): cond = cond + 'context.contextSupports(vk::' + req + ')' else: cond = cond + 'isExtensionSupported(deviceExtensions, RequiredExtension("' + req + '"))' if i+1 < len(reqs) : cond = cond + ' || ' cond = cond + ' )' stream.append('\t' + cond) stream.extend(['\t{', '\t\t' + v[0] + '.sType = getStructureType<' + k + '>();', '\t\t*nextPtr = &' + v[0] + ';', '\t\tnextPtr = &' + v[0] + '.pNext;', '\t}', '']) stream.extend(['\tcontext.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &coreFeatures);', '\tbool result = true;', '']) for v in dictData: structType = v[0]; structName = 'coreFeatures.features'; if v[0] != 'VkPhysicalDeviceFeatures' : structName = dictStructs[v[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 + 'isExtensionSupported(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].split(" ")) == 1: stream.append('\t\tif ( ' + structName + '.' + v[1] + ' == VK_FALSE )') else: condition = 'if ( ' for i, feature in enumerate(v[1].split(" ")): if i != 0: condition = condition + ' && ' condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )' condition = condition + ' )' stream.append('\t\t' + condition) featureSet = v[1].replace(" ", " or ") 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}', '']) stream.append('\treturn result;') stream.append('}\n') writeInlFile(filename, INL_HEADER, stream) def writeExtensionList(filename, patternPart): stream = [] stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(patternPart.title())) extensionsData = readFile(os.path.join(VULKAN_SRC_DIR, "extensions_data.txt")) pattern = r'\s*([^\s]+)\s+{0}\s*[0-9_]*'.format(patternPart) matches = re.findall(pattern, extensionsData) for m in matches: stream.append('\t"' + m + '",') stream.append('};\n') writeInlFile(filename, INL_HEADER, stream) def preprocessTopInclude(src, dir): pattern = r'#include\s+"([^\n]+)"' while True: inc = re.search(pattern, src) if inc is None: return src incFileName = inc.string[inc.start(1):inc.end(1)] patternIncNamed = r'#include\s+"' + incFileName + '"' incBody = readFile(os.path.join(dir, incFileName)) if incFileName != 'vk_platform.h' else '' incBodySanitized = re.sub(pattern, '', incBody) bodyEndSanitized = re.sub(patternIncNamed, '', src[inc.end(0):]) src = src[0:inc.start(0)] + incBodySanitized + bodyEndSanitized return src if __name__ == "__main__": # Script requires output path to which .inl files will be written if len(sys.argv) == 1: sys.exit("Error - output path wasn't specified in argument") outputPath = str(sys.argv[1]) if not os.path.isabs(outputPath): outputPath = os.path.abspath(outputPath) if not os.path.exists(outputPath): os.makedirs(outputPath) # Generate vulkan headers from vk.xml currentDir = os.getcwd() pythonExecutable = sys.executable or "python" os.chdir(os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "..", "xml")) targets = [ "vulkan_android.h", "vulkan_beta.h", "vulkan_core.h", "vulkan_fuchsia.h", "vulkan_ggp.h", "vulkan_ios.h", "vulkan_macos.h", "vulkan_metal.h", "vulkan_vi.h", "vulkan_wayland.h", "vulkan_win32.h", "vulkan_xcb.h", "vulkan_xlib.h", "vulkan_xlib_xrandr.h", "vulkan_ohos.h" ] for target in targets: execute([pythonExecutable, "../scripts/genvk.py", "-o", "../include/vulkan", target]) os.chdir(currentDir) # Read all .h files and make sure vulkan_core.h is first out of vulkan files targets.remove("vulkan_core.h") targets.sort() vkFilesWithCatalog = [os.path.join("vulkan", f) for f in targets] first = [os.path.join("vk_video", "vulkan_video_codecs_common.h"), os.path.join("vulkan", "vulkan_core.h")] allFilesWithCatalog = first + vkFilesWithCatalog src = "" for file in allFilesWithCatalog: src += preprocessTopInclude(readFile(os.path.join(VULKAN_HEADERS_INCLUDE_DIR,file)), VULKAN_HEADERS_INCLUDE_DIR) src = re.sub('\s*//[^\n]*', '', src) src = re.sub('\n\n', '\n', src) api = parseAPI(src) platformFuncs = [Function.TYPE_PLATFORM] instanceFuncs = [Function.TYPE_INSTANCE] deviceFuncs = [Function.TYPE_DEVICE] dfd = generateDeviceFeaturesDefs(src) 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 = generateDevicePropertiesDefs(src) 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") 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")) writeSupportedExtenions (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 ( os.path.join(outputPath, "vkMandatoryFeatures.inl")) writeExtensionList ( os.path.join(outputPath, "vkInstanceExtensions.inl"), 'INSTANCE') writeExtensionList ( os.path.join(outputPath, "vkDeviceExtensions.inl"), 'DEVICE') writeDriverIds ( os.path.join(outputPath, "vkKnownDriverIds.inl")) writeObjTypeImpl (api, os.path.join(outputPath, "vkObjTypeImpl.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