| # -*- 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 |
| import glob |
| import json |
| 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. |
| * This file was generated by /scripts/gen_framework.py |
| */\ |
| """ |
| |
| DEFINITIONS = [ |
| ("VK_MAX_PHYSICAL_DEVICE_NAME_SIZE", "size_t"), |
| ("VK_MAX_EXTENSION_NAME_SIZE", "size_t"), |
| ("VK_MAX_DRIVER_NAME_SIZE", "size_t"), |
| ("VK_MAX_DRIVER_INFO_SIZE", "size_t"), |
| ("VK_UUID_SIZE", "size_t"), |
| ("VK_LUID_SIZE", "size_t"), |
| ("VK_MAX_MEMORY_TYPES", "size_t"), |
| ("VK_MAX_MEMORY_HEAPS", "size_t"), |
| ("VK_MAX_DESCRIPTION_SIZE", "size_t"), |
| ("VK_MAX_DEVICE_GROUP_SIZE", "size_t"), |
| ("VK_ATTACHMENT_UNUSED", "uint32_t"), |
| ("VK_SUBPASS_EXTERNAL", "uint32_t"), |
| ("VK_QUEUE_FAMILY_IGNORED", "uint32_t"), |
| ("VK_QUEUE_FAMILY_EXTERNAL", "uint32_t"), |
| ("VK_REMAINING_MIP_LEVELS", "uint32_t"), |
| ("VK_REMAINING_ARRAY_LAYERS", "uint32_t"), |
| ("VK_WHOLE_SIZE", "vk::VkDeviceSize"), |
| ("VK_TRUE", "vk::VkBool32"), |
| ("VK_FALSE", "vk::VkBool32"), |
| ] |
| |
| PLATFORM_TYPES = [ |
| # VK_KHR_xlib_surface |
| (["Display","*"], ["XlibDisplayPtr"], "void*"), |
| (["Window"], ["XlibWindow"], "uintptr_t",), |
| (["VisualID"], ["XlibVisualID"], "uint32_t"), |
| |
| # VK_KHR_xcb_surface |
| (["xcb_connection_t", "*"], ["XcbConnectionPtr"], "void*"), |
| (["xcb_window_t"], ["XcbWindow"], "uintptr_t"), |
| (["xcb_visualid_t"], ["XcbVisualid"], "uint32_t"), |
| |
| # VK_KHR_wayland_surface |
| (["struct", "wl_display","*"], ["WaylandDisplayPtr"], "void*"), |
| (["struct", "wl_surface", "*"], ["WaylandSurfacePtr"], "void*"), |
| |
| # VK_KHR_mir_surface |
| (["MirConnection", "*"], ["MirConnectionPtr"], "void*"), |
| (["MirSurface", "*"], ["MirSurfacePtr"], "void*"), |
| |
| # VK_KHR_android_surface |
| (["ANativeWindow", "*"], ["AndroidNativeWindowPtr"], "void*"), |
| |
| # VK_KHR_win32_surface |
| (["HINSTANCE"], ["Win32InstanceHandle"], "void*"), |
| (["HWND"], ["Win32WindowHandle"], "void*"), |
| (["HANDLE"], ["Win32Handle"], "void*"), |
| (["const", "SECURITY_ATTRIBUTES", "*"], ["Win32SecurityAttributesPtr"], "const void*"), |
| (["AHardwareBuffer", "*"], ["AndroidHardwareBufferPtr"], "void*"), |
| (["HMONITOR"], ["Win32MonitorHandle"], "void*"), |
| (["LPCWSTR"], ["Win32LPCWSTR"], "const void*"), |
| |
| # VK_EXT_acquire_xlib_display |
| (["RROutput"], ["RROutput"], "void*"), |
| |
| (["zx_handle_t"], ["zx_handle_t"], "uint32_t"), |
| (["GgpFrameToken"], ["GgpFrameToken"], "int32_t"), |
| (["GgpStreamDescriptor"], ["GgpStreamDescriptor"], "int32_t"), |
| (["CAMetalLayer"], ["CAMetalLayer"], "void*"), |
| ] |
| |
| 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"] |
| EXTENSION_POSTFIXES_STANDARD = ["KHR", "EXT"] |
| |
| def prefixName (prefix, name): |
| name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name[2:]) |
| name = re.sub(r'([a-zA-Z])([0-9])', r'\1_\2', name) |
| name = name.upper() |
| |
| 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("VULKAN_13_FEATURES", "VULKAN_1_3_FEATURES") |
| name = name.replace("VULKAN_13_PROPERTIES", "VULKAN_1_3_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, additionalExtensionData): |
| 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 |
| self.additionalExtensionData = additionalExtensionData # \note contains mandatory features and information about promotion |
| |
| 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, additionalExtensionData): |
| |
| # note registeredExtensionDict is also executed for vulkan 1.0 source for which extension name is None |
| registeredExtensionDict = {None: None} |
| for extensionName, data in additionalExtensionData: |
| # make sure that this extension was registered |
| if 'register_extension' not in data.keys(): |
| continue |
| # save array containing 'device' or 'instance' string followed by the optional vulkan version in which this extension is core; |
| # note that register_extension section is also required for partialy promoted extensions like VK_EXT_extended_dynamic_state2 |
| # but those extensions should not fill 'core' tag |
| registeredExtensionDict[extensionName] = [ data['register_extension']['type'] ] |
| match = re.match("(\d).(\d).(\d)", data['register_extension']['core']) |
| if match != None: |
| registeredExtensionDict[extensionName].extend( [ int(match.group(1)), int(match.group(2)), int(match.group(3)) ] ) |
| |
| 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 = parse32bitBitfieldNames(extensionSrc) |
| typedefs = parseTypedefs(extensionSrc) |
| enumBitfieldNames = [getBitEnumNameForBitfield(name) for name in bitfieldNames] |
| enums = [enum for enum in rawEnums if enum.name not in enumBitfieldNames] |
| |
| extCoreVersion = None |
| extData = registeredExtensionDict.get(extensionName, None) |
| 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 extData != None: |
| populateExtensionAliases(functionsByName, extFunctions) |
| populateExtensionAliases(handlesByName, extHandles) |
| populateExtensionAliases(enumsByName, extEnums) |
| populateExtensionAliases(bitfieldsByName, extBitfields) |
| populateExtensionAliases(compositeTypesByName, extCompositeTypes) |
| if len(extData) > 1: |
| extCoreVersion = extData |
| |
| extensions.append(Extension(extensionName, extHandles, extEnums, extBitfields, extCompositeTypes, extFunctions, extDefinitions, additionalDefinitions, typedefs, extCoreVersion)) |
| return extensions |
| |
| def parse32bitBitfieldNames (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 = parse32bitBitfieldNames(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) |
| additionalExtensionData = {} |
| |
| # read all files from extensions directory |
| for fileName in glob.glob(os.path.join(VULKAN_SRC_DIR, "extensions", "*.json")): |
| extensionName = os.path.basename(fileName)[:-5] |
| fileContent = readFile(fileName) |
| try: |
| additionalExtensionData[extensionName] = json.loads(fileContent) |
| except ValueError as err: |
| print("Error in %s: %s" % (os.path.basename(fileName), str(err))) |
| sys.exit(-1) |
| additionalExtensionData = sorted(additionalExtensionData.items(), key=lambda e: e[0]) |
| |
| 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, additionalExtensionData) |
| |
| # Populate alias fields |
| populateAliasesWithTypedefs(compositeTypes, src) |
| populateAliasesWithTypedefs(enums, src) |
| populateAliasesWithTypedefs(bitfields, src) |
| populateAliasesWithTypedefs(bitfields64, src) |
| populateAliasesWithTypedefs(handles, src) |
| |
| for enum in enums: |
| removeAliasedValues(enum) |
| |
| # Make generator to create Deleter<VkAccelerationStructureNV> |
| 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, |
| additionalExtensionData = additionalExtensionData) |
| |
| 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 |
| maxIntCount = 0 |
| for name, value in enum.values: |
| if value[:2] != "VK": |
| intValue = parseInt(value) |
| if intValue != curIndex: |
| # enum is linear when all items are in order |
| if intValue != 0x7FFFFFFF: |
| return False |
| # count number of items with 0x7FFFFFFF value; |
| # enum containing single 0x7FFFFFFF item are also |
| # considered as linear (this is usualy *_MAX_ENUM item) |
| maxIntCount += 1 |
| # enums containing more then one 0x7FFFFFFF value |
| # are not considered as linear (vulkan video enums) |
| if maxIntCount > 1: |
| 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 bitfield in api.bitfields64: |
| if not bitfield.isAlias: |
| for line in genBitfield64Src(bitfield): |
| yield line |
| else: |
| for bitfield2 in api.bitfields64: |
| if bitfield2.alias == bitfield: |
| yield "typedef %s %s;" % (bitfield2.name, bitfield.name) |
| yield "" |
| |
| 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{" |
| enumValues = [] |
| lastValue = 0x7FFFFFFF |
| for n, v in enum.values: |
| if (v[:2] != "VK") and (v != lastValue): |
| enumValues.append(f"\t\tcase {n}:\treturn \"{n}\";") |
| lastValue = v |
| enumValues.append("\t\tdefault:\treturn DE_NULL;") |
| for line in indentLines(enumValues): |
| 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<typename T> VkObjectType getObjectType (void);" |
| |
| for line in indentLines(["template<> inline VkObjectType\tgetObjectType<%s>\t(void) { return %s;\t}" % (handle.name, prefixName("VK_OBJECT_TYPE_", handle.name)) for handle in api.handles 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<const char*>&%s)" % (" dst" if len(deviceMap) != 0 else ""), |
| "{"] + writeExtensionsForVersions(deviceMap) + [ |
| "}", |
| "", |
| "void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%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<const char*>& functions)\n{' |
| dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"] |
| elif functionType == Function.TYPE_DEVICE: |
| yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{' |
| dg_list = ["vkGetDeviceGroupPresentCapabilitiesKHR", "vkGetDeviceGroupSurfacePresentModesKHR", "vkAcquireNextImage2KHR"] |
| for ext in api.extensions: |
| funcNames = [] |
| 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<const char*, FunctionOrigin> FunctionInfo;", |
| "typedef ::std::vector<FunctionInfo> FunctionInfosList;", |
| "typedef ::std::map<uint32_t, FunctionInfosList> ApisMap;", |
| "", |
| "void initApisMap (ApisMap& apis)", |
| "{", |
| " apis.clear();"] + [ |
| " apis.insert(::std::pair<uint32_t, FunctionInfosList>(" + 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 camelToSnake(name): |
| name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) |
| return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower() |
| |
| def writeDeviceFeatures2(api, filename): |
| # 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 = [ |
| 'VkPhysicalDevice4444FormatsFeaturesEXT', |
| 'VkPhysicalDevice8BitStorageFeatures', |
| 'VkPhysicalDevice16BitStorageFeatures', |
| 'VkPhysicalDeviceAccelerationStructureFeaturesKHR', |
| 'VkPhysicalDeviceASTCDecodeFeaturesEXT', |
| 'VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT', |
| 'VkPhysicalDeviceBufferDeviceAddressFeaturesEXT', |
| 'VkPhysicalDeviceBufferDeviceAddressFeatures', |
| 'VkPhysicalDeviceConditionalRenderingFeaturesEXT', |
| 'VkPhysicalDeviceCustomBorderColorFeaturesEXT', |
| 'VkPhysicalDeviceColorWriteEnableFeaturesEXT', |
| 'VkPhysicalDeviceDescriptorIndexingFeatures', |
| 'VkPhysicalDeviceDepthClipEnableFeaturesEXT', |
| 'VkPhysicalDeviceDynamicRenderingFeatures', |
| 'VkPhysicalDeviceExtendedDynamicStateFeaturesEXT', |
| 'VkPhysicalDeviceExtendedDynamicState2FeaturesEXT', |
| 'VkPhysicalDeviceFragmentDensityMapFeaturesEXT', |
| 'VkPhysicalDeviceFragmentDensityMap2FeaturesEXT', |
| 'VkPhysicalDeviceFragmentShadingRateFeaturesKHR', |
| 'VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR', |
| 'VkPhysicalDeviceInlineUniformBlockFeatures', |
| 'VkPhysicalDeviceIndexTypeUint8FeaturesEXT', |
| 'VkPhysicalDeviceImagelessFramebufferFeatures', |
| 'VkPhysicalDeviceImageRobustnessFeatures', |
| 'VkPhysicalDeviceHostQueryResetFeatures', |
| 'VkPhysicalDeviceLineRasterizationFeaturesEXT', |
| 'VkPhysicalDeviceMaintenance4Features', |
| 'VkPhysicalDeviceMultiviewFeatures', |
| 'VkPhysicalDeviceMultiDrawFeaturesEXT', |
| 'VkPhysicalDeviceMemoryPriorityFeaturesEXT', |
| 'VkPhysicalDeviceDeviceMemoryReportFeaturesEXT', |
| 'VkPhysicalDevicePerformanceQueryFeaturesKHR', |
| 'VkPhysicalDevicePipelineCreationCacheControlFeatures', |
| 'VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR', |
| 'VkPhysicalDevicePresentIdFeaturesKHR', |
| 'VkPhysicalDevicePresentWaitFeaturesKHR', |
| 'VkPhysicalDeviceProtectedMemoryFeatures', |
| 'VkPhysicalDeviceProvokingVertexFeaturesEXT', |
| 'VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT', |
| 'VkPhysicalDevicePrivateDataFeatures', |
| 'VkPhysicalDeviceRayTracingPipelineFeaturesKHR', |
| 'VkPhysicalDeviceRayQueryFeaturesKHR', |
| 'VkPhysicalDeviceRobustness2FeaturesEXT', |
| 'VkPhysicalDeviceSamplerYcbcrConversionFeatures', |
| 'VkPhysicalDeviceScalarBlockLayoutFeatures', |
| 'VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures', |
| 'VkPhysicalDeviceShaderAtomicInt64Features', |
| 'VkPhysicalDeviceShaderAtomicFloatFeaturesEXT', |
| 'VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT', |
| 'VkPhysicalDeviceShaderFloat16Int8Features', |
| 'VkPhysicalDeviceShaderClockFeaturesKHR', |
| 'VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures', |
| 'VkPhysicalDeviceShaderDrawParametersFeatures', |
| 'VkPhysicalDeviceShaderIntegerDotProductFeatures', |
| 'VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures', |
| 'VkPhysicalDeviceShaderTerminateInvocationFeatures', |
| 'VkPhysicalDeviceSubgroupSizeControlFeatures', |
| 'VkPhysicalDeviceSynchronization2Features', |
| 'VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT', |
| 'VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT', |
| 'VkPhysicalDeviceTextureCompressionASTCHDRFeatures', |
| 'VkPhysicalDeviceTimelineSemaphoreFeatures', |
| 'VkPhysicalDeviceTransformFeedbackFeaturesEXT', |
| 'VkPhysicalDeviceUniformBufferStandardLayoutFeatures', |
| 'VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR', |
| 'VkPhysicalDeviceVariablePointersFeatures', |
| 'VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT', |
| 'VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT', |
| 'VkPhysicalDeviceVulkanMemoryModelFeaturesKHR', |
| 'VkPhysicalDeviceYcbcrImageArraysFeaturesEXT', |
| 'VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT', |
| 'VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures', |
| ] |
| |
| # 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 |
| specialCaseDict = { |
| 'FragmentDensityMap2' : ['FRAGMENT', 'DENSITY', 'MAP', '2'], |
| 'Ycbcr2Plane444Formats' : ['YCBCR', '2', 'PLANE', '444', 'FORMATS'], |
| 'ASTCDecode' : ['ASTC', 'DECODE'], |
| '4444Formats' : ['4444', 'FORMATS'], |
| 'TextureCompressionASTCHDR' : ['TEXTURE', 'COMPRESSION', 'ASTC', 'HDR'], |
| 'Synchronization2' : ['SYNCHRONIZATION', '2'], |
| 'ShaderAtomicFloat2' : ['SHADER', 'ATOMIC', 'FLOAT', '2'], |
| 'Robustness2' : ['ROBUSTNESS', '2'], |
| 'Maintenance4' : ['MAINTENANCE', '4'], |
| 'ExtendedDynamicState2' : ['EXTENDED', 'DYNAMIC', 'STATE', '2'], |
| } |
| nameSplitUp = specialCaseDict.get(nameResult.group(1)) |
| if nameSplitUp == None: |
| 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' |
| 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 += ' || ' |
| else: |
| condition += ' ' |
| condition += 'context.contextSupports(vk::ApiVersion(' + str(major) + ', ' + str(structureDetail.minor) + ', 0))' |
| if condition == '': |
| condition = 'true' |
| condition += ';' |
| nameSpacing = '\t' * int((len(structureDetail.name) - 4) / 4) |
| featureEnabledFlags.append('const bool' + nameSpacing + structureDetail.flagName + ' =' + condition) |
| # clear memory of each structure |
| clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx], 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\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.flagName + ' ? ' + structureDetail.sType + ' : VK_STRUCTURE_TYPE_MAX_ENUM;', |
| '\t\t' + structureDetail.instanceName + '[ndx].pNext = DE_NULL;']) |
| # construct log section |
| logStructures.append([ |
| '\tif (' + structureDetail.flagName + ')', |
| '\t\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;' |
| ]) |
| #construct verification section |
| verifyStructure = [] |
| verifyStructure.append('\tif (' + structureDetail.flagName + ' &&') |
| for index, m in enumerate(structureDetail.members): |
| prefix = '\t\t(' if index == 0 else '\t\t ' |
| postfix = '))' if index == len(structureDetail.members)-1 else ' ||' |
| verifyStructure.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix) |
| if len(structureDetail.members) == 0: |
| verifyStructure.append('\t\tfalse)') |
| verifyStructure.append('\t{\n\t\tTCU_FAIL("Mismatch between ' + structureDetail.name + '");\n\t}') |
| verifyStructures.append(verifyStructure) |
| |
| # construct file content |
| stream = [] |
| |
| # individual test functions |
| for n, x in enumerate(testedStructureDetail): |
| stream.append("tcu::TestStatus testPhysicalDeviceFeature" + x.instanceName[len('device'):]+" (Context& context)") |
| stream.append("""{ |
| const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); |
| const CustomInstance instance (createCustomInstanceWithExtension(context, "VK_KHR_get_physical_device_properties2")); |
| const InstanceDriver& vki (instance.getDriver()); |
| const int count = 2u; |
| TestLog& log = context.getTestContext().getLog(); |
| VkPhysicalDeviceFeatures2 extFeatures; |
| vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL); |
| """) |
| stream.append("\t"+structureDefinitions[n]) |
| stream.append("\t"+featureEnabledFlags[n]) |
| stream.append('') |
| stream.append('\tfor (int ndx = 0; ndx < count; ++ndx)\n\t{') |
| stream.append("\t" + clearStructures[n]) |
| stream.extend(structureChain[n]) |
| stream.append('') |
| stream.append( |
| '\t\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n' |
| '\t\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n' |
| '\t\textFeatures.pNext = &' + testedStructureDetail[n].instanceName + '[ndx];\n\n' |
| '\t\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);') |
| stream.append('\t}\n') |
| stream.extend(logStructures[n]) |
| stream.append('') |
| stream.extend(verifyStructures[n]) |
| stream.append('\treturn tcu::TestStatus::pass("Querying succeeded");') |
| stream.append("}\n") |
| |
| # function to create tests |
| stream.append(""" |
| void addSeparateFeatureTests (tcu::TestCaseGroup* testGroup) |
| { |
| """) |
| for x in testedStructureDetail: |
| stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x.instanceName[len('device'):]) + '", "' + x.name + '", testPhysicalDeviceFeature' + x.instanceName[len('device'):] + ');') |
| stream.append('}\n') |
| |
| # write out |
| 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" |
| elif sType == "MAINTENANCE_4": |
| sType = "MAINTENANCE4" |
| elif sType == "YCBCR_2_PLANE_444_FORMATS": |
| sType = "YCBCR_2PLANE_444_FORMATS" |
| elif sType in {'VULKAN_1_1', 'VULKAN_1_2', 'VULKAN_1_3'}: |
| continue |
| elif sType == 'RASTERIZATION_ORDER_ATTACHMENT_ACCESS': |
| # skip case that has const pNext pointer |
| continue |
| # skip cases that have const pNext pointer |
| if sType == 'RASTERIZATION_ORDER_ATTACHMENT_ACCESS': |
| 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', 'VULKAN_1_3', '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" |
| elif sType == "MAINTENANCE4": |
| sType = "MAINTENANCE_4" |
| elif sType == "YCBCR_2PLANE_444_FORMATS": |
| sType = "YCBCR_2_PLANE_444_FORMATS" |
| # 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 function that will check for which vk version structure sType is part of blob |
| blobChecker = "deUint32 getBlobFeaturesVersion (VkStructureType sType)\n{\n" \ |
| "\tconst std::map<VkStructureType, deUint32> sTypeBlobMap\n" \ |
| "\t{\n" |
| # iterate over blobs with list of structures |
| for blobName in sorted(blobStructs.keys()): |
| blobChecker += "\t\t// Vulkan{0}\n".format(blobName) |
| # iterate over all feature structures in current blob |
| structuresList = list(blobStructs[blobName]) |
| structuresList = sorted(structuresList, key=lambda s: s.name) |
| for structType in structuresList: |
| # find definition of this structure in dfDefs |
| 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" |
| elif sType == "MAINTENANCE4": |
| sType = "MAINTENANCE_4" |
| # end handling special cases |
| sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix) |
| tabs = "\t" * int((88 - len(sTypeName)) / 4) |
| blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) |
| blobChecker += "\t};\n\n" \ |
| "\tauto it = sTypeBlobMap.find(sType);\n" \ |
| "\tif(it == sTypeBlobMap.end())\n" \ |
| "\t\treturn 0;\n" \ |
| "\treturn it->second;\n" \ |
| "}\n" |
| # combine all definition lists |
| stream = [ |
| '#include "vkDeviceFeatures.hpp"\n', |
| 'namespace vk\n{'] |
| stream.extend(extensionDefines) |
| stream.append('\n') |
| stream.extend(initFromBlobDefinitions) |
| stream.append('\n// generic template is not enough for some compilers') |
| stream.extend(emptyInitDefinitions) |
| stream.append('\n') |
| stream.extend(makeFeatureDescDefinitions) |
| stream.append('\n') |
| stream.append('static const FeatureStructCreationData featureStructCreationArray[]\n{') |
| stream.extend(featureStructWrappers) |
| stream.append('};\n') |
| stream.append(blobChecker) |
| stream.append('} // vk\n') |
| writeInlFile(filename, INL_HEADER, stream) |
| |
| def writeDeviceFeatureTest(api, filename): |
| |
| coreFeaturesPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") |
| featureItems = [] |
| testFunctions = [] |
| # iterate over all feature structures |
| allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*") |
| for structureType in api.compositeTypes: |
| # skip structures that are not feature structures |
| if not allFeaturesPattern.match(structureType.name): |
| continue |
| # skip 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 = """ |
| tcu::TestStatus createDeviceWithUnsupportedFeaturesTest{4} (Context& context) |
| {{ |
| const PlatformInterface& vkp = context.getPlatformInterface(); |
| tcu::TestLog& log = context.getTestContext().getLog(); |
| tcu::ResultCollector resultCollector (log); |
| const CustomInstance instance (createCustomInstanceWithExtensions(context, context.getInstanceExtensions(), DE_NULL, true)); |
| const InstanceDriver& instanceDriver (instance.getDriver()); |
| const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); |
| const deUint32 queueFamilyIndex = 0; |
| const deUint32 queueCount = 1; |
| const float queuePriority = 1.0f; |
| const DeviceFeatures deviceFeaturesAll (context.getInstanceInterface(), context.getUsedApiVersion(), physicalDevice, context.getInstanceExtensions(), context.getDeviceExtensions(), DE_TRUE); |
| const VkPhysicalDeviceFeatures2 deviceFeatures2 = deviceFeaturesAll.getCoreFeatures2(); |
| int numErrors = 0; |
| |
| VkPhysicalDeviceFeatures emptyDeviceFeatures; |
| deMemset(&emptyDeviceFeatures, 0, sizeof(emptyDeviceFeatures)); |
| |
| // Only non-core extensions will be used when creating the device. |
| vector<const char*> coreExtensions; |
| getCoreDeviceExtensions(context.getUsedApiVersion(), coreExtensions); |
| vector<string> nonCoreExtensions(removeExtensions(context.getDeviceExtensions(), coreExtensions)); |
| |
| vector<const char*> extensionNames; |
| extensionNames.reserve(nonCoreExtensions.size()); |
| for (const string& extension : nonCoreExtensions) |
| extensionNames.push_back(extension.c_str()); |
| |
| if (const void* featuresStruct = findStructureInChain(const_cast<const void*>(deviceFeatures2.pNext), getStructureType<{0}>())) |
| {{ |
| static const Feature features[] = |
| {{ |
| {1} |
| }}; |
| auto* supportedFeatures = reinterpret_cast<const {0}*>(featuresStruct); |
| checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures); |
| }} |
| |
| if (numErrors > 0) |
| return tcu::TestStatus(resultCollector.getResult(), "Enabling unsupported features didn't return VK_ERROR_FEATURE_NOT_PRESENT."); |
| else |
| return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage()); |
| }} |
| """ |
| featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("DE_NULL" if coreFeaturesPattern.match(structureType.name) else "&extensionNames"), structureType.name[len('VkPhysicalDevice'):])) |
| |
| testFunctions.append("createDeviceWithUnsupportedFeaturesTest" + structureType.name[len('VkPhysicalDevice'):]) |
| |
| stream = [''] |
| stream.extend(featureItems) |
| stream.append(""" |
| void addSeparateUnsupportedFeatureTests (tcu::TestCaseGroup* testGroup) |
| { |
| """) |
| for x in testFunctions: |
| stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x[len('createDeviceWithUnsupportedFeaturesTest'):]) + '", "' + x + '", ' + x + ');') |
| stream.append('}\n') |
| |
| writeInlFile(filename, INL_HEADER, stream) |
| |
| def writeDeviceProperties(api, dpDefs, filename): |
| # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs |
| # and construct dictionary with all of their attributes |
| blobMembers = {} |
| blobStructs = {} |
| blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Properties[0-9]*$") |
| for structureType in api.compositeTypes: |
| match = blobPattern.match(structureType.name) |
| if match: |
| allMembers = [member.name for member in structureType.members] |
| vkVersion = match.group(1) |
| blobMembers[vkVersion] = allMembers[2:] |
| blobStructs[vkVersion] = set() |
| initFromBlobDefinitions = [] |
| emptyInitDefinitions = [] |
| # iterate over all property structures |
| allPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*") |
| nonExtPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*$") |
| for structureType in api.compositeTypes: |
| # skip structures that are not property structures |
| if not allPropertiesPattern.match(structureType.name): |
| continue |
| # skip structures that were previously identified as blobs |
| if blobPattern.match(structureType.name): |
| continue |
| 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 = "deUint32 getBlobPropertiesVersion (VkStructureType sType)\n{\n" \ |
| "\tconst std::map<VkStructureType, deUint32> sTypeBlobMap\n" \ |
| "\t{\n" |
| # iterate over blobs with list of structures |
| for blobName in sorted(blobStructs.keys()): |
| blobChecker += "\t\t// Vulkan{0}\n".format(blobName) |
| # iterate over all feature structures in current blob |
| structuresList = list(blobStructs[blobName]) |
| structuresList = sorted(structuresList, key=lambda s: s.name) |
| for structType in structuresList: |
| # find definition of this structure in dpDefs |
| structName = structType.name |
| structDef = [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) |
| tabs = "\t" * int((76 - len(sTypeName)) / 4) |
| blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) |
| blobChecker += "\t};\n\n" \ |
| "\tauto it = sTypeBlobMap.find(sType);\n" \ |
| "\tif(it == sTypeBlobMap.end())\n" \ |
| "\t\treturn 0;\n" \ |
| "\treturn it->second;\n" \ |
| "}\n" |
| # combine all definition lists |
| stream = [ |
| '#include "vkDeviceProperties.hpp"\n', |
| 'namespace vk\n{'] |
| stream.extend(extensionDefines) |
| stream.append('\n') |
| stream.extend(initFromBlobDefinitions) |
| stream.append('\n// generic template is not enough for some compilers') |
| stream.extend(emptyInitDefinitions) |
| stream.append('\n') |
| stream.extend(makePropertyDescDefinitions) |
| stream.append('\n') |
| stream.append('static const PropertyStructCreationData propertyStructCreationArray[] =\n{') |
| stream.extend(propertyStructWrappers) |
| stream.append('};\n') |
| stream.append(blobChecker) |
| stream.append('} // vk\n') |
| writeInlFile(filename, INL_HEADER, stream) |
| |
| 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 writeMandatoryFeatures(api, filename): |
| stream = [] |
| |
| dictStructs = {} |
| dictData = [] |
| for _, data in api.additionalExtensionData: |
| if 'mandatory_features' not in data.keys(): |
| continue |
| # sort to have same results for py2 and py3 |
| listStructFeatures = sorted(data['mandatory_features'].items(), key=lambda tup: tup[0]) |
| for structure, featuresList in listStructFeatures: |
| for featureData in featuresList: |
| assert('features' in featureData.keys()) |
| assert('requirements' in featureData.keys()) |
| requirements = featureData['requirements'] |
| dictData.append( [ structure, featureData['features'], requirements ]) |
| if structure == 'VkPhysicalDeviceFeatures': |
| continue |
| # if structure is not in dict construct name of variable and add is as a first item |
| if (structure not in dictStructs): |
| dictStructs[structure] = [structure[2:3].lower() + structure[3:]] |
| # add first requirement if it is unique |
| if requirements and (requirements[0] not in dictStructs[structure]): |
| dictStructs[structure].append(requirements[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<VkExtensionProperties>\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]) == 1: |
| stream.append('\t\tif ( ' + structName + '.' + v[1][0] + ' == VK_FALSE )') |
| else: |
| condition = 'if ( ' |
| for i, feature in enumerate(v[1]): |
| if i != 0: |
| condition = condition + ' && ' |
| condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )' |
| condition = condition + ' )' |
| stream.append('\t\t' + condition) |
| featureSet = " or ".join(v[1]) |
| stream.extend(['\t\t{', |
| '\t\t\tlog << tcu::TestLog::Message << "Mandatory feature ' + featureSet + ' not supported" << tcu::TestLog::EndMessage;', |
| '\t\t\tresult = false;', |
| '\t\t}', |
| '\t}', |
| '']) |
| stream.append('\treturn result;') |
| stream.append('}\n') |
| writeInlFile(filename, INL_HEADER, stream) |
| |
| def writeExtensionList(api, filename, extensionType): |
| extensionList = [] |
| for extensionName, data in api.additionalExtensionData: |
| # make sure extension name starts with VK_KHR |
| if not extensionName.startswith('VK_KHR'): |
| continue |
| # make sure that this extension was registered |
| if 'register_extension' not in data.keys(): |
| continue |
| # make sure extension has proper type |
| if extensionType == data['register_extension']['type']: |
| extensionList.append(extensionName) |
| extensionList.sort() |
| # write list of all found extensions |
| stream = [] |
| stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(extensionType.title())) |
| for n in extensionList: |
| stream.append('\t"' + n + '",') |
| stream.append('};\n') |
| writeInlFile(filename, INL_HEADER, stream) |
| |
| def 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__": |
| |
| outputPath = os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan") |
| # if argument was specified it is interpreted as a path to which .inl files will be written |
| if len(sys.argv) > 1: |
| outputPath = str(sys.argv[1]) |
| |
| # Generate vulkan headers from vk.xml |
| currentDir = os.getcwd() |
| pythonExecutable = sys.executable or "python" |
| os.chdir(os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "..", "xml")) |
| vkTargets = [ |
| "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", |
| ] |
| for target in vkTargets: |
| execute([pythonExecutable, "../scripts/genvk.py", "-o", "../include/vulkan", target]) |
| |
| videoDir = "../include/vk_video" |
| if (not os.path.isdir(videoDir)): |
| os.mkdir(videoDir) |
| |
| videoTargets = [ |
| 'vulkan_video_codecs_common.h', |
| 'vulkan_video_codec_h264std.h', |
| 'vulkan_video_codec_h264std_decode.h', |
| 'vulkan_video_codec_h264std_encode.h', |
| 'vulkan_video_codec_h265std.h', |
| 'vulkan_video_codec_h265std_decode.h', |
| 'vulkan_video_codec_h265std_encode.h', |
| ] |
| for target in videoTargets: |
| execute([pythonExecutable, "../scripts/genvk.py", "-registry", "video.xml", "-o", videoDir, target]) |
| |
| os.chdir(currentDir) |
| |
| # Read all .h files and make sure vulkan_core.h is first out of vulkan files |
| vkTargets.remove("vulkan_core.h") |
| vkTargets.sort() |
| vkTargets.insert(0, "vulkan_core.h") |
| vkFilesWithCatalog = [os.path.join("vulkan", f) for f in vkTargets] |
| |
| src = "" |
| for file in vkFilesWithCatalog: |
| 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 (api, os.path.join(outputPath, "vkMandatoryFeatures.inl")) |
| writeExtensionList (api, os.path.join(outputPath, "vkInstanceExtensions.inl"), 'instance') |
| writeExtensionList (api, os.path.join(outputPath, "vkDeviceExtensions.inl"), 'device') |
| writeDriverIds ( 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 |