1# -*- coding: utf-8 -*- 2 3#------------------------------------------------------------------------- 4# Vulkan CTS 5# ---------- 6# 7# Copyright (c) 2015 Google Inc. 8# 9# Licensed under the Apache License, Version 2.0 (the "License"); 10# you may not use this file except in compliance with the License. 11# You may obtain a copy of the License at 12# 13# http://www.apache.org/licenses/LICENSE-2.0 14# 15# Unless required by applicable law or agreed to in writing, software 16# distributed under the License is distributed on an "AS IS" BASIS, 17# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18# See the License for the specific language governing permissions and 19# limitations under the License. 20# 21#------------------------------------------------------------------------- 22 23import os 24import re 25import sys 26import glob 27import json 28import argparse 29import datetime 30import collections 31import ast 32import logging 33from lxml import etree 34 35scriptPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts") 36sys.path.insert(0, scriptPath) 37 38from ctsbuild.common import * 39from khr_util.format import indentLines, writeInlFile 40 41VULKAN_XML_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "xml") 42SCRIPTS_SRC_DIR = os.path.join(os.path.dirname(__file__), "src") 43DEFAULT_OUTPUT_DIR = { "" : os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkan"), 44 "SC" : os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkansc") } 45 46EXTENSIONS_TO_READ_FROM_XML_NOT_JSON = """ 47VK_KHR_video_encode_av1 48VK_KHR_video_encode_quantization_map 49""".split() 50 51EXTENSIONS_TO_READ_FROM_XML_NOT_JSON = [s for s in EXTENSIONS_TO_READ_FROM_XML_NOT_JSON if not s.startswith('#')] 52 53INL_HEADER = """\ 54/* WARNING: This is auto-generated file. Do not modify, since changes will 55 * be lost! Modify the generating script instead. 56 * This file was generated by /scripts/gen_framework.py 57 */\ 58 59""" 60 61DEFINITIONS = { 62 "VK_MAX_PHYSICAL_DEVICE_NAME_SIZE": "size_t", 63 "VK_MAX_EXTENSION_NAME_SIZE": "size_t", 64 "VK_MAX_DRIVER_NAME_SIZE": "size_t", 65 "VK_MAX_DRIVER_INFO_SIZE": "size_t", 66 "VK_UUID_SIZE": "size_t", 67 "VK_LUID_SIZE": "size_t", 68 "VK_MAX_MEMORY_TYPES": "size_t", 69 "VK_MAX_MEMORY_HEAPS": "size_t", 70 "VK_MAX_DESCRIPTION_SIZE": "size_t", 71 "VK_MAX_DEVICE_GROUP_SIZE": "size_t", 72 "VK_ATTACHMENT_UNUSED": "uint32_t", 73 "VK_SUBPASS_EXTERNAL": "uint32_t", 74 "VK_QUEUE_FAMILY_IGNORED": "uint32_t", 75 "VK_QUEUE_FAMILY_EXTERNAL": "uint32_t", 76 "VK_REMAINING_MIP_LEVELS": "uint32_t", 77 "VK_REMAINING_ARRAY_LAYERS": "uint32_t", 78 "VK_WHOLE_SIZE": "vk::VkDeviceSize", 79 "VK_TRUE": "vk::VkBool32", 80 "VK_FALSE": "vk::VkBool32", 81} 82 83PLATFORM_TYPES = [ 84 # VK_KHR_xlib_surface 85 (["Display","*"], ["XlibDisplayPtr"], "void*"), 86 (["Window"], ["XlibWindow"], "uintptr_t",), 87 (["VisualID"], ["XlibVisualID"], "uint32_t"), 88 89 # VK_KHR_xcb_surface 90 (["xcb_connection_t", "*"], ["XcbConnectionPtr"], "void*"), 91 (["xcb_window_t"], ["XcbWindow"], "uintptr_t"), 92 (["xcb_visualid_t"], ["XcbVisualid"], "uint32_t"), 93 94 # VK_KHR_wayland_surface 95 (["struct", "wl_display","*"], ["WaylandDisplayPtr"], "void*"), 96 (["struct", "wl_surface", "*"], ["WaylandSurfacePtr"], "void*"), 97 98 # VK_KHR_mir_surface 99 (["MirConnection", "*"], ["MirConnectionPtr"], "void*"), 100 (["MirSurface", "*"], ["MirSurfacePtr"], "void*"), 101 102 # VK_KHR_android_surface 103 (["ANativeWindow", "*"], ["AndroidNativeWindowPtr"], "void*"), 104 105 # VK_KHR_win32_surface 106 (["HINSTANCE"], ["Win32InstanceHandle"], "void*"), 107 (["HWND"], ["Win32WindowHandle"], "void*"), 108 (["HANDLE"], ["Win32Handle"], "void*"), 109 (["const", "SECURITY_ATTRIBUTES", "*"], ["Win32SecurityAttributesPtr"], "const void*"), 110 (["AHardwareBuffer", "*"], ["AndroidHardwareBufferPtr"], "void*"), 111 (["HMONITOR"], ["Win32MonitorHandle"], "void*"), 112 (["LPCWSTR"], ["Win32LPCWSTR"], "const void*"), 113 114 # VK_EXT_acquire_xlib_display 115 (["RROutput"], ["RROutput"], "void*"), 116 117 (["zx_handle_t"], ["zx_handle_t"], "uint32_t"), 118 (["GgpFrameToken"], ["GgpFrameToken"], "int32_t"), 119 (["GgpStreamDescriptor"], ["GgpStreamDescriptor"], "int32_t"), 120 (["CAMetalLayer"], ["CAMetalLayer"], "void*"), 121 (["struct", "_screen_context", "*"], ["QNXScreenContextPtr"], "void*"), 122 (["struct", "_screen_window", "*"], ["QNXScreenWindowPtr"], "void*"), 123 124 # VK_EXT_metal_objects 125 (["MTLDevice_id"], ["MTLDevice_id"], "void*"), 126 (["MTLCommandQueue_id"], ["MTLCommandQueue_id"], "void*"), 127 (["MTLBuffer_id"], ["MTLBuffer_id"], "void*"), 128 (["MTLTexture_id"], ["MTLTexture_id"], "void*"), 129 (["IOSurfaceRef"], ["IOSurfaceRef"], "void*"), 130 (["MTLSharedEvent_id"], ["MTLSharedEvent_id"], "void*"), 131 132 # VK_NV_external_sci_sync 133 (["NvSciBufObj"], ["NvSciBufObj"], "int"), 134 (["NvSciSyncObj"], ["NvSciSyncObj"], "int"), 135 (["NvSciSyncFence"], ["NvSciSyncFence"], "int"), 136 (["NvSciBufAttrList"], ["NvSciBufAttrList"], "int"), 137 (["NvSciSyncAttrList"], ["NvSciSyncAttrList"], "int"), 138] 139 140PLATFORM_TYPE_NAMESPACE = "pt" 141 142TYPE_SUBSTITUTIONS = [ 143 # Platform-specific 144 ("DWORD", "uint32_t"), 145 ("HANDLE*", PLATFORM_TYPE_NAMESPACE + "::" + "Win32Handle*"), 146] 147 148EXTENSION_POSTFIXES_STANDARD = ["KHR", "EXT"] 149EXTENSION_POSTFIXES_VENDOR = ["AMD", "ARM", "NV", 'INTEL', "NVX", "KHX", "NN", "MVK", "FUCHSIA", 'QCOM', "GGP", "QNX", "ANDROID", 'VALVE', 'HUAWEI'] 150EXTENSION_POSTFIXES = EXTENSION_POSTFIXES_STANDARD + EXTENSION_POSTFIXES_VENDOR 151 152def printObjectAttributes(obj, indent=0): 153 indent_str = ' ' * indent 154 if isinstance(obj, dict): 155 for key, value in obj.items(): 156 print(f"{indent_str}{key}:") 157 printObjectAttributes(value, indent + 1) 158 elif isinstance(obj, list): 159 for i, item in enumerate(obj): 160 print(f"{indent_str}[{i}]:") 161 printObjectAttributes(item, indent + 1) 162 elif hasattr(obj, '__dict__'): # Check if the object has a __dict__ attribute 163 for key, value in obj.__dict__.items(): 164 print(f"{indent_str}{key}:") 165 printObjectAttributes(value, indent + 1) 166 else: 167 print(f"{indent_str}{repr(obj)}") 168 169def printAttributesToFile(obj, file, indent=0): 170 try: 171 json_str = json.dumps(obj, indent=4) 172 file.write(json_str) 173 except TypeError: 174 # If serialization fails, fall back to custom printing and write to the file 175 indent_str = ' ' * indent 176 file.write(f"{indent_str}Object could not be serialized to JSON\n") 177 if isinstance(obj, dict): 178 for key, value in obj.items(): 179 file.write(f"{indent_str}{key}:\n") 180 printAttributesToFile(value, file, indent + 1) 181 elif isinstance(obj, list): 182 for i, item in enumerate(obj): 183 file.write(f"{indent_str}[{i}]:\n") 184 printAttributesToFile(item, file, indent + 1) 185 elif hasattr(obj, '__dict__'): 186 for key, value in obj.__dict__.items(): 187 file.write(f"{indent_str}{key}:\n") 188 printAttributesToFile(value, file, indent + 1) 189 else: 190 file.write(f"{indent_str}{repr(obj)}\n") 191 192# Converts the dependecies expression into an Abstract Syntax Tree that uses boolean operators 193def parseDependsEpression(string): 194 try: 195 # Parse the input string into an abstract syntax tree (AST) 196 tree = ast.parse(string.replace('+', ' and ').replace(',', ' or '), mode='eval') 197 expression = tree.body 198 return expression 199 except SyntaxError as e: 200 print(f"Syntax error in the input string: {e}") 201 return None 202 203# Checks the dependencies AST against the passed extensions 204def checkDependencyAST(node, extensions): 205 if isinstance(node, ast.BoolOp): 206 assert(len(node.values) >= 2) 207 value = checkDependencyAST(node.values.pop(), extensions) 208 while node.values: 209 nextValue = checkDependencyAST(node.values.pop(), extensions) 210 if isinstance(node.op, ast.And): 211 value = value and nextValue 212 if isinstance(node.op, ast.Or): 213 value = value or nextValue 214 return value 215 elif isinstance(node, ast.Name): 216 if '_VERSION_' in node.id: 217 return True 218 for ext in extensions: 219 if node.id == ext.name: 220 return True 221 return False 222 elif isinstance(node, ast.Constant): 223 return node.value 224 225# helper function that check if dependency is in list of extension 226def isDependencyMet(dependsExpression, extensionList): 227 if dependsExpression is None: 228 return True 229 tree = parseDependsEpression(dependsExpression) 230 # check if requirement dependencies are meet; if not then struct/function is not used 231 ret = checkDependencyAST(tree, extensionList) 232 return ret 233 234def substituteType(object): # both CompositeMember and FunctionArgument can be passed to this function 235 for src, dst in TYPE_SUBSTITUTIONS: 236 object.type = object.type.replace(src, dst) 237 for platformType, substitute, _ in PLATFORM_TYPES: 238 platformTypeName = platformType[0] 239 platformTypeName = platformType[-2] if "*" in platformType else platformType[0] 240 if object.type == platformTypeName: 241 object.type = PLATFORM_TYPE_NAMESPACE + '::' + substitute[0] 242 object.qualifiers = None if 'struct' in platformType else object.qualifiers 243 object.qualifiers = None if 'const' in platformType else object.qualifiers 244 if "*" in platformType: 245 object.pointer = "*" if object.pointer == "**" else None 246 247class Define: 248 def __init__ (self, name, aType, alias, value): 249 self.name = name 250 self.type = aType 251 self.alias = alias 252 self.value = value 253 254class Handle: 255 def __init__ (self, name, aType, alias, parent, objtypeenum): 256 self.name = name 257 self.type = aType 258 self.alias = alias 259 self.parent = parent 260 self.objtypeenum = objtypeenum 261 262class Bitmask: 263 def __init__ (self, name, aType, requires, bitvalues): 264 self.name = name 265 self.type = aType 266 self.alias = None # initialy None but may be filled while parsing next tag 267 self.requires = requires 268 self.bitvalues = bitvalues 269 270class Enumerator: 271 def __init__ (self, name, value, bitpos): 272 self.name = name 273 self.aliasList = [] # list of strings 274 self.value = value # some enums specify value and some bitpos 275 self.bitpos = bitpos 276 self.extension = None # name of extension that added this enumerator 277 278class Enum: 279 def __init__ (self, name): 280 self.name = name 281 self.alias = None # name of enum alias or None 282 self.type = None # enum or bitmask 283 self.bitwidth = "32" 284 self.enumeratorList = [] # list of Enumerator objects 285 286 def areValuesLinear (self): 287 if self.type == 'bitmask': 288 return False 289 curIndex = 0 290 for enumerator in self.enumeratorList: 291 intValue = parseInt(enumerator.value) 292 if intValue != curIndex: 293 return False 294 curIndex += 1 295 return True 296 297class CompositeMember: 298 def __init__ (self, name, aType, pointer, qualifiers, arraySizeList, optional, limittype, values, fieldWidth): 299 self.name = name 300 self.type = aType # member type 301 self.pointer = pointer # None, '*' or '**' 302 self.qualifiers = qualifiers # 'const' or 'struct' or None 303 self.arraySizeList = arraySizeList # can contain digits or enums 304 self.optional = optional 305 self.limittype = limittype 306 self.values = values # allowed member values 307 self.fieldWidth = fieldWidth # ':' followed by number of bits 308 309 # check if type should be swaped 310 substituteType(self) 311 312class Composite: 313 def __init__ (self, name, category, allowduplicate, structextends, returnedonly, members): 314 self.name = name 315 self.category = category # is it struct or union 316 self.aliasList = [] # most composite types have single alias but there are cases like VkPhysicalDeviceVariablePointersFeatures that have 3 317 self.allowduplicate = allowduplicate 318 self.structextends = structextends 319 self.returnedonly = returnedonly 320 self.members = members # list of CompositeMember objects 321 self.notSupportedAlias = None # alias used in not supported api e.g. VkPhysicalDeviceLineRasterizationFeaturesKHR is alias available only in vulkan but not in SC 322 323class FunctionArgument: 324 def __init__ (self, name, qualifiers, aType, pointer = None, secondPointerIsConst = False, arraySize = None, len = None): 325 self.name = name 326 self.qualifiers = qualifiers 327 self.type = aType 328 self.pointer = pointer # None, '*' or '**' 329 self.secondPointerIsConst = secondPointerIsConst 330 self.arraySize = arraySize 331 self.len = len 332 333 # check if type should be swaped 334 substituteType(self) 335 336class Function: 337 TYPE_PLATFORM = 0 # Not bound to anything 338 TYPE_INSTANCE = 1 # Bound to VkInstance 339 TYPE_DEVICE = 2 # Bound to VkDevice 340 341 def __init__ (self, name, returnType = None, arguments = None): 342 self.name = name 343 self.aliasList = [] 344 self.queuesList = [] 345 self.returnType = returnType 346 self.arguments = arguments # list of FunctionArgument objects 347 self.functionType = Function.TYPE_PLATFORM 348 349 # Determine function type based on first argument but use TYPE_PLATFORM for vkGetInstanceProcAddr 350 if self.name == "vkGetInstanceProcAddr": 351 return 352 assert len(self.arguments) > 0 353 firstArgType = self.arguments[0].type 354 if firstArgType in ["VkInstance", "VkPhysicalDevice"]: 355 self.functionType = Function.TYPE_INSTANCE 356 elif firstArgType in ["VkDevice", "VkCommandBuffer", "VkQueue"]: 357 self.functionType = Function.TYPE_DEVICE 358 359 def getType (self): 360 return self.functionType 361 362class FeatureEnumerator: 363 def __init__ (self, name, extends, offset, extnumber): 364 self.name = name 365 self.extends = extends 366 self.offset = offset 367 self.extnumber = extnumber 368 369class FeatureRequirement: 370 def __init__ (self, operation, comment, enumList, typeList, commandList, featureList): 371 self.operation = operation # "require" or "remove" 372 self.comment = comment 373 self.enumList = enumList # list of FeatureEnumerator objects 374 self.typeList = typeList # list of strings, each representing required structure name 375 self.commandList = commandList # list of strings, each representing required function name 376 self.features = featureList # list of ExtensionFeature objects 377 378class Feature: 379 def __init__ (self, api, name, number, requirementsList): 380 self.api = api 381 self.name = name 382 self.number = number 383 self.requirementsList = requirementsList # list of FeatureRequirement objects 384 385class ExtensionEnumerator: 386 def __init__ (self, name, extends, alias, value, extnumber, offset, bitpos, vdir, comment): 387 self.name = name 388 self.extends = extends 389 self.alias = alias 390 self.value = value 391 self.extnumber = extnumber 392 self.offset = offset 393 self.bitpos = bitpos 394 self.dir = vdir 395 self.comment = comment # note: comment is used to mark not promoted features for partially promoted extensions 396 397class ExtensionCommand: 398 def __init__ (self, name, comment): 399 self.name = name 400 self.comment = comment 401 402class ExtensionType: 403 def __init__ (self, name, comment): 404 self.name = name 405 self.comment = comment 406 407class ExtensionFeature: 408 def __init__ (self, name, struct): 409 self.name = name 410 self.struct = struct 411 412class ExtensionRequirements: 413 def __init__ (self, depends, extendedEnums, newCommands, newTypes, featureList): 414 self.depends = depends # None when requirement apply to all implementations of extension or string with dependencies 415 # string with extension name when requirements apply to implementations that also support given extension 416 self.extendedEnums = extendedEnums # list of ExtensionEnumerator objects 417 self.newCommands = newCommands # list of ExtensionCommand objects 418 self.newTypes = newTypes # list of ExtensionType objects 419 self.features = featureList # list of ExtensionFeature objects 420 421class Extension: 422 def __init__ (self, name, number, type, depends, platform, promotedto, partiallyPromoted, requirementsList, supportedList): 423 self.name = name # extension name 424 self.number = number # extension version 425 self.type = type # extension type - "device" or "instance" 426 self.depends = depends # string containig grammar for required core vulkan version and/or other extensions 427 self.platform = platform # None, "win32", "ios", "android" etc. 428 self.promotedto = promotedto # vulkan version, other extension or None 429 self.partiallyPromoted = partiallyPromoted # when True then some of requirements were not promoted 430 self.requirementsList = requirementsList # list of ExtensionRequirements objects 431 self.supported = supportedList # list of supported APIs 432 433class API: 434 def __init__ (self, apiName): 435 self.apiName = apiName # string "vulkan" or "vulkansc" 436 self.basetypes = {} # dictionary, e.g. one of keys is VkFlags and its value is uint32_t 437 self.defines = [] 438 self.handles = [] # list of Handle objects 439 self.bitmasks = [] # list of Bitmask objects 440 self.enums = [] # list of Enum objects - each contains individual enum definition (including extension enums) 441 self.compositeTypes = [] # list of Composite objects - each contains individual structure/union definition (including extension structures) 442 self.functions = [] # list of Function objects - each contains individual command definition (including extension functions) 443 self.features = [] # list of Feature objects 444 self.extensions = [] # list of Extension objects - each contains individual, supported extension definition 445 self.notSupportedExtensions = [] # list of Extension objects - it contains NOT supported extensions; this is filled and needed only for SC 446 self.basicCTypes = [] # list of basic C types e.g. 'void', 'int8_t' 447 self.tempAliasesList = [] # list of aliases for enums that could not be added because enum is defined later than its alias; this is needed for SC 448 449 # read all files from extensions directory 450 additionalExtensionData = {} 451 for fileName in glob.glob(os.path.join(SCRIPTS_SRC_DIR, "extensions", "*.json")): 452 if "schema.json" in fileName: 453 continue 454 extensionName = os.path.basename(fileName)[:-5] 455 if extensionName in EXTENSIONS_TO_READ_FROM_XML_NOT_JSON: 456 continue 457 fileContent = readFile(fileName) 458 try: 459 additionalExtensionData[extensionName] = json.loads(fileContent) 460 with open(fileName, 'w') as file: 461 file.write(json.dumps(additionalExtensionData[extensionName], indent=4)) 462 except ValueError as err: 463 print("Error in %s: %s" % (os.path.basename(fileName), str(err))) 464 sys.exit(-1) 465 self.additionalExtensionData = sorted(additionalExtensionData.items(), key=lambda e: e[0]) 466 467 def addEnumerator(self, targetEnum, name, value, offset, extnumber, bitpos, dir = None): 468 # calculate enumerator value if offset attribute is present 469 if value is None and offset is not None: 470 value = 1000000000 + (int(extnumber) - 1) * 1000 + int(offset) 471 # check if value should be negative 472 value = -value if dir == "-" else value 473 # convert to string so that type matches the type in which values 474 # are stored for enums that were read from enums xml section 475 value = str(value) 476 # add new enumerator 477 targetEnum.enumeratorList.append(Enumerator(name, value, bitpos)) 478 479 def addAliasToEnumerator (self, targetEnum, name, alias): 480 assert(alias is not None) 481 for e in reversed(targetEnum.enumeratorList): 482 if alias == e.name or alias in e.aliasList: 483 # make sure same alias is not already on the list; this handles special case like 484 # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR alais which is defined in three places 485 if name not in e.aliasList: 486 e.aliasList.append(name) 487 return True 488 return False 489 490 def readEnum (self, enumsNode): 491 enumName = enumsNode.get("name") 492 # special case for vulkan hardcoded constants that are specified as enum in vk.xml 493 if enumName == "API Constants": 494 for enumItem in enumsNode: 495 self.defines.append(Define( 496 enumItem.get("name"), 497 enumItem.get("type"), 498 enumItem.get("alias"), 499 enumItem.get("value") 500 )) 501 return 502 # initial enum definition is read while processing types section; 503 # we need to find this enum definition and add data to it 504 enumDefinition = [enumDef for enumDef in self.enums if enumName == enumDef.name][0] 505 # add type and bitwidth to enum definition 506 enumDefinition.type = enumsNode.get("type") 507 enumDefinition.bitwidth = enumsNode.get("bitwidth") 508 if enumDefinition.bitwidth is None: 509 enumDefinition.bitwidth = "32" 510 # add components to enum definition 511 for enumeratorItem in enumsNode: 512 # skip comment tags 513 if enumeratorItem.tag != "enum": 514 continue 515 # when api attribute is present it limits param to specific api 516 supportedApi = enumeratorItem.get("api") 517 if supportedApi != None and supportedApi != self.apiName: 518 continue 519 name = enumeratorItem.get("name") 520 alias = enumeratorItem.get("alias") 521 if alias is None: 522 self.addEnumerator( 523 enumDefinition, 524 name, 525 enumeratorItem.get("value"), 526 enumeratorItem.get("offset"), 527 enumeratorItem.get("extnumber"), 528 enumeratorItem.get("bitpos"), 529 enumeratorItem.get("dir")) 530 else: 531 self.addAliasToEnumerator(enumDefinition, name, alias) 532 533 def readCommand (self, commandNode): 534 # when api attribute is present it limits command just to specified api 535 dedicatedForApi = commandNode.get("api") 536 if dedicatedForApi is not None and dedicatedForApi != self.apiName: 537 # we dont need to parse this command 538 return 539 # check if this is alias 540 alias = commandNode.get("alias") 541 # if node is alias then use the fact that alias definition follows aliased structure 542 if alias is not None: 543 # aliased command has usually been added recently, so we iterate in reverse order 544 found = False 545 for f in reversed(self.functions): 546 found = (f.name == alias) 547 if found: 548 f.aliasList.append(commandNode.get("name")) 549 break 550 assert found 551 # go to next node 552 return 553 # memorize all parameters 554 functionParams = [] 555 queuesList = [] 556 557 protoNode = None 558 for paramNode in commandNode: 559 # memorize prototype node 560 if paramNode.tag == "proto": 561 protoNode = paramNode 562 continue 563 # skip implicitexternsyncparams 564 if paramNode.tag != "param": 565 continue 566 # when api attribute is present it limits param to specific api 567 supportedApi = paramNode.get("api") 568 if supportedApi != None and supportedApi != self.apiName: 569 continue 570 nameNode = paramNode.find("name") 571 typeNode = paramNode.find("type") 572 starCount = typeNode.tail.count('*') 573 lenAttr = paramNode.get("len") 574 functionParams.append(FunctionArgument( 575 nameNode.text, 576 paramNode.text, 577 paramNode.find("type").text, 578 '*' * starCount if starCount > 0 else None, 579 'const' in typeNode.tail, 580 nameNode.tail, 581 lenAttr 582 )) 583 584 queuesAttr = commandNode.get("queues") 585 if queuesAttr: 586 queuesList = queuesAttr.split(",") 587 588 # memorize whole function 589 func = Function( 590 protoNode.find("name").text, 591 protoNode.find("type").text, 592 functionParams, 593 ) 594 595 func.queuesList = queuesList 596 self.functions.append(func) 597 598 def readExtension (self, extensionNode): 599 # check to which list this extension should be added 600 supportedList = extensionNode.get("supported") 601 isExtensionSupported = self.apiName in supportedList.split(',') 602 promotedto = extensionNode.get("promotedto") 603 # read extension definition to proper list 604 extensionName = extensionNode.get("name") 605 extensionNumber = extensionNode.get("number") 606 if promotedto is not None and 'VK_VERSION' in promotedto: 607 p = promotedto 608 major = int(p[-3]) 609 minor = int(p[-1]) 610 # if self.apiName == "vulkansc" and "vulkan" in supportedList and major == 1 and minor <= 2 and extensionName in EXTENSIONS_TO_READ_FROM_XML_NOT_JSON: 611 # isExtensionSupported = True 612 targetExtensionList = self.extensions if isExtensionSupported else self.notSupportedExtensions 613 partiallyPromoted = False 614 # before reading extension data first read extension 615 # requirements by iterating over all require tags 616 requirementsList = [] 617 for requireItem in extensionNode.findall('require'): 618 extendedEnums = [] 619 newCommands = [] 620 newTypes = [] 621 featureList = [] 622 # iterate over all children in current require tag 623 # and add them to proper list 624 for individualRequirement in requireItem: 625 requirementName = individualRequirement.get("name") 626 requirementComment = individualRequirement.get("comment") 627 # check if this requirement was not promoted and mark 628 # this extension as not fully promoted 629 if requirementComment is not None and "Not promoted to" in requirementComment: 630 partiallyPromoted = True 631 # check if this requirement describes enum, command or type 632 if individualRequirement.tag == "enum": 633 # when api attribute is present it limits enumerator to specific api 634 supportedApi = individualRequirement.get("api") 635 if supportedApi != None and supportedApi != self.apiName: 636 continue 637 extendedEnumName = individualRequirement.get("extends") 638 extendedEnums.append(ExtensionEnumerator( 639 requirementName, 640 extendedEnumName, 641 individualRequirement.get("alias"), 642 individualRequirement.get("value"), 643 individualRequirement.get("extnumber"), 644 individualRequirement.get("offset"), 645 individualRequirement.get("bitpos"), 646 individualRequirement.get("dir"), 647 requirementComment)) 648 elif individualRequirement.tag == "command": 649 newCommands.append(ExtensionCommand(requirementName, requirementComment)) 650 elif individualRequirement.tag == "type": 651 newTypes.append(ExtensionType(requirementName, requirementComment)) 652 elif individualRequirement.tag == "feature": 653 featureList.append(ExtensionFeature(requirementName, individualRequirement.get("struct"))) 654 elif individualRequirement.tag == "comment" and "not promoted to" in individualRequirement.text: 655 # partial promotion of VK_EXT_ycbcr_2plane_444_formats and VK_EXT_4444_formats 656 # is marked with comment tag in first require section 657 partiallyPromoted = True 658 # construct requirement object and add it to the list 659 requirementsList.append(ExtensionRequirements( 660 requireItem.get("depends"), # dependencies that can include "and/or" grammar 661 extendedEnums, # extendedEnums 662 newCommands, # newCommands 663 newTypes, # newTypes 664 featureList # features 665 )) 666 667 supportedList = extensionNode.get("supported").split(",") 668 # add extension definition to proper api object 669 targetExtensionList.append(Extension( 670 extensionName, # name 671 extensionNumber, # number 672 extensionNode.get("type"), # type 673 extensionNode.get("depends"), # depends 674 extensionNode.get("platform"), # platform 675 extensionNode.get("promotedto"), # promotedto 676 partiallyPromoted, # partiallyPromoted 677 requirementsList, # requirementsList 678 supportedList # supportedList 679 )) 680 681 def readFeature (self, featureNode): 682 # api attribute limits feature just to specified api 683 supportedApis = featureNode.get("api") 684 isFeatureSupportedByApi = self.apiName in supportedApis.split(',') 685 requirementsList = [] 686 for requirementGroup in featureNode: 687 enumList = [] 688 typeList = [] 689 featureList = [] 690 commandList = [] 691 for requirement in requirementGroup: 692 requirementName = requirement.get("name") 693 if requirement.tag == "enum": 694 extendedEnumName = requirement.get("extends") 695 offset = requirement.get("offset") 696 extnumber = requirement.get("extnumber") 697 enumList.append(FeatureEnumerator(requirementName, extendedEnumName, offset, extnumber)) 698 if isFeatureSupportedByApi and extendedEnumName is not None: 699 # find extended enum in api.enums list 700 for e in self.enums: 701 if extendedEnumName == e.name: 702 # read enumerator and add it to enum 703 alias = requirement.get("alias") 704 if alias is None: 705 self.addEnumerator( 706 e, 707 requirementName, 708 requirement.get("value"), 709 offset, 710 extnumber, 711 requirement.get("bitpos"), 712 requirement.get("dir")) 713 elif not self.addAliasToEnumerator(e, requirementName, alias): 714 self.tempAliasesList.append((e, requirementName, alias)) 715 break 716 elif requirement.tag == "type": 717 typeList.append(requirementName) 718 elif requirement.tag == "feature": 719 featureList.append(ExtensionFeature(requirementName, requirement.get("struct"))) 720 elif requirement.tag == "command": 721 commandList.append(requirementName) 722 requirementsList.append(FeatureRequirement( 723 requirementGroup.tag, 724 requirementGroup.get("comment"), 725 enumList, 726 typeList, 727 commandList, 728 featureList 729 )) 730 self.features.append(Feature( 731 supportedApis, 732 featureNode.get("name"), 733 featureNode.get("number"), 734 requirementsList 735 )) 736 737 def readType (self, typeNode): 738 name = typeNode.get("name") 739 alias = typeNode.get("alias") 740 category = typeNode.get("category") 741 if category == "enum": 742 if alias is None: 743 self.enums.append(Enum(name)) 744 else: 745 for e in reversed(self.enums): 746 if alias == e.name: 747 e.alias = name 748 break 749 elif category == "handle": 750 type = None 751 if alias is None: 752 name = typeNode.find("name").text 753 type = typeNode.find("type").text 754 self.handles.append(Handle( 755 name, 756 type, 757 alias, 758 typeNode.get("parent"), 759 typeNode.get("objtypeenum"), 760 )) 761 else: 762 for h in reversed(self.handles): 763 if alias == h.name: 764 h.alias = name 765 break 766 elif category == "basetype": 767 # processing only those basetypes that have type child 768 type = typeNode.find("type") 769 if type is not None: 770 self.basetypes[typeNode.find("name").text] = type.text 771 elif category == "bitmask": 772 # when api attribute is present it limits bitmask to specific api 773 supportedApi = typeNode.get("api") 774 if supportedApi != None and supportedApi != self.apiName: 775 # go to next node 776 return 777 # if node is alias then use the fact that alias definition follows aliased bitmasks; 778 # in majoriti of cases it follows directly aliased bitmasks but in some cases there 779 # is a unrelated bitmasks definition in between - to handle this traverse in reverse order 780 if alias is not None: 781 for bm in reversed(self.bitmasks): 782 if alias == bm.name: 783 bm.alias = name 784 break 785 else: 786 self.bitmasks.append(Bitmask( 787 typeNode.find("name").text, 788 typeNode.find("type").text, 789 typeNode.get("requires"), 790 typeNode.get("bitvalues") 791 )) 792 elif category in ["struct", "union"]: 793 # if node is alias then use the fact that alias definition follows aliased structure; 794 # in majoriti of cases it follows directly aliased structure but in some cases there 795 # is a unrelated structure definition in between - to handle this traverse in reverse order 796 if alias is not None: 797 for ct in reversed(self.compositeTypes): 798 if alias == ct.name or alias in ct.aliasList: 799 ct.aliasList.append(name) 800 break 801 # go to next node 802 return 803 # read structure members 804 structMembers = [] 805 for memberNode in typeNode: 806 if memberNode.tag != "member": 807 continue 808 # when api attribute is present it limits bitmask to specific api 809 supportedApi = memberNode.get("api") 810 if supportedApi != None and supportedApi != self.apiName: 811 # go to next member 812 continue 813 # handle enum nodes that can be used for array dimensions 814 arraySizeList = [] 815 for node in memberNode: 816 if node.tag == "enum": 817 arraySizeList.append(node.text) 818 # check if there are array dimension that are not enums 819 if '[' in node.tail and len(node.tail) > 2: 820 arraySizeList += node.tail.replace(']', ' ').replace('[', ' ').split() 821 # handle additional text after name tag; it can represent array 822 # size like in VkPipelineFragmentShadingRateEnumStateCreateInfoNV 823 # or number of bits like in VkAccelerationStructureInstanceKHR 824 nameNode = memberNode.find("name") 825 nameTail = nameNode.tail 826 fieldWidth = None 827 if nameTail: 828 if ':' in nameTail: 829 fieldWidth = nameTail.replace(':', '').replace(' ', '') 830 elif '[' in nameTail and ']' in nameTail: 831 nameTail = nameTail.replace(']', ' ').replace('[', ' ') 832 arraySizeList = nameTail.split() + arraySizeList 833 # handle additional text after type tag; it can represent pointers like *pNext 834 memberTypeNode = memberNode.find("type") 835 pointer = memberTypeNode.tail.strip() if memberTypeNode.tail is not None else None 836 structMembers.append(CompositeMember( 837 nameNode.text, # name 838 memberTypeNode.text, # type 839 pointer, # pointer 840 memberNode.text, # qualifiers 841 arraySizeList, # arraySizeList 842 memberNode.get("optional"), # optional 843 memberNode.get("limittype"), # limittype 844 memberNode.get("values"), # values 845 fieldWidth # fieldWidth 846 )) 847 # create structure definition 848 self.compositeTypes.append(Composite( 849 name, 850 category, 851 typeNode.get("allowduplicate"), 852 typeNode.get("structextends"), 853 typeNode.get("returnedonly"), 854 structMembers 855 )) 856 elif category == "define": 857 nNode = typeNode.find("name") 858 tNode = typeNode.find("type") 859 if nNode == None or tNode == None: 860 return 861 requires = typeNode.get("requires") 862 name = nNode.text 863 if "API_VERSION_" in name or requires == "VK_MAKE_VIDEO_STD_VERSION": 864 value = tNode.tail 865 value = tNode.text + value[:value.find(')')+1] 866 value = value.replace('VKSC_API_VARIANT', '1') 867 self.defines.append(Define( 868 name, 869 "uint32_t", 870 None, 871 value 872 )) 873 else: 874 requires = typeNode.get("requires") 875 if requires == 'vk_platform': 876 self.basicCTypes.append(name) 877 878 def build (self, rawVkXml): 879 # iterate over all *.xml root children 880 for rootChild in rawVkXml.getroot(): 881 882 # each enum is defined in separate enums node directly under root node 883 if rootChild.tag == "enums": 884 self.readEnum(rootChild) 885 886 # read function definitions 887 if rootChild.tag == "commands": 888 commandsNode = rootChild 889 for commandItem in commandsNode: 890 self.readCommand(commandItem) 891 892 # read vulkan versions 893 if rootChild.tag == "feature": 894 self.readFeature(rootChild) 895 896 # read extensions 897 if rootChild.tag == "extensions": 898 extensionsNode = rootChild 899 for extensionItem in extensionsNode: 900 self.readExtension(extensionItem) 901 902 # "types" is a first child of root so it's optimal to check for it 903 # last and don't repeat this check for all other iterations 904 if rootChild.tag == "types": 905 typesNode = rootChild 906 for typeItem in typesNode: 907 self.readType(typeItem) 908 909 def postProcess (self): 910 911 # verify that promotedto extensions are supported by the api 912 for ext in self.extensions: 913 if ext.promotedto is not None and "VK_VERSION" not in ext.promotedto: 914 if not any(x.name == ext.promotedto for x in self.extensions): 915 ext.promotedto = None 916 917 if self.apiName == "vulkansc": 918 # temporary workaround for extensions that are marked only for vulkan api in xml while 919 # they are need by vulkan_json_data.hpp and vulkan_json_parser.hpp in vulkansc 920 workAroundList = [ 921 "VK_NV_device_diagnostic_checkpoints", 922 "VK_KHR_format_feature_flags2", 923 "VK_EXT_vertex_attribute_divisor", 924 "VK_EXT_global_priority", 925 "VK_EXT_calibrated_timestamps", 926 ] 927 for extName in workAroundList: 928 extData = [e for e in self.notSupportedExtensions if e.name == extName] 929 if len(extData): 930 extData = extData[0] 931 self.extensions.append(extData) 932 self.notSupportedExtensions.remove(extData) 933 # temporary workaround for enums needed by vulkan_json_parser.hpp that are marked only for vulkan api in xml 934 scFeatures = [f for f in self.features if f.api == "vulkansc"][0] 935 for enum in self.enums: 936 if enum.name == "VkPipelineLayoutCreateFlagBits": 937 self.addEnumerator(enum, "VK_PIPELINE_LAYOUT_CREATE_RESERVED_0_BIT_AMD", None, None, None, 0, None) 938 self.addEnumerator(enum, "VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT", None, None, None, 1, None) 939 scFeatures.requirementsList[0].typeList.append(enum.name) 940 break 941 # add new enumerators that were added by extensions to api.enums 942 # we have to do it at the end for SC because some enums are dependent from extensions/api versions 943 # and those dependencies can be checked only after all extensions were read 944 for ext in self.extensions: 945 logging.debug("Considering extension %s for API %s" % (ext.name, apiName)) 946 for requirement in ext.requirementsList: 947 # check if this requirement is supported by current implementation 948 isRequirementSupported = isDependencyMet(requirement.depends, self.extensions) 949 # add enumerator to proper enum from api.enums 950 if isRequirementSupported: 951 for enumerator in requirement.extendedEnums: 952 if enumerator.extends is None: 953 continue 954 # find enum in api.enums 955 matchedEnums = [enum for enum in self.enums if enumerator.extends == enum.name or enumerator.extends == enum.alias] 956 if len(matchedEnums) == 0: 957 logging.error("Could not find enum %s extends %s in %s " % (enumerator.name, enumerator.extends, self.apiName)) 958 matchedEnum = matchedEnums[0] 959 # add enumerator only when it is not already in enum 960 if len([e for e in matchedEnum.enumeratorList if e.name == enumerator.name]) == 0: 961 if enumerator.alias == None: 962 logging.debug("Adding enum value %s for extension %s in API %s" % (enumerator.name, ext.name, apiName)) 963 self.addEnumerator( 964 matchedEnum, 965 enumerator.name, 966 enumerator.value, 967 enumerator.offset, 968 enumerator.extnumber if enumerator.extnumber else ext.number, 969 enumerator.bitpos, 970 enumerator.dir) 971 elif not self.addAliasToEnumerator(matchedEnum, enumerator.name, enumerator.alias): 972 # we might not be able to add alias as we might be missing what we are aliasing 973 # this will happen when aliased enum is added later then definition of alias 974 logging.debug("Adding alias %s to enum %s for extension %s in API %s" % (enumerator.name, matchedEnum.name, ext.name, apiName)) 975 self.tempAliasesList.append((matchedEnum, enumerator.name, enumerator.alias)) 976 else: 977 logging.warning("Skipping requirement in extension %s because dependencies are not met: %s" % (ext.name, requirement.depends)) 978 979 # add aliases to enumerators that were defined after alias definition 980 for enum, name, alias in self.tempAliasesList: 981 if not self.addAliasToEnumerator(enum, name, alias): 982 # if enumerator that should be aliased was not found then try to insert it without alias 983 # (this happens for vulkansc as in xml enumerator might be defined in extension that is 984 # not supported by sc or in normal vulkan version) 985 def tryToFindEnumValueInNotSupportedExtensions(searchedName): 986 for nsExt in self.notSupportedExtensions: 987 for r in nsExt.requirementsList: 988 for enumerator in r.extendedEnums: 989 if enumerator.name == searchedName: 990 self.addEnumerator( 991 enum, 992 name, 993 enumerator.value, 994 enumerator.offset, 995 enumerator.extnumber if enumerator.extnumber else ext.number, 996 enumerator.bitpos, 997 enumerator.dir) 998 # there is still 1 case where alias that is not part of SC needs to be added for SC 999 self.addAliasToEnumerator(enum, alias, name) 1000 return True 1001 return False 1002 def tryToFindEnumValueInNotSupportedVersions(searchedName): 1003 for f in self.features: 1004 # check only not supported features 1005 if self.apiName in f.api.split(','): 1006 continue 1007 for r in f.requirementsList: 1008 for enumerator in r.enumList: 1009 if enumerator.name == searchedName: 1010 assert enumerator.extnumber is not None 1011 self.addEnumerator( 1012 enum, 1013 name, 1014 None, 1015 enumerator.offset, 1016 enumerator.extnumber, 1017 None, 1018 None) 1019 self.addAliasToEnumerator(enum, alias, name) 1020 return True 1021 return False 1022 # using functions for fast stack unwinding 1023 if tryToFindEnumValueInNotSupportedExtensions(alias): 1024 continue 1025 if tryToFindEnumValueInNotSupportedVersions(alias): 1026 continue 1027 self.tempAliasesList = None 1028 1029 if self.apiName == "vulkan": 1030 def removeExtensionFromApi(extName, structureNameList, commandNameList): 1031 extObjectList = [e for e in api.extensions if e.name == extName] 1032 if len(extObjectList) > 0: 1033 api.extensions.remove(extObjectList[0]) 1034 structObjectList = [ct for ct in api.compositeTypes if ct.name in structureNameList] 1035 for s in structObjectList: 1036 api.compositeTypes.remove(s) 1037 commandObjectList = [f for f in api.functions if f.name in commandNameList] 1038 for f in commandObjectList: 1039 api.functions.remove(f) 1040 1041 # remove structures and commands added by VK_EXT_directfb_surface extension 1042 removeExtensionFromApi("VK_EXT_directfb_surface", 1043 ["VkDirectFBSurfaceCreateFlagsEXT", "VkDirectFBSurfaceCreateInfoEXT"], 1044 ["vkCreateDirectFBSurfaceEXT", "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"]) 1045 1046 # remove structures and commands added by disabled VK_ANDROID_native_buffer extension; 1047 # disabled extensions aren't read but their structures and commands will be in types and commands sections in vk.xml 1048 removeExtensionFromApi("VK_ANDROID_native_buffer", 1049 ["VkNativeBufferANDROID", "VkSwapchainImageCreateInfoANDROID", 1050 "VkPhysicalDevicePresentationPropertiesANDROID", "VkNativeBufferUsage2ANDROID", 1051 "VkSwapchainImageUsageFlagBitsANDROID", "VkSwapchainImageUsageFlagsANDROID"], 1052 ["vkGetSwapchainGrallocUsageANDROID", "vkAcquireImageANDROID", 1053 "vkQueueSignalReleaseImageANDROID", "vkGetSwapchainGrallocUsage2ANDROID"]) 1054 1055 # remove empty enums e.g. VkQueryPoolCreateFlagBits, VkDeviceCreateFlagBits 1056 enumsToRemove = [enum for enum in self.enums if len(enum.enumeratorList) == 0] 1057 for er in enumsToRemove: 1058 self.enums.remove(er) 1059 1060 # add alias for VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR (in vk.xml for this struct alias is defined before struct 1061 # where in all other cases it is defined after structure definition) 1062 barycentricFeaturesStruct = [c for c in api.compositeTypes if c.name == 'VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR'][0] 1063 barycentricFeaturesStruct.aliasList.append('VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV') 1064 1065 elif self.apiName == "vulkansc": 1066 # remove commands that are marked with <remove> tag in SC feature specification; 1067 # e.g. there is no vkCreateShaderModule in SC 1068 functionsToRemove = [] 1069 scFeatures = [f for f in self.features if f.api == "vulkansc"][0] 1070 for featureRequirement in scFeatures.requirementsList: 1071 if featureRequirement.operation == "remove": 1072 # find function in the list of all functions 1073 for fun in self.functions: 1074 if fun.name in featureRequirement.commandList: 1075 functionsToRemove.append(fun) 1076 for fun in functionsToRemove: 1077 self.functions.remove(fun) 1078 1079 # sc is based on vk1.2 so we need to check features of vk1.3+ 1080 # and rename functions and structures that were promoted in 1081 # those versions to their previous names (aliases) 1082 renamedStructuresDict = {} 1083 for feature in self.features: 1084 # skip vk versions smaller than 1.3 1085 if int(feature.number[-1]) < 3: 1086 continue 1087 # iterate over all requirements and enums/commands/structs added in them 1088 for featureRequirement in feature.requirementsList: 1089 renamedFunctionsList = [] 1090 # find promotedFun in list of all functions 1091 for fun in self.functions: 1092 if fun.name not in featureRequirement.commandList: 1093 continue 1094 # replace function name with its last alias 1095 fun.name = fun.aliasList[-1] 1096 fun.aliasList = fun.aliasList[:-1] 1097 # memorize renamed functions 1098 renamedFunctionsList.append(fun) 1099 # skip renaming enums and structures for extensions that are available for SC 1100 if featureRequirement.comment is not None: 1101 matchedExtension = re.search(r'Promoted from (\w+) ', featureRequirement.comment, re.IGNORECASE) 1102 if matchedExtension is not None: 1103 promotedExtensionName = matchedExtension.group(1) 1104 extensionList = [e for e in self.extensions if e.name == promotedExtensionName] 1105 if len(extensionList) > 0: 1106 continue 1107 for promotedEnumerator in featureRequirement.enumList: 1108 # iterate over all enums and find one that was extended 1109 for enum in self.enums: 1110 logging.debug("Considering enum %s for API %s" % (enum.name, api.apiName)) 1111 if enum.name != promotedEnumerator.extends: 1112 continue 1113 enumeratorReplaced = False 1114 # find enumerator that should have changed name 1115 for enumerator in enum.enumeratorList: 1116 if enumerator.name != promotedEnumerator.name or len(enumerator.aliasList) == 0: 1117 continue 1118 # replace enumerator name with its first alias 1119 enumerator.name = enumerator.aliasList[0] 1120 enumerator.aliasList = enumerator.aliasList[1:] 1121 # first member of almost all structures is VkStructureType and in xml that member 1122 # has defined value - we need to change those values to versions supported by SC 1123 if "STRUCTURE_TYPE" in enumerator.name: 1124 for struct in self.compositeTypes: 1125 if struct.members[0].values == promotedEnumerator.name: 1126 struct.members[0].values = enumerator.name 1127 break 1128 enumeratorReplaced = True 1129 break 1130 if enumeratorReplaced: 1131 break 1132 structsToRemove = [] 1133 # find promotedStruct in list of all structures 1134 for struct in self.compositeTypes: 1135 promotedStruct = struct.name 1136 if promotedStruct not in featureRequirement.typeList: 1137 continue 1138 # skip structures without alias 1139 if len(struct.aliasList) == 0: 1140 # remove VkPhysicalDeviceVulkan13Features/Properties 1141 if "VkPhysicalDeviceVulkan" in promotedStruct: 1142 structsToRemove.append(struct) 1143 continue 1144 # replace struct name with its last alias 1145 struct.notSupportedAlias = struct.name 1146 struct.name = struct.aliasList[-1] 1147 struct.aliasList = struct.aliasList[:-1] 1148 # memorize all renamed structures 1149 renamedStructuresDict[promotedStruct] = struct 1150 # check all renamed functions and make sure that argument types are also renamed 1151 for renamedFun in renamedFunctionsList: 1152 for arg in renamedFun.arguments: 1153 if arg.type == promotedStruct: 1154 arg.type = struct.name 1155 # remove structures that were marked for removal 1156 for st in structsToRemove: 1157 self.compositeTypes.remove(st) 1158 1159 # iterate over all renamed structures and make sure that all their attributes are also renamed 1160 for newName in renamedStructuresDict: 1161 for member in renamedStructuresDict[newName].members: 1162 if member.type in renamedStructuresDict: 1163 member.type = renamedStructuresDict[member.type].name 1164 1165 # remove enums that are not part of any vulkan version nor extension 1166 # (SC specific enums are in vk.xml without any attribute identifying that they are SC specific; same for enums for disabled extensions) 1167 def isEnumUsed(enumName, enumAlias): 1168 for feature in self.features: 1169 if self.apiName not in feature.api.split(','): 1170 continue 1171 for requirement in feature.requirementsList: 1172 for typeName in requirement.typeList: 1173 if (typeName == enumName) or (typeName == enumAlias): 1174 return True 1175 for ext in self.extensions: 1176 for requirement in ext.requirementsList: 1177 for newType in requirement.newTypes: 1178 if (newType.name == enumName) or (newType.name == enumAlias): 1179 return True 1180 for extendedEnum in requirement.extendedEnums: 1181 if extendedEnum.extends == enumName: 1182 return True 1183 return False 1184 # do removal using above function 1185 enumsToRemove = [] 1186 for enum in self.enums: 1187 if isEnumUsed(enum.name, enum.alias): 1188 continue 1189 enumsToRemove.append(enum) 1190 for er in enumsToRemove: 1191 logging.debug("Removing enum %s because not used in API %s" % (er.name, self.apiName)) 1192 self.enums.remove(er) 1193 1194 # remove structures that are not part of any vulkan version nor extension; SC specific 1195 # structures are in vk.xml without any attribute identifying that they are SC specific 1196 def isStructUsed(structNameList): 1197 for feature in self.features: 1198 if self.apiName not in feature.api.split(','): 1199 continue 1200 for requirement in feature.requirementsList: 1201 for typeName in requirement.typeList: 1202 if typeName in structNameList: 1203 return True 1204 for ext in self.extensions: 1205 for requirement in ext.requirementsList: 1206 for newType in requirement.newTypes: 1207 if newType.name in structNameList: 1208 return isDependencyMet(requirement.depends, self.extensions) 1209 return False 1210 1211 structsToRemove = [] 1212 for struct in self.compositeTypes: 1213 structNameList = [struct.name] + struct.aliasList 1214 if isStructUsed(structNameList): 1215 continue 1216 structsToRemove.append(struct) 1217 for st in structsToRemove: 1218 self.compositeTypes.remove(st) 1219 1220 # remove commands that are not part of any vulkan version nor extension 1221 # (SC specific commands are in vk.xml without any attribute identifying that they are SC specific) 1222 def isFunctionUsed(functionNameList): 1223 for feature in self.features: 1224 if self.apiName not in feature.api.split(','): 1225 continue 1226 for requirement in feature.requirementsList: 1227 for commandName in requirement.commandList: 1228 if commandName in functionNameList: 1229 return True 1230 for ext in self.extensions: 1231 for requirement in ext.requirementsList: 1232 for newCommand in requirement.newCommands: 1233 if newCommand.name in functionNameList: 1234 return isDependencyMet(requirement.depends, self.extensions) 1235 return False 1236 1237 functionsToRemove = [] 1238 for fun in self.functions: 1239 functionNameList = [fun.name] + fun.aliasList 1240 if isFunctionUsed(functionNameList): 1241 continue 1242 functionsToRemove.append(fun) 1243 for fun in functionsToRemove: 1244 logging.debug("Removing function %s because not used in API %s" % (fun.name, self.apiName)) 1245 self.functions.remove(fun) 1246 1247 # remove handles that are not part of any vulkan command or structure 1248 def isHandleUsed(structList, functionList, handleName): 1249 for struct in structList: 1250 for member in struct.members: 1251 if handleName in member.type: 1252 return True 1253 for fun in functionList: 1254 for arg in fun.arguments: 1255 if handleName in arg.type: 1256 return True 1257 return False 1258 1259 handlesToRemove = [] 1260 for h in self.handles: 1261 if isHandleUsed(self.compositeTypes, self.functions, h.name): 1262 continue 1263 handlesToRemove.append(h) 1264 for h in handlesToRemove: 1265 logging.debug("Removing unused handle %s from API %s" % (h.name, self.apiName)) 1266 self.handles.remove(h) 1267 1268 # sort enumerators in enums 1269 sortLambda = lambda enumerator: int(enumerator.bitpos) if enumerator.value is None else int(enumerator.value, 16 if 'x' in enumerator.value else 10) 1270 for enum in self.enums: 1271 # skip enums that have no items or just one in enumeratorList (e.g. VkQueryPoolCreateFlagBits) 1272 if len(enum.enumeratorList) < 2: 1273 continue 1274 # construct list of enumerators in which value and bitpos are not None 1275 enumeratorsToSort = [e for e in enum.enumeratorList if e.value != e.bitpos] 1276 # construct list of enumerators in which value and bitpos are equal to None 1277 remainingEnumerators = [e for e in enum.enumeratorList if e.value == e.bitpos] 1278 # construct sorted enumerator list with aliases at the end 1279 enum.enumeratorList = sorted(enumeratorsToSort, key=sortLambda) 1280 enum.enumeratorList.extend(remainingEnumerators) 1281 1282 # Fill in extension data that comes from the XML 1283 additionalExtensionNames = [item[0] for item in self.additionalExtensionData] 1284 for ext in self.extensions: 1285 if ext.name not in EXTENSIONS_TO_READ_FROM_XML_NOT_JSON: 1286 continue 1287 if ext.name in additionalExtensionNames: 1288 logging.error("Extension %s already defined as JSON!" % (ext.name)) 1289 mandatoryFeatures = {} 1290 core = "" 1291 mandatory_variants = ext.supported 1292 if ext.promotedto is not None and 'VK_VERSION' in ext.promotedto: 1293 p = ext.promotedto 1294 major = int(p[-3]) 1295 minor = int(p[-1]) 1296 core = f'0.{major}.{minor}.0' 1297 if "vulkan" in mandatory_variants and major == 1 and minor <= 2: 1298 mandatory_variants = [] 1299 for requirement in ext.requirementsList: 1300 featureStructName = None 1301 featureStruct = None 1302 for feature in requirement.features: 1303 newFeatureStructName = feature.struct 1304 for ct in self.compositeTypes: 1305 if newFeatureStructName in ct.aliasList: 1306 newFeatureStructName = ct.name 1307 if newFeatureStructName not in mandatoryFeatures.keys(): 1308 mandatoryFeatures[newFeatureStructName] = [] 1309 if newFeatureStructName != featureStructName: 1310 featureStructName = newFeatureStructName 1311 featureStruct = {'features': [], 'requirements': [], 'mandatory_variant': []} 1312 mandatoryFeatures[featureStructName].append(featureStruct) 1313 featureStruct['features'].append(feature.name) 1314 featureStruct['requirements'].append(ext.name) 1315 if requirement.depends is not None: 1316 featureStruct['requirements'].append(requirement.depends) 1317 if len(mandatory_variants) > 0: 1318 featureStruct["mandatory_variant"] = mandatory_variants 1319 1320 # 1321 # for reqtype in requirement.newTypes: 1322 # for ct in api.compositeTypes: 1323 # if reqtype.name == ct.name or reqtype in ct.aliasList: 1324 # featureStructName = ct.name 1325 # featureStruct = {'features': [], 'requirements': [], 'mandatory_variant': []} 1326 # for m in ct.members: 1327 # if m.name not in ["sType", "pNext"]: 1328 # featureStruct['features'].append(m.name) 1329 # featureStruct['requirements'].append(ext.name) 1330 # if requirement.depends is not None: 1331 # featureStruct['requirements'].append(requirement.depends) 1332 # if len(mandatory_variants) > 0: 1333 # featureStruct["mandatory_variant"] = mandatory_variants 1334 # featureStruct['features'] = list(dict.fromkeys(featureStruct['features'])) 1335 # featureStruct['requirements'] = list(dict.fromkeys(featureStruct['requirements'])) 1336 # featureStruct['mandatory_variant'] = list(dict.fromkeys(featureStruct['mandatory_variant'])) 1337 # if len(featureStruct['mandatory_variant']) == 0: 1338 # featureStruct.pop('mandatory_variant') 1339 # if featureStructName not in mandatoryFeatures.keys(): 1340 # mandatoryFeatures[featureStructName] = [] 1341 # mandatoryFeatures[featureStructName].append(featureStruct) 1342 for featureStructName in mandatoryFeatures.keys(): 1343 for featureStruct in mandatoryFeatures[featureStructName]: 1344 featureStruct['features'] = list(dict.fromkeys(featureStruct['features'])) 1345 featureStruct['requirements'] = list(dict.fromkeys(featureStruct['requirements'])) 1346 featureStruct['mandatory_variant'] = list(dict.fromkeys(featureStruct['mandatory_variant'])) 1347 if len(featureStruct['mandatory_variant']) == 0: 1348 featureStruct.pop('mandatory_variant') 1349 data = {} 1350 if ext.name.startswith("VK_KHR") or ext.name.startswith("VK_EXT"): 1351 data['register_extension'] = {'type': ext.type, 'core': core} 1352 if len(mandatoryFeatures) > 0: 1353 data['mandatory_features'] = mandatoryFeatures 1354 1355 jsonFilePath = os.path.join(SCRIPTS_SRC_DIR, "extensions", ext.name + ".json") 1356 with open(jsonFilePath, 'w') as file: 1357 printAttributesToFile(data, file, indent=4) 1358 logging.debug("File written to " + jsonFilePath) 1359 api.additionalExtensionData.append((ext.name, data)) 1360 1361 # Here we do the API version requirements 1362 for apiFeature in self.features: 1363 if apiFeature.name not in EXTENSIONS_TO_READ_FROM_XML_NOT_JSON: 1364 continue 1365 if apiFeature.name in additionalExtensionNames: 1366 logging.error("API feature %s already defined as JSON!" % (ext.name)) 1367 mandatoryFeatures = {} 1368 for requirement in apiFeature.requirementsList: 1369 featureStructName = None 1370 featureStruct = None 1371 for feature in requirement.features: 1372 newFeatureStructName = feature.struct 1373 for ct in self.compositeTypes: 1374 if newFeatureStructName in ct.aliasList: 1375 newFeatureStructName = ct.name 1376 if newFeatureStructName not in mandatoryFeatures.keys(): 1377 mandatoryFeatures[newFeatureStructName] = [] 1378 if newFeatureStructName != featureStructName: 1379 featureStructName = newFeatureStructName 1380 featureStruct = {'features': [], 'requirements': []} 1381 mandatoryFeatures[featureStructName].append(featureStruct) 1382 featureStruct['features'].append(feature.name) 1383 # if feature.name == "vulkanMemoryModel": 1384 # logging.debug("feature %s %s in %s" % (feature.name, featureStructName, apiFeature.name)) 1385 # exit(-1) 1386 dep = apiFeature.name 1387 if 'VK_VERSION' in dep: 1388 major = int(dep[-3]) 1389 minor = int(dep[-1]) 1390 featureStruct['requirements'].append(f"ApiVersion(0, {major}, {minor}, 0)") 1391 else: 1392 logging.error("requirement not valid in %s" % (apiFeature.name)) 1393 exit(-1) 1394 if featureStructName is not None: 1395 featureStruct['features'] = list(dict.fromkeys(featureStruct['features'])) 1396 featureStruct['requirements'] = list(dict.fromkeys(featureStruct['requirements'])) 1397 data = {'mandatory_features': mandatoryFeatures} 1398 jsonFilePath = os.path.join(SCRIPTS_SRC_DIR, "extensions", apiFeature.name + ".json") 1399 with open(jsonFilePath, 'w') as file: 1400 printAttributesToFile(data, file, indent=4) 1401 logging.debug("File written to " + jsonFilePath) 1402 api.additionalExtensionData.append((apiFeature.name, data)) 1403 1404 self.additionalExtensionData = sorted(self.additionalExtensionData, key=lambda e: e[0]) 1405 1406def prefixName (prefix, name): 1407 name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name[2:]) 1408 name = re.sub(r'([a-zA-Z])([0-9])', r'\1_\2', name) 1409 name = name.upper() 1410 return prefix + name 1411 1412def parseInt (value): 1413 return int(value, 16 if ("0x" in value) else 10) 1414 1415def readFile (filename): 1416 with open(filename, 'rt') as f: 1417 return f.read() 1418 1419def getInterfaceName (functionName): 1420 assert functionName[:2] == "vk" 1421 return functionName[2].lower() + functionName[3:] 1422 1423def getFunctionTypeName (functionName): 1424 assert functionName[:2] == "vk" 1425 return functionName[2:] + "Func" 1426 1427def endsWith (str, postfix): 1428 return str[-len(postfix):] == postfix 1429 1430def writeHandleType (api, filename): 1431 1432 def getHandleName (name): 1433 return prefixName("HANDLE_TYPE_", name) 1434 1435 def genHandles (): 1436 yield "\t%s\t= 0," % getHandleName(api.handles[0].name) 1437 for h in api.handles[1:]: 1438 yield "\t%s," % getHandleName(h.name) 1439 for h in api.handles: 1440 if h.alias is not None: 1441 yield "\t%s\t= %s," % (getHandleName(h.alias), getHandleName(h.name)) 1442 yield "\tHANDLE_TYPE_LAST\t= %s + 1" % (getHandleName(api.handles[-1].name)) 1443 1444 def genHandlesBlock (): 1445 yield "enum HandleType" 1446 yield "{" 1447 1448 for line in indentLines(genHandles()): 1449 yield line 1450 1451 yield "};" 1452 yield "" 1453 1454 writeInlFile(filename, INL_HEADER, genHandlesBlock()) 1455 1456def getEnumValuePrefixAndPostfix (enum): 1457 prefix = enum.name[0] 1458 for i in range(1, len(enum.name)): 1459 if enum.name[i].isupper() and not enum.name[i-1].isupper(): 1460 prefix += "_" 1461 prefix += enum.name[i].upper() 1462 for p in EXTENSION_POSTFIXES: 1463 if prefix.endswith(p): 1464 return prefix[:-len(p)-1], '_'+p 1465 return prefix, '' 1466 1467def genEnumSrc (enum): 1468 yield "enum %s" % enum.name 1469 yield "{" 1470 lines = [] 1471 for ed in enum.enumeratorList: 1472 if ed.value is not None: 1473 lines.append(f"\t{ed.name}\t= {ed.value},") 1474 for ed in enum.enumeratorList: 1475 for alias in ed.aliasList: 1476 lines.append(f"\t{alias}\t= {ed.name},") 1477 1478 # add *_LAST item when enum is linear 1479 prefix, postfix = getEnumValuePrefixAndPostfix(enum) 1480 if enum.areValuesLinear(): 1481 lines.append(f"\t{prefix}{postfix}_LAST,") 1482 1483 # add _MAX_ENUM item with the ext postifix at the end 1484 lines.append(f"\t{prefix}_MAX_ENUM{postfix}\t= 0x7FFFFFFF") 1485 1486 for line in indentLines(lines): 1487 yield line 1488 1489 yield "};" 1490 1491def genBitfieldSrc (bitfield): 1492 lines = [] 1493 for ev in bitfield.enumeratorList: 1494 # bitfields may use mix of bitpos and values 1495 if ev.bitpos is not None: 1496 value = pow(2, int(ev.bitpos)) 1497 lines.append(f"\t{ev.name}\t= {value:#010x},") 1498 if ev.value is not None: 1499 lines.append(f"\t{ev.name}\t= {ev.value},") 1500 for ev in bitfield.enumeratorList: 1501 for alias in ev.aliasList: 1502 lines.append(f"\t{alias}\t= {ev.name},") 1503 # add _MAX_ENUM item 1504 prefix, postfix = getEnumValuePrefixAndPostfix(bitfield) 1505 lines.append(f"\t{prefix}_MAX_ENUM{postfix}\t= 0x7FFFFFFF") 1506 yield f"enum {bitfield.name}" 1507 yield "{" 1508 for line in indentLines(lines): 1509 yield line 1510 yield "};" 1511 1512def genBitfield64Src (bitfield64): 1513 def generateEntry(lines, bitfieldName, entryName, bitpos, value): 1514 if entryName is None: 1515 return 1516 # bitfields may use mix of bitpos and values 1517 if ev.bitpos is not None: 1518 v = pow(2, int(bitpos)) 1519 lines.append(f"static const {bitfieldName} {entryName}\t= {v:#010x}ULL;") 1520 if value is not None: 1521 lines.append(f"static const {bitfieldName} {entryName}\t= {value}ULL;") 1522 1523 yield f"typedef uint64_t {bitfield64.name};" 1524 lines = [] 1525 for ev in bitfield64.enumeratorList: 1526 generateEntry(lines, bitfield64.name, ev.name, ev.bitpos, ev.value) 1527 for alias in ev.aliasList: 1528 generateEntry(lines, bitfield64.name, alias, ev.bitpos, ev.value) 1529 # write indented lines 1530 for line in indentLines(lines): 1531 yield line 1532 yield "" 1533 1534def genDefinesSrc (apiName, defines): 1535 def genLines (defines): 1536 for d in defines: 1537 if d.alias is not None: 1538 continue 1539 defineType = DEFINITIONS.get(d.name, d.type) 1540 yield f"#define {d.name}\t(static_cast<{defineType}>\t({d.value}))" 1541 for line in indentLines(genLines(defines)): 1542 yield line 1543 # add VK_API_MAX_FRAMEWORK_VERSION 1544 major, minor = 1, 0 1545 # In vk.xml, vulkan features (1.1, 1.2, 1.3) are marked as vulkan,vulkansc 1546 api_feature_name = "vulkan,vulkansc" if api.apiName == "vulkan" else api.apiName 1547 sorted_features = reversed(sorted(api.features, key=lambda feature: feature.number)) 1548 for feature in sorted_features: 1549 if feature.api == api_feature_name: 1550 major, minor = feature.number.split('.') 1551 break 1552 logging.debug("Found max framework version for API '%s': %s.%s" % (api.apiName, major, minor)) 1553 yield f"#define VK{apiName}_API_MAX_FRAMEWORK_VERSION\tVK{apiName}_API_VERSION_{major}_{minor}" 1554 1555def genHandlesSrc (handles): 1556 def genLines (handles): 1557 for h in handles: 1558 handleType = h.type 1559 handleObjtype = h.objtypeenum 1560 if h.alias is not None: 1561 # search for aliased handle 1562 for searchedHandle in handles: 1563 if h.alias == searchedHandle.name: 1564 handleType = searchedHandle.type 1565 handleObjtype = searchedHandle.objtypeenum 1566 break 1567 yield f"{handleType}\t({h.name},\tHANDLE{handleObjtype[9:]});" 1568 for line in indentLines(genLines(handles)): 1569 yield line 1570 1571def genHandlesSrc (handles): 1572 def genLines (handles): 1573 for h in handles: 1574 handleType = h.type 1575 handleObjtype = h.objtypeenum 1576 line = f"{handleType}\t({{}},\tHANDLE{handleObjtype[9:]});" 1577 yield line.format(h.name) 1578 if h.alias is not None: 1579 yield line.format(h.alias) 1580 1581 for line in indentLines(genLines(handles)): 1582 yield line 1583 1584def writeBasicTypes (api, filename): 1585 1586 def gen (): 1587 yield "// Defines" 1588 for line in genDefinesSrc("SC" if api.apiName == "vulkansc" else "", api.defines): 1589 yield line 1590 yield "" 1591 1592 yield "// Handles" 1593 for line in genHandlesSrc(api.handles): 1594 yield line 1595 yield "" 1596 1597 yield "// Enums" 1598 for enum in api.enums: 1599 # skip empty enums only for vulkan 1600 # vulkan_json_data.hpp and vulkan_json_parser.hpp in SC need many empty enums 1601 if len(enum.enumeratorList) == 0 and api.apiName == "vulkan": 1602 continue 1603 if enum.type == "bitmask": 1604 if enum.bitwidth == "32": 1605 for line in genBitfieldSrc(enum): 1606 yield line 1607 else: 1608 for line in genBitfield64Src(enum): 1609 yield line 1610 else: 1611 for line in genEnumSrc(enum): 1612 yield line 1613 if enum.alias is not None: 1614 yield f"typedef {enum.name} {enum.alias};" 1615 yield "" 1616 1617 yield "// Bitmasks" 1618 for bitmask in api.bitmasks: 1619 plainType = api.basetypes[bitmask.type] 1620 yield f"typedef {plainType} {bitmask.name};\n" 1621 if bitmask.alias: 1622 yield f"typedef {bitmask.name} {bitmask.alias};\n" 1623 1624 yield "" 1625 for line in indentLines(["VK_DEFINE_PLATFORM_TYPE(%s,\t%s)" % (s[0], c) for n, s, c in PLATFORM_TYPES]): 1626 yield line 1627 yield "" 1628 1629 yield "// Extensions" 1630 for ext in api.extensions: 1631 firstRequirementEnums = ext.requirementsList[0].extendedEnums 1632 for e in firstRequirementEnums: 1633 if e.extends is None and e.value is not None: 1634 yield "#define " + e.name + " " + e.value 1635 1636 writeInlFile(filename, INL_HEADER, gen()) 1637 1638def writeCompositeTypes (api, filename): 1639 # function that returns definition of structure member 1640 def memberAsString (member): 1641 result = '' 1642 if member.qualifiers: 1643 result += member.qualifiers 1644 result += member.type 1645 if member.pointer: 1646 result += member.pointer 1647 result += '\t' + member.name 1648 for size in member.arraySizeList: 1649 result += f"[{size}]" 1650 if member.fieldWidth: 1651 result += f":{member.fieldWidth}" 1652 return result 1653 1654 # function that prints single structure definition 1655 def genCompositeTypeSrc (type): 1656 structLines = "%s %s\n{\n" % (type.category, type.name) 1657 for line in indentLines(['\t'+memberAsString(m)+';' for m in type.members]): 1658 structLines += line + '\n' 1659 return structLines + "};\n" 1660 1661 # function that prints all structure definitions and alias typedefs 1662 def gen (): 1663 # structures in xml are not ordered in a correct way for C++ 1664 # we need to save structures that are used in other structures first 1665 allStructureNamesList = [s.name for s in api.compositeTypes] 1666 commonTypesList = api.basicCTypes + ['VkStructureType'] 1667 savedStructureNamesList = [] 1668 delayedStructureObjectsList = [] 1669 1670 # helper function that checks if all structure members were already saved 1671 def canStructBeSaved(compositeObject): 1672 for m in compositeObject.members: 1673 # check first commonTypesList to speed up the algorithm 1674 if m.type in commonTypesList: 1675 continue 1676 # make sure that member is not of same type as compositeObject 1677 # (this hadles cases like VkBaseOutStructure) 1678 if m.type == compositeObject.name: 1679 continue 1680 # if member is of compositeType that was not saved we cant save it now 1681 if m.type in allStructureNamesList and m.type not in savedStructureNamesList: 1682 return False 1683 return True 1684 1685 # iterate over all composite types 1686 lastDelayedComposite = None 1687 for ct in api.compositeTypes: 1688 # check if one of delayed structures can be saved 1689 delayedButSaved = [] 1690 for dct in delayedStructureObjectsList: 1691 if lastDelayedComposite != dct and canStructBeSaved(dct): 1692 yield genCompositeTypeSrc(dct) 1693 delayedButSaved.append(dct) 1694 lastDelayedComposite = None 1695 for dsct in delayedButSaved: 1696 savedStructureNamesList.append(dsct.name) 1697 delayedStructureObjectsList.remove(dsct) 1698 # check if current structure can be saved 1699 if canStructBeSaved(ct): 1700 yield genCompositeTypeSrc(ct) 1701 savedStructureNamesList.append(ct.name) 1702 else: 1703 delayedStructureObjectsList.append(ct) 1704 # memorize structure that was delayed in last iteration to 1705 # avoid calling for it canStructBeSaved in next iteration 1706 lastDelayedComposite = ct 1707 # save remaining delayed composite types (~4 video related structures) 1708 while len(delayedStructureObjectsList) > 0: 1709 for dct in delayedStructureObjectsList: 1710 if canStructBeSaved(dct): 1711 yield genCompositeTypeSrc(dct) 1712 savedStructureNamesList.append(dct.name) 1713 delayedStructureObjectsList.remove(dct) 1714 break 1715 # write all alias typedefs 1716 for ct in api.compositeTypes: 1717 for alias in ct.aliasList: 1718 yield "typedef %s %s;" % (ct.name, alias) 1719 yield "" 1720 1721 writeInlFile(filename, INL_HEADER, gen()) 1722 1723def argListToStr (args): 1724 def argumentToString(arg): 1725 # args can be instance of FunctionArgument or CompositeMember 1726 # but CompositeMember has no arraySize atrribute nor secondPointerIsConst 1727 workingOnFunctionArgument = True if hasattr(arg, 'arraySize') else False 1728 result = '' 1729 if arg.qualifiers: 1730 result += arg.qualifiers 1731 result += arg.type 1732 if arg.pointer: 1733 if workingOnFunctionArgument and arg.secondPointerIsConst: 1734 result += '* const*' 1735 else: 1736 result += arg.pointer 1737 result += ' ' + arg.name 1738 if workingOnFunctionArgument: 1739 if arg.arraySize: 1740 result += arg.arraySize 1741 return result 1742 return ", ".join(argumentToString(arg) for arg in args) 1743 1744def writeInterfaceDecl (api, filename, functionTypes, concrete): 1745 def genProtos (): 1746 postfix = "" if concrete else " = 0" 1747 for function in api.functions: 1748 if not function.getType() in functionTypes: 1749 continue 1750 yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments), postfix) 1751 1752 writeInlFile(filename, INL_HEADER, indentLines(genProtos())) 1753 1754def writeFunctionPtrTypes (api, filename): 1755 def genTypes (): 1756 pattern = "typedef VKAPI_ATTR {}\t(VKAPI_CALL* {})\t({});" 1757 for function in api.functions: 1758 argList = argListToStr(function.arguments) 1759 yield pattern.format(function.returnType, getFunctionTypeName(function.name), argList) 1760 for alias in function.aliasList: 1761 yield pattern.format(function.returnType, getFunctionTypeName(alias), argList) 1762 1763 writeInlFile(filename, INL_HEADER, indentLines(genTypes())) 1764 1765def writeFunctionPointers (api, filename, functionTypes): 1766 def FunctionsYielder (): 1767 for function in api.functions: 1768 if function.getType() in functionTypes: 1769 interfaceName = getInterfaceName(function.name) 1770 functionTypeName = getFunctionTypeName(function.name) 1771 yield f"{functionTypeName}\t{interfaceName};" 1772 if function.getType() == Function.TYPE_INSTANCE: 1773 for alias in function.aliasList: 1774 interfaceName = getInterfaceName(alias) 1775 functionTypeName = getFunctionTypeName(alias) 1776 yield f"{functionTypeName}\t{interfaceName};" 1777 1778 writeInlFile(filename, INL_HEADER, indentLines(FunctionsYielder())) 1779 1780def getPromotedFunctions (api): 1781 apiNum = 0 if api.apiName == "vulkan" else 1 1782 promotedFunctions = collections.defaultdict(lambda: list()) 1783 for feature in api.features: 1784 versionSplit = feature.name.split('_') 1785 apiMajor = int(versionSplit[-2]) 1786 apiMinor = int(versionSplit[-1]) 1787 apiPrefix = '_'.join(versionSplit[:-2]) 1788 if apiNum == 0 and apiPrefix != 'VK_VERSION': 1789 continue 1790 if apiNum == 1 and apiPrefix == 'VK_VERSION': 1791 # Map of "standard" Vulkan versions to VulkanSC version. 1792 stdToSCMap = { 1793 (1, 0): (1, 0), 1794 (1, 1): (1, 0), 1795 (1, 2): (1, 0), 1796 } 1797 mapKey = (apiMajor, apiMinor) 1798 if mapKey not in stdToSCMap: 1799 continue 1800 (apiMajor, apiMinor) = stdToSCMap[mapKey] 1801 apituple = (apiNum, apiMajor, apiMinor) 1802 for featureRequirement in feature.requirementsList: 1803 for promotedFun in featureRequirement.commandList: 1804 promotedFunctions[promotedFun].append(apituple) 1805 return promotedFunctions 1806 1807def writeInitFunctionPointers (api, filename, functionTypes, cond = None): 1808 promotedFunctions = getPromotedFunctions(api) if Function.TYPE_DEVICE in functionTypes else None 1809 def makeInitFunctionPointers (): 1810 for function in api.functions: 1811 if function.getType() in functionTypes and (cond == None or cond(function)): 1812 condition = '' 1813 if function.getType() == Function.TYPE_DEVICE: 1814 versionCheck = '' 1815 if function.name in promotedFunctions: 1816 for versionTuple in promotedFunctions[function.name]: 1817 if len(versionCheck) > 0: 1818 versionCheck += ' || ' 1819 versionCheck = 'usedApiVersion >= VK_MAKE_API_VERSION(%s, %s, %s, 0)' % versionTuple 1820 if len(versionCheck) > 0: 1821 condition = f"if ({versionCheck})\n " 1822 interfaceName = getInterfaceName(function.name) 1823 functionTypeName = getFunctionTypeName(function.name) 1824 yield f"{condition}m_vk.{interfaceName} = ({functionTypeName}) GET_PROC_ADDR(\"{function.name}\");" 1825 for alias in function.aliasList: 1826 yield f"if (!m_vk.{interfaceName})" 1827 yield f" m_vk.{interfaceName} = ({functionTypeName}) GET_PROC_ADDR(\"{alias}\");" 1828 if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].type == "VkPhysicalDevice": 1829 interfaceName = getInterfaceName(alias) 1830 functionTypeName = getFunctionTypeName(alias) 1831 yield f"m_vk.{interfaceName} = ({functionTypeName}) GET_PROC_ADDR(\"{alias}\");" 1832 1833 lines = makeInitFunctionPointers() 1834 writeInlFile(filename, INL_HEADER, lines) 1835 1836# List pre filled manually with commands forbidden for computation only implementations 1837computeOnlyForbiddenCommands = [ 1838 "destroyRenderPass", 1839 "createRenderPass2", 1840 "createRenderPass", 1841 "createGraphicsPipelines" 1842] 1843 1844computeOnlyRestrictedCommands = { 1845 "createComputePipelines" : "\t\tfor (uint32_t i=0; i<createInfoCount; ++i)\n\t\t\tif ((pCreateInfos[i].stage.stage & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) THROW_NOT_SUPPORTED_COMPUTE_ONLY();", 1846 "createBuffer" : "\t\tif ((pCreateInfo->usage & ( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT )) !=0) THROW_NOT_SUPPORTED_COMPUTE_ONLY();", 1847} 1848 1849def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className): 1850 1851 # populate compute only forbidden commands 1852 for fun in api.functions: 1853 if "graphics" in fun.queuesList and "compute" not in fun.queuesList: 1854 # remove the 'vk' prefix and change the first character of the remaining string to lowercase 1855 commandName = fun.name[2:3].lower() + fun.name[3:] 1856 computeOnlyForbiddenCommands.append(commandName) 1857 1858 # if the command has an alias, also add it 1859 for alias_name in fun.aliasList: 1860 alias_name_without_vk = alias_name[2:3].lower() + alias_name[3:] 1861 computeOnlyForbiddenCommands.append(alias_name_without_vk) 1862 1863 def makeFuncPtrInterfaceImpl (): 1864 for function in api.functions: 1865 functionInterfaceName = getInterfaceName(function.name) 1866 if function.getType() in functionTypes: 1867 yield "" 1868 yield "%s %s::%s (%s) const" % (function.returnType, className, functionInterfaceName, argListToStr(function.arguments)) 1869 yield "{" 1870 # Check for compute only forbidden commands 1871 if functionInterfaceName in computeOnlyForbiddenCommands: 1872 yield " if( m_computeOnlyMode ) THROW_NOT_SUPPORTED_COMPUTE_ONLY();" 1873 # Check for compute only restricted commands 1874 if functionInterfaceName in computeOnlyRestrictedCommands: 1875 yield "\tif( m_computeOnlyMode )" 1876 yield "\t{" 1877 yield computeOnlyRestrictedCommands[functionInterfaceName] 1878 yield "\t}" 1879 # Special case for vkEnumerateInstanceVersion 1880 if function.name == "vkEnumerateInstanceVersion": 1881 yield " if (m_vk.enumerateInstanceVersion)" 1882 yield " return m_vk.enumerateInstanceVersion(pApiVersion);" 1883 yield "" 1884 yield " *pApiVersion = VK_API_VERSION_1_0;" 1885 yield " return VK_SUCCESS;" 1886 yield "}" 1887 continue 1888 # Simplify code by preparing string template needed in few code branches 1889 tab = ' ' * 4 1890 funReturn = "" if function.returnType == "void" else "return " 1891 funParams = ", ".join(a.name for a in function.arguments) 1892 callTemplate = f"{tab}{funReturn}m_vk.{{}}({funParams});" 1893 # Special case for all instance functions that operate on VkPhysicalDevice 1894 if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].type == "VkPhysicalDevice": 1895 # Helper function that checks if entry point was promoted to core 1896 def isInCore(allFunAliases): 1897 for feature in api.features: 1898 if api.apiName not in feature.api.split(','): 1899 continue 1900 for r in feature.requirementsList: 1901 for n in allFunAliases: 1902 if n in r.commandList: 1903 return (True, feature.number) 1904 return (False, "1.0") 1905 (inCore, coreNumber) = isInCore([function.name] + function.aliasList) 1906 if inCore and "1.0" not in coreNumber: 1907 callTemplate = f"{tab}{callTemplate}" 1908 yield " vk::VkPhysicalDeviceProperties props;" 1909 yield " m_vk.getPhysicalDeviceProperties(physicalDevice, &props);" 1910 yield f" if (props.apiVersion >= VK_API_VERSION_{coreNumber.replace('.', '_')})" 1911 yield callTemplate.format(functionInterfaceName) 1912 yield " else" 1913 yield callTemplate.format(getInterfaceName(function.aliasList[0])) 1914 yield "}" 1915 continue 1916 yield callTemplate.format(functionInterfaceName) 1917 yield "}" 1918 writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl()) 1919 1920def writeFuncPtrInterfaceSCImpl (api, filename, functionTypes, className): 1921 normFuncs = { 1922 "createGraphicsPipelines" : "\t\treturn createGraphicsPipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1923 "createComputePipelines" : "\t\treturn createComputePipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1924 "createSampler" : "\t\treturn createSamplerHandlerNorm(device, pCreateInfo, pAllocator, pSampler);", 1925 "createSamplerYcbcrConversion" : "\t\treturn createSamplerYcbcrConversionHandlerNorm(device, pCreateInfo, pAllocator, pYcbcrConversion);", 1926 "createDescriptorSetLayout" : "\t\treturn createDescriptorSetLayoutHandlerNorm(device, pCreateInfo, pAllocator, pSetLayout);", 1927 "createPipelineLayout" : "\t\treturn createPipelineLayoutHandlerNorm(device, pCreateInfo, pAllocator, pPipelineLayout);", 1928 "createRenderPass" : "\t\treturn createRenderPassHandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);", 1929 "createRenderPass2" : "\t\treturn createRenderPass2HandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);", 1930 "createCommandPool" : "\t\treturn createCommandPoolHandlerNorm(device, pCreateInfo, pAllocator, pCommandPool);", 1931 "resetCommandPool" : "\t\treturn resetCommandPoolHandlerNorm(device, commandPool, flags);", 1932 "createFramebuffer" : "\t\treturn createFramebufferHandlerNorm(device, pCreateInfo, pAllocator, pFramebuffer);", 1933 } 1934 statFuncs = { 1935 "destroyDevice" : "\t\tdestroyDeviceHandler(device, pAllocator);", 1936 "createDescriptorSetLayout" : "\t\tcreateDescriptorSetLayoutHandlerStat(device, pCreateInfo, pAllocator, pSetLayout);", 1937 "destroyDescriptorSetLayout" : "\t\tdestroyDescriptorSetLayoutHandler(device, descriptorSetLayout, pAllocator);", 1938 "createImageView" : "\t\tcreateImageViewHandler(device, pCreateInfo, pAllocator, pView);", 1939 "destroyImageView" : "\t\tdestroyImageViewHandler(device, imageView, pAllocator);", 1940 "createSemaphore" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(semaphoreRequestCount,1);\n\t\t*pSemaphore = m_resourceInterface->incResourceCounter<VkSemaphore>();\n\t}", 1941 "destroySemaphore" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(semaphore,semaphoreRequestCount,1);\n\t}", 1942 "createFence" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(fenceRequestCount,1);\n\t\t*pFence = m_resourceInterface->incResourceCounter<VkFence>();\n\t}", 1943 "destroyFence" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(fence,fenceRequestCount,1);\n\t}", 1944 "allocateMemory" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(deviceMemoryRequestCount,1);\n\t\t*pMemory = m_resourceInterface->incResourceCounter<VkDeviceMemory>();\n\t}", 1945 "createBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferRequestCount,1);\n\t\t*pBuffer = m_resourceInterface->incResourceCounter<VkBuffer>();\n\t}", 1946 "destroyBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(buffer,bufferRequestCount,1);\n\t}", 1947 "createImage" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(imageRequestCount,1);\n\t\t*pImage = m_resourceInterface->incResourceCounter<VkImage>();\n\t}", 1948 "destroyImage" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(image,imageRequestCount,1);\n\t}", 1949 "createEvent" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(eventRequestCount,1);\n\t\t*pEvent = m_resourceInterface->incResourceCounter<VkEvent>();\n\t}", 1950 "destroyEvent" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(event,eventRequestCount,1);\n\t}", 1951 "createQueryPool" : "\t\tcreateQueryPoolHandler(device, pCreateInfo, pAllocator, pQueryPool);", 1952 "createBufferView" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferViewRequestCount,1);\n\t\t*pView = m_resourceInterface->incResourceCounter<VkBufferView>();\n\t}", 1953 "destroyBufferView" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(bufferView,bufferViewRequestCount,1);\n\t}", 1954 "createPipelineLayout" : "\t\tcreatePipelineLayoutHandlerStat(device, pCreateInfo, pAllocator, pPipelineLayout);", 1955 "destroyPipelineLayout" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineLayout,pipelineLayoutRequestCount,1);\n\t}", 1956 "createRenderPass" : "\t\tcreateRenderPassHandlerStat(device, pCreateInfo, pAllocator, pRenderPass);", 1957 "createRenderPass2" : "\t\tcreateRenderPass2HandlerStat(device, pCreateInfo, pAllocator, pRenderPass);", 1958 "destroyRenderPass" : "\t\tdestroyRenderPassHandler(device, renderPass, pAllocator);", 1959 "createGraphicsPipelines" : "\t\tcreateGraphicsPipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1960 "createComputePipelines" : "\t\tcreateComputePipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1961 "destroyPipeline" : "\t\tdestroyPipelineHandler(device, pipeline, pAllocator);", 1962 "createSampler" : "\t\tcreateSamplerHandlerStat(device, pCreateInfo, pAllocator, pSampler);", 1963 "destroySampler" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(sampler,samplerRequestCount,1);\n\t}", 1964 "createDescriptorPool" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(descriptorPoolRequestCount,1);\n\t\t*pDescriptorPool = m_resourceInterface->incResourceCounter<VkDescriptorPool>();\n\t}", 1965 "resetDescriptorPool" : "\t\tresetDescriptorPoolHandlerStat(device, descriptorPool, flags);", 1966 "allocateDescriptorSets" : "\t\tallocateDescriptorSetsHandlerStat(device, pAllocateInfo, pDescriptorSets);", 1967 "freeDescriptorSets" : "\t\tfreeDescriptorSetsHandlerStat(device, descriptorPool, descriptorSetCount, pDescriptorSets);", 1968 "createFramebuffer" : "\t\tcreateFramebufferHandlerStat(device, pCreateInfo, pAllocator, pFramebuffer);", 1969 "destroyFramebuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(framebuffer,framebufferRequestCount,1);\n\t}", 1970 "createCommandPool" : "\t\tcreateCommandPoolHandlerStat(device, pCreateInfo, pAllocator, pCommandPool);", 1971 "resetCommandPool" : "\t\tresetCommandPoolHandlerStat(device, commandPool, flags);", 1972 "allocateCommandBuffers" : "\t\tallocateCommandBuffersHandler(device, pAllocateInfo, pCommandBuffers);", 1973 "freeCommandBuffers" : "\t\tfreeCommandBuffersHandler(device, commandPool, commandBufferCount, pCommandBuffers);", 1974 "createSamplerYcbcrConversion" : "\t\tcreateSamplerYcbcrConversionHandlerStat(device, pCreateInfo, pAllocator, pYcbcrConversion);", 1975 "destroySamplerYcbcrConversion" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(ycbcrConversion,samplerYcbcrConversionRequestCount,1);\n\t}", 1976 "getDescriptorSetLayoutSupport" : "\t\tgetDescriptorSetLayoutSupportHandler(device, pCreateInfo, pSupport);", 1977# "" : "surfaceRequestCount", 1978# "" : "swapchainRequestCount", 1979# "" : "displayModeRequestCount" 1980 "mapMemory" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tif(m_falseMemory.size() < (static_cast<std::size_t>(offset+size)))\n\t\t\tm_falseMemory.resize(static_cast<std::size_t>(offset+size));\n\t\t*ppData = (void*)m_falseMemory.data();\n\t}", 1981 "getBufferMemoryRequirements" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}", 1982 "getImageMemoryRequirements" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}", 1983 "getBufferMemoryRequirements2" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->memoryRequirements.size = 1048576U;\n\t\tpMemoryRequirements->memoryRequirements.alignment = 1U;\n\t\tpMemoryRequirements->memoryRequirements.memoryTypeBits = ~0U;\n\t}", 1984 "getImageMemoryRequirements2" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->memoryRequirements.size = 1048576U;\n\t\tpMemoryRequirements->memoryRequirements.alignment = 1U;\n\t\tpMemoryRequirements->memoryRequirements.memoryTypeBits = ~0U;\n\t}", 1985 "getImageSubresourceLayout" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpLayout->offset = 0U;\n\t\tpLayout->size = 1048576U;\n\t\tpLayout->rowPitch = 0U;\n\t\tpLayout->arrayPitch = 0U;\n\t\tpLayout->depthPitch = 0U;\n\t}", 1986 "createPipelineCache" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(pipelineCacheRequestCount,1);\n\t\t*pPipelineCache = m_resourceInterface->incResourceCounter<VkPipelineCache>();\n\t}", 1987 "destroyPipelineCache" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineCache,pipelineCacheRequestCount,1);\n\t}", 1988 "cmdUpdateBuffer" : "\t\tincreaseCommandBufferSize(commandBuffer, dataSize);", 1989 "getDeviceQueue" : "\t\tm_vk.getDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);", 1990 } 1991 1992 statReturns = { 1993 "VkResult" : "return VK_SUCCESS;", 1994 "VkDeviceAddress" : "return 0u;", 1995 "uint64_t" : "return 0u;", 1996 } 1997 1998 def makeFuncPtrInterfaceStatisticsImpl (): 1999 for function in api.functions: 2000 if function.getType() in functionTypes: 2001 ifaceName = getInterfaceName(function.name) 2002 yield "" 2003 yield "%s %s::%s (%s) const" % (function.returnType, className, ifaceName, argListToStr(function.arguments)) 2004 yield "{" 2005 # Check for compute only forbidden commands 2006 if ifaceName in computeOnlyForbiddenCommands: 2007 yield "\tif( m_computeOnlyMode ) THROW_NOT_SUPPORTED_COMPUTE_ONLY();" 2008 # Check for compute only restricted commands 2009 if ifaceName in computeOnlyRestrictedCommands: 2010 yield "\tif( m_computeOnlyMode )" 2011 yield "\t{" 2012 yield computeOnlyRestrictedCommands[ifaceName] 2013 yield "\t}" 2014 if ( ifaceName in normFuncs ) or ( ifaceName in statFuncs ): 2015 yield "\tstd::lock_guard<std::mutex> lock(functionMutex);" 2016 if ifaceName != "getDeviceProcAddr" : 2017 yield "\tif (m_normalMode)" 2018 if ifaceName in normFuncs : 2019 yield "%s" % ( normFuncs[ifaceName] ) 2020 else: 2021 yield "\t\t%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", ifaceName, ", ".join(a.name for a in function.arguments)) 2022 if ifaceName in statFuncs : 2023 yield "\telse" 2024 yield "%s" % ( statFuncs[ifaceName] ) 2025 elif ifaceName[:3] == "cmd" : 2026 yield "\telse" 2027 yield "\t\tincreaseCommandBufferSize(commandBuffer, 0u);" 2028 if function.returnType in statReturns: 2029 yield "\t%s" % ( statReturns[function.returnType] ) 2030 yield "}" 2031 2032 writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceStatisticsImpl()) 2033 2034def writeStrUtilProto (api, filename): 2035 def makeStrUtilProto (): 2036 for line in indentLines(["const char*\tget%sName\t(%s value);" % (enum.name[2:], enum.name) for enum in api.enums if enum.type == "enum"]): 2037 yield line 2038 yield "" 2039 for line in indentLines(["inline tcu::Format::Enum<%s>\tget%sStr\t(%s value)\t{ return tcu::Format::Enum<%s>(get%sName, value);\t}" % (e.name, e.name[2:], e.name, e.name, e.name[2:]) for e in api.enums if e.type == "enum"]): 2040 yield line 2041 yield "" 2042 for line in indentLines(["inline std::ostream&\toperator<<\t(std::ostream& s, %s value)\t{ return s << get%sStr(value);\t}" % (e.name, e.name[2:]) for e in api.enums if e.type == "enum"]): 2043 yield line 2044 yield "" 2045 for line in indentLines(["tcu::Format::Bitfield<%s>\tget%sStr\t(%s value);" % (("64" if b.type == "VkFlags64" else "32"), b.name[2:], b.name) for b in api.bitmasks]): 2046 yield line 2047 yield "" 2048 for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.compositeTypes]): 2049 yield line 2050 2051 writeInlFile(filename, INL_HEADER, makeStrUtilProto()) 2052 2053def writeStrUtilImpl (api, filename): 2054 def makeStrUtilImpl (): 2055 for line in indentLines(["template<> const char*\tgetTypeName<%s>\t(void) { return \"%s\";\t}" % (handle.name, handle.name) for handle in api.handles]): 2056 yield line 2057 2058 yield "" 2059 yield "namespace %s" % PLATFORM_TYPE_NAMESPACE 2060 yield "{" 2061 2062 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): 2063 yield line 2064 2065 yield "}" 2066 2067 savedBitmasks = [] 2068 for enum in api.enums: 2069 if enum.type == "enum": 2070 yield "" 2071 yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name) 2072 yield "{" 2073 yield "\tswitch (value)" 2074 yield "\t{" 2075 enumValues = [] 2076 lastValue = 0x7FFFFFFF 2077 for e in enum.enumeratorList: 2078 enumValues.append(f"\t\tcase {e.name}:\treturn \"{e.name}\";") 2079 enumValues.append("\t\tdefault:\treturn nullptr;") 2080 for line in indentLines(enumValues): 2081 yield line 2082 yield "\t}" 2083 yield "}" 2084 elif enum.type == "bitmask": 2085 # find bitfield that uses those bitmasks 2086 foundBitmask = None 2087 for bitmask in api.bitmasks: 2088 if bitmask.requires == enum.name or bitmask.bitvalues == enum.name: 2089 foundBitmask = bitmask 2090 break 2091 if foundBitmask == None: 2092 continue 2093 savedBitmasks.append(foundBitmask.name) 2094 bitSize = "64" if foundBitmask.type == "VkFlags64" else "32" 2095 yield "" 2096 yield f"tcu::Format::Bitfield<{bitSize}> get{bitmask.name[2:]}Str ({bitmask.name} value)" 2097 yield "{" 2098 yield "\tstatic const tcu::Format::BitDesc s_desc[] =" 2099 yield "\t{" 2100 if len(enum.enumeratorList) == 0: 2101 # some bitfields in SC have no items 2102 yield f"\t\ttcu::Format::BitDesc(0, \"0\")" 2103 else: 2104 for line in indentLines([f"\t\ttcu::Format::BitDesc({e.name},\t\"{e.name}\")," for e in enum.enumeratorList]): 2105 yield line 2106 yield "\t};" 2107 yield f"\treturn tcu::Format::Bitfield<{bitSize}>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));" 2108 yield "}" 2109 2110 for bitmask in api.bitmasks: 2111 if bitmask.name not in savedBitmasks: 2112 bitSize = "64" if bitmask.type == "VkFlags64" else "32" 2113 yield "" 2114 yield f"tcu::Format::Bitfield<{bitSize}> get{bitmask.name[2:]}Str ({bitmask.name} value)" 2115 yield "{" 2116 yield f"\treturn tcu::Format::Bitfield<{bitSize}>(value, nullptr, nullptr);" 2117 yield "}" 2118 2119 bitfieldTypeNames = set([bitmask.name for bitmask in api.bitmasks]) 2120 2121 for type in api.compositeTypes: 2122 yield "" 2123 yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % type.name 2124 yield "{" 2125 yield "\ts << \"%s = {\\n\";" % type.name 2126 for member in type.members: 2127 memberName = member.name 2128 valFmt = None 2129 newLine = "" 2130 if member.type in bitfieldTypeNames: 2131 operator = '*' if member.pointer == '*' else '' 2132 valFmt = "get%sStr(%svalue.%s)" % (member.type[2:], operator, member.name) 2133 elif member.type == "char" and member.pointer == '*': 2134 valFmt = "getCharPtrStr(value.%s)" % member.name 2135 elif member.type == PLATFORM_TYPE_NAMESPACE + "::Win32LPCWSTR": 2136 valFmt = "getWStr(value.%s)" % member.name 2137 elif len(member.arraySizeList) == 1: 2138 if member.name in ["extensionName", "deviceName", "layerName", "description"]: 2139 valFmt = "(const char*)value.%s" % member.name 2140 elif member.type == 'char' or member.type == 'uint8_t': 2141 newLine = "'\\n' << " 2142 valFmt = "tcu::formatArray(tcu::Format::HexIterator<%s>(DE_ARRAY_BEGIN(value.%s)), tcu::Format::HexIterator<%s>(DE_ARRAY_END(value.%s)))" % (member.type, member.name, member.type, member.name) 2143 else: 2144 if member.name == "memoryTypes" or member.name == "memoryHeaps": 2145 endIter = "DE_ARRAY_BEGIN(value.%s) + value.%sCount" % (member.name, member.name[:-1]) 2146 else: 2147 endIter = "DE_ARRAY_END(value.%s)" % member.name 2148 newLine = "'\\n' << " 2149 valFmt = "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), %s)" % (member.name, endIter) 2150 memberName = member.name 2151 elif len(member.arraySizeList) > 1: 2152 yield f"\ts << \"\\t{member.name} = \" << '\\n';" 2153 dim = 0 2154 index = '' 2155 dimensionCount = len(member.arraySizeList) 2156 while dim < dimensionCount-1: 2157 yield f"\tfor(uint32_t i{dim} = 0 ; i{dim} < {member.arraySizeList[dim]} ; ++i{dim})" 2158 index += f"[i{dim}]" 2159 dim +=1 2160 yield f"\t\ts << tcu::formatArray(DE_ARRAY_BEGIN(value.{member.name}{index}), DE_ARRAY_END(value.{member.name}{index})) << '\\n';" 2161 # move to next member 2162 continue 2163 else: 2164 valFmt = "value.%s" % member.name 2165 yield ("\ts << \"\\t%s = \" << " % memberName) + newLine + valFmt + " << '\\n';" 2166 yield "\ts << '}';" 2167 yield "\treturn s;" 2168 yield "}" 2169 writeInlFile(filename, INL_HEADER, makeStrUtilImpl()) 2170 2171def writeObjTypeImpl (api, filename): 2172 def makeObjTypeImpl (): 2173 2174 yield "namespace vk" 2175 yield "{" 2176 2177 yield "template<typename T> VkObjectType getObjectType (void);" 2178 2179 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]): 2180 yield line 2181 2182 yield "}" 2183 2184 writeInlFile(filename, INL_HEADER, makeObjTypeImpl()) 2185 2186class ConstructorFunction: 2187 def __init__ (self, type, name, objectType, ifaceArgs, arguments): 2188 self.type = type 2189 self.name = name 2190 self.objectType = objectType 2191 self.ifaceArgs = ifaceArgs 2192 self.arguments = arguments 2193 2194def getConstructorFunctions (api): 2195 funcs = [] 2196 2197 ifacesDict = { 2198 Function.TYPE_PLATFORM: [FunctionArgument("vk", "const ", "PlatformInterface&")], 2199 Function.TYPE_INSTANCE: [FunctionArgument("vk", "const ", "InstanceInterface&")], 2200 Function.TYPE_DEVICE: [FunctionArgument("vk", "const ", "DeviceInterface&")]} 2201 2202 for function in api.functions: 2203 if (function.name[:8] == "vkCreate" or function.name == "vkAllocateMemory") and not "createInfoCount" in [a.name for a in function.arguments]: 2204 if function.name in ["vkCreatePipelineBinariesKHR", "vkCreateDisplayModeKHR"]: 2205 continue # No way to delete display modes (bug?) 2206 2207 ifaceArgs = [] 2208 if function.name == "vkCreateDevice": 2209 ifaceArgs = [FunctionArgument("vkp", "const ", "PlatformInterface&"), 2210 FunctionArgument("instance", "", "VkInstance")] 2211 ifaceArgs.extend(ifacesDict[function.getType()]) 2212 2213 allocatorArg = function.arguments[-2] 2214 assert (allocatorArg.type == "VkAllocationCallbacks" and \ 2215 "const" in allocatorArg.qualifiers and \ 2216 allocatorArg.pointer == "*") 2217 2218 objectType = function.arguments[-1].type 2219 arguments = function.arguments[:-1] 2220 funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function.name), objectType, ifaceArgs, arguments)) 2221 return funcs 2222 2223def addVersionDefines(versionSpectrum): 2224 output = ["#define " + ver.getDefineName() + " " + ver.getInHex() for ver in versionSpectrum if not ver.isStandardVersion()] 2225 return output 2226 2227def writeRefUtilProto (api, filename): 2228 functions = getConstructorFunctions(api) 2229 2230 def makeRefUtilProto (): 2231 unindented = [] 2232 for line in indentLines(["Move<%s>\t%s\t(%s = nullptr);" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments)) for function in functions]): 2233 yield line 2234 2235 writeInlFile(filename, INL_HEADER, makeRefUtilProto()) 2236 2237def writeRefUtilImpl (api, filename): 2238 functions = getConstructorFunctions(api) 2239 2240 def makeRefUtilImpl (): 2241 yield "namespace refdetails" 2242 yield "{" 2243 yield "" 2244 2245 for function in api.functions: 2246 if function.getType() == Function.TYPE_DEVICE \ 2247 and (function.name[:9] == "vkDestroy" or function.name == "vkFreeMemory") \ 2248 and not function.name == "vkDestroyDevice": 2249 objectType = function.arguments[-2].type 2250 yield "template<>" 2251 yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType) 2252 yield "{" 2253 yield "\tm_deviceIface->%s(m_device, obj, m_allocator);" % (getInterfaceName(function.name)) 2254 yield "}" 2255 yield "" 2256 2257 yield "} // refdetails" 2258 yield "" 2259 2260 dtorDict = { 2261 Function.TYPE_PLATFORM: "object", 2262 Function.TYPE_INSTANCE: "instance", 2263 Function.TYPE_DEVICE: "device" 2264 } 2265 2266 for function in functions: 2267 deleterArgsString = '' 2268 if function.name == "createDevice": 2269 # createDevice requires two additional parameters to setup VkDevice deleter 2270 deleterArgsString = "vkp, instance, object, " + function.arguments[-1].name 2271 else: 2272 deleterArgsString = "vk, %s, %s" % (dtorDict[function.type], function.arguments[-1].name) 2273 2274 yield "Move<%s> %s (%s)" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments)) 2275 yield "{" 2276 yield "\t%s object = VK_NULL_HANDLE;" % function.objectType 2277 yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"])) 2278 yield "\treturn Move<%s>(check<%s>(object), Deleter<%s>(%s));" % (function.objectType, function.objectType, function.objectType, deleterArgsString) 2279 yield "}" 2280 yield "" 2281 2282 writeInlFile(filename, INL_HEADER, makeRefUtilImpl()) 2283 2284def writeStructTraitsImpl (api, filename): 2285 def gen (): 2286 for cType in api.compositeTypes: 2287 if cType.category == "struct" and cType.members[0].name == "sType" and cType.name != "VkBaseOutStructure" and cType.name != "VkBaseInStructure": 2288 yield "template<> VkStructureType getStructureType<%s> (void)" % cType.name 2289 yield "{" 2290 yield "\treturn %s;" % cType.members[0].values 2291 yield "}" 2292 yield "" 2293 2294 writeInlFile(filename, INL_HEADER, gen()) 2295 2296def writeNullDriverImpl (api, filename): 2297 def genNullDriverImpl (): 2298 specialFuncNames = [ 2299 "vkCreateGraphicsPipelines", 2300 "vkCreateComputePipelines", 2301 "vkCreateRayTracingPipelinesNV", 2302 "vkCreateRayTracingPipelinesKHR", 2303 "vkGetInstanceProcAddr", 2304 "vkGetDeviceProcAddr", 2305 "vkEnumeratePhysicalDevices", 2306 "vkEnumerateInstanceExtensionProperties", 2307 "vkEnumerateDeviceExtensionProperties", 2308 "vkGetPhysicalDeviceFeatures", 2309 "vkGetPhysicalDeviceFeatures2KHR", 2310 "vkGetPhysicalDeviceProperties", 2311 "vkGetPhysicalDeviceProperties2KHR", 2312 "vkGetPhysicalDeviceQueueFamilyProperties", 2313 "vkGetPhysicalDeviceMemoryProperties", 2314 "vkGetPhysicalDeviceFormatProperties", 2315 "vkGetPhysicalDeviceImageFormatProperties", 2316 "vkGetDeviceQueue", 2317 "vkGetBufferMemoryRequirements", 2318 "vkGetBufferMemoryRequirements2KHR", 2319 "vkGetImageMemoryRequirements", 2320 "vkGetImageMemoryRequirements2KHR", 2321 "vkAllocateMemory", 2322 "vkMapMemory", 2323 "vkUnmapMemory", 2324 "vkAllocateDescriptorSets", 2325 "vkFreeDescriptorSets", 2326 "vkResetDescriptorPool", 2327 "vkAllocateCommandBuffers", 2328 "vkFreeCommandBuffers", 2329 "vkCreateDisplayModeKHR", 2330 "vkCreateSharedSwapchainsKHR", 2331 "vkGetPhysicalDeviceExternalBufferPropertiesKHR", 2332 "vkGetPhysicalDeviceImageFormatProperties2KHR", 2333 "vkGetMemoryAndroidHardwareBufferANDROID", 2334 "vkCreateShadersEXT", 2335 ] 2336 2337 specialFuncs = [f for f in api.functions if f.name in specialFuncNames] 2338 createFuncs = [f for f in api.functions if (f.name[:8] == "vkCreate" or f.name == "vkAllocateMemory") and not f in specialFuncs] 2339 destroyFuncs = [f for f in api.functions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs] 2340 dummyFuncs = [f for f in api.functions if f not in specialFuncs + createFuncs + destroyFuncs] 2341 2342 def getHandle (name): 2343 for handle in api.handles: 2344 if handle.name == name: 2345 return handle 2346 raise Exception("No such handle: %s" % name) 2347 2348 for function in createFuncs: 2349 objectType = function.arguments[-1].type 2350 argsStr = ", ".join([a.name for a in function.arguments[:-1]]) 2351 2352 yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments)) 2353 yield "{" 2354 yield "\tDE_UNREF(%s);" % function.arguments[-2].name 2355 2356 if function.arguments[-1].len != None: 2357 yield "\tVK_NULL_RETURN((allocateNonDispHandleArray<%s, %s>(%s, %s)));" % (objectType[2:], objectType, argsStr, function.arguments[-1].name) 2358 else: 2359 if function.name == "vkCreatePipelineBinariesKHR": 2360 yield "\tDE_UNREF(device);" 2361 yield "\tDE_UNREF(pCreateInfo);" 2362 yield "\tDE_UNREF(pAllocator);" 2363 yield "\tDE_UNREF(pBinaries);" 2364 yield "\treturn VK_SUCCESS;" 2365 elif getHandle(objectType).type == "VK_DEFINE_NON_DISPATCHABLE_HANDLE": 2366 yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr) 2367 else: 2368 yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr) 2369 yield "}" 2370 yield "" 2371 2372 for function in destroyFuncs: 2373 objectArg = function.arguments[-2] 2374 2375 yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments)) 2376 yield "{" 2377 for arg in function.arguments[:-2]: 2378 yield "\tDE_UNREF(%s);" % arg.name 2379 2380 if getHandle(objectArg.type).type == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE': 2381 yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name) 2382 else: 2383 yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name) 2384 2385 yield "}" 2386 yield "" 2387 2388 for function in dummyFuncs: 2389 yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments)) 2390 yield "{" 2391 for arg in function.arguments: 2392 yield "\tDE_UNREF(%s);" % arg.name 2393 if function.returnType != "void": 2394 yield "\treturn VK_SUCCESS;" 2395 yield "}" 2396 yield "" 2397 2398 def genFuncEntryTable (type, name): 2399 2400 entries = [] 2401 pattern = "\tVK_NULL_FUNC_ENTRY(%s,\t%s)," 2402 for f in api.functions: 2403 if f.getType() != type: 2404 continue 2405 entries.append(pattern % (f.name, getInterfaceName(f.name))) 2406 2407 yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name 2408 yield "{" 2409 2410 for line in indentLines(entries): 2411 yield line 2412 yield "};" 2413 yield "" 2414 2415 # Func tables 2416 for line in genFuncEntryTable(Function.TYPE_PLATFORM, "s_platformFunctions"): 2417 yield line 2418 2419 for line in genFuncEntryTable(Function.TYPE_INSTANCE, "s_instanceFunctions"): 2420 yield line 2421 2422 for line in genFuncEntryTable(Function.TYPE_DEVICE, "s_deviceFunctions"): 2423 yield line 2424 2425 writeInlFile(filename, INL_HEADER, genNullDriverImpl()) 2426 2427def writeTypeUtil (api, filename): 2428 # Structs filled by API queries are not often used in test code 2429 QUERY_RESULT_TYPES = set([ 2430 "VkPhysicalDeviceFeatures", 2431 "VkPhysicalDeviceLimits", 2432 "VkFormatProperties", 2433 "VkImageFormatProperties", 2434 "VkPhysicalDeviceSparseProperties", 2435 "VkQueueFamilyProperties", 2436 "VkMemoryType", 2437 "VkMemoryHeap", 2438 "StdVideoH264SpsVuiFlags", 2439 "StdVideoH264SpsFlags", 2440 "StdVideoH264PpsFlags", 2441 "StdVideoDecodeH264PictureInfoFlags", 2442 "StdVideoDecodeH264ReferenceInfoFlags", 2443 "StdVideoEncodeH264SliceHeaderFlags", 2444 "StdVideoEncodeH264PictureInfoFlags", 2445 "StdVideoEncodeH264ReferenceInfoFlags", 2446 "StdVideoEncodeH264ReferenceInfoFlags", 2447 "StdVideoH265HrdFlags", 2448 "StdVideoH265VpsFlags", 2449 "StdVideoH265SpsVuiFlags", 2450 "StdVideoH265SpsFlags", 2451 "StdVideoH265PpsFlags", 2452 "StdVideoDecodeH265PictureInfoFlags", 2453 "StdVideoDecodeH265ReferenceInfoFlags", 2454 "StdVideoEncodeH265PictureInfoFlags", 2455 "StdVideoEncodeH265ReferenceInfoFlags", 2456 "StdVideoEncodeH265SliceSegmentHeaderFlags", 2457 "StdVideoH265ProfileTierLevelFlags", 2458 "StdVideoH265ShortTermRefPicSetFlags", 2459 "StdVideoEncodeH264ReferenceListsInfoFlags", 2460 "StdVideoEncodeH265ReferenceListsInfoFlags", 2461 "StdVideoEncodeAV1OperatingPointInfoFlags", 2462 "StdVideoEncodeAV1PictureInfoFlags", 2463 "StdVideoEncodeAV1ReferenceInfoFlags", 2464 ]) 2465 2466 def isSimpleStruct (type): 2467 def hasArrayMember (type): 2468 for member in type.members: 2469 if len(member.arraySizeList) > 0: 2470 return True 2471 return False 2472 2473 def hasCompositeMember (type): 2474 for member in type.members: 2475 if member.pointer is not None and '*' not in member.pointer: 2476 match = [c for c in api.compositeTypes if member.type == c.name] 2477 if len(match) > 0: 2478 return True 2479 return False 2480 2481 return type.category == "struct" and \ 2482 type.members[0].type != "VkStructureType" and \ 2483 not type.name in QUERY_RESULT_TYPES and \ 2484 not hasArrayMember(type) and \ 2485 not hasCompositeMember(type) 2486 2487 def gen (): 2488 for type in api.compositeTypes: 2489 if not isSimpleStruct(type): 2490 continue 2491 2492 if "StdVideoAV1" in type.name or "StdVideoDecodeAV1" in type.name: 2493 continue 2494 2495 name = type.name[2:] if type.name[:2].lower() == "vk" else type.name 2496 2497 yield "" 2498 yield "inline %s make%s (%s)" % (type.name, name, argListToStr(type.members)) 2499 yield "{" 2500 yield "\t%s res;" % type.name 2501 for line in indentLines(["\tres.%s\t= %s;" % (m.name, m.name) for m in type.members]): 2502 yield line 2503 yield "\treturn res;" 2504 yield "}" 2505 2506 writeInlFile(filename, INL_HEADER, gen()) 2507 2508def writeDriverIds(api, filename): 2509 driverIdsString = [] 2510 driverIdsString.append("static const struct\n" 2511 "{\n" 2512 "\tstd::string driver;\n" 2513 "\tuint32_t id;\n" 2514 "} driverIds [] =\n" 2515 "{") 2516 driverItems = dict() 2517 driverIdEnum = [enum for enum in api.enums if enum.name == 'VkDriverId'][0] 2518 for enumerator in driverIdEnum.enumeratorList: 2519 driverIdsString.append(f"\t{{\"{enumerator.name}\", {enumerator.value}}},") 2520 driverItems[enumerator.name] = enumerator.value 2521 for enumerator in driverIdEnum.enumeratorList: 2522 if len(enumerator.aliasList) > 0: 2523 driverIdsString.append(f"\t{{\"{enumerator.aliasList[0]}\", {enumerator.value}}},\t// {enumerator.name}") 2524 driverIdsString.append("\t{\"VK_DRIVER_ID_MAX_ENUM\", 0x7FFFFFFF}") 2525 driverIdsString.append("};") 2526 2527 writeInlFile(filename, INL_HEADER, driverIdsString) 2528 2529def writeSupportedExtensions(api, filename): 2530 2531 def writeExtensionsForVersions(map): 2532 result = [] 2533 for version in map: 2534 result.append(" if (coreVersion >= " + str(version) + ")") 2535 result.append(" {") 2536 for extension in map[version]: 2537 result.append(' dst.push_back("' + extension.name + '");') 2538 result.append(" }") 2539 2540 if not map: 2541 result.append(" DE_UNREF(coreVersion);") 2542 2543 return result 2544 2545 isSC = api.apiName == 'vulkansc' 2546 instanceMap = {} 2547 deviceMap = {} 2548 2549 allExtensionNames = {e.name for e in api.extensions} 2550 for ext in api.extensions: 2551 if ext.promotedto is None or "VK_VERSION" not in ext.promotedto: 2552 continue 2553 # skip partialy promoted extensions 2554 if ext.partiallyPromoted is True: 2555 continue 2556 major = int(ext.promotedto[-3]) 2557 minor = int(ext.promotedto[-1]) 2558 currVersion = "VK_API_VERSION_" + ext.promotedto[-3:] 2559 # VulkanSC is based on Vulkan 1.2. Any Vulkan version greater than 1.2 should be excluded 2560 if isSC and major==1 and minor>2: 2561 continue 2562 if ext.type == 'instance': 2563 list = instanceMap.get(currVersion) 2564 instanceMap[currVersion] = list + [ext] if list else [ext] 2565 else: 2566 list = deviceMap.get(currVersion) 2567 deviceMap[currVersion] = list + [ext] if list else [ext] 2568 2569 # add list of extensions missing in Vulkan SC specification 2570 if isSC: 2571 for extensionName, data in api.additionalExtensionData: 2572 if extensionName in allExtensionNames: 2573 logging.debug("Skipping additional extension " + extensionName + " because already added") 2574 continue 2575 # make sure that this extension was registered 2576 if 'register_extension' not in data.keys(): 2577 logging.debug("Skipping unregistered extension " + extensionName) 2578 continue 2579 # save array containing 'device' or 'instance' string followed by the optional vulkan version in which this extension is core; 2580 # note that register_extension section is also required for partialy promoted extensions like VK_EXT_extended_dynamic_state2 2581 # but those extensions should not fill 'core' tag 2582 match = re.match(r"(\d).(\d).(\d).(\d)", data['register_extension']['core']) 2583 if match is None: 2584 logging.debug("Skipping extension that is not matching core " + extensionName) 2585 continue 2586 major = int(match.group(2)) 2587 minor = int(match.group(3)) 2588 if major==1 and minor>2: 2589 continue 2590 currVersion = f"VK_API_VERSION_{major}_{minor}" 2591 ext = Extension(extensionName, 0, 0, 0, 0, 0, 0, 0, 0) 2592 if data['register_extension']['type'] == 'instance': 2593 list = instanceMap.get(currVersion) 2594 instanceMap[currVersion] = list + [ext] if list else [ext] 2595 else: 2596 list = deviceMap.get(currVersion) 2597 deviceMap[currVersion] = list + [ext] if list else [ext] 2598 2599 lines = [ 2600 "", 2601 "void getCoreDeviceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(deviceMap) != 0 or isSC else ""), 2602 "{"] + writeExtensionsForVersions(deviceMap) + [ 2603 "}", 2604 "", 2605 "void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(instanceMap) != 0 or isSC else ""), 2606 "{"] + writeExtensionsForVersions(instanceMap) + [ 2607 "}", 2608 ""] 2609 writeInlFile(filename, INL_HEADER, lines) 2610 2611 2612def writeExtensionFunctions (api, filename): 2613 2614 def writeExtensionNameArrays (): 2615 instanceExtensionNames = [f"\t\"{ext.name}\"," for ext in api.extensions if ext.type == "instance"] 2616 deviceExtensionNames = [f"\t\"{ext.name}\"," for ext in api.extensions if ext.type == "device"] 2617 yield '::std::string instanceExtensionNames[] =\n{' 2618 for instanceExtName in instanceExtensionNames: 2619 yield instanceExtName 2620 yield '};\n' 2621 yield '::std::string deviceExtensionNames[] =\n{' 2622 for deviceExtName in deviceExtensionNames: 2623 yield deviceExtName 2624 yield '};' 2625 2626 def writeExtensionFunctions (functionType): 2627 isFirstWrite = True 2628 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 2629 if functionType == Function.TYPE_INSTANCE: 2630 yield 'void getInstanceExtensionFunctions (uint32_t apiVersion, const std::vector<std::string> vIEP, const std::vector<std::string> vDEP, const std::string extName, ::std::vector<const char*>& functions)\n{' 2631 yield '\t(void)vIEP;\n(void)vDEP;' 2632 dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"] 2633 elif functionType == Function.TYPE_DEVICE: 2634 yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, const std::vector<std::string> vIEP, const std::vector<std::string> vDEP, const std::string extName, ::std::vector<const char*>& functions)\n{' 2635 yield '\t(void)vIEP;\n(void)vDEP;' 2636 dg_list = ["vkGetDeviceGroupPresentCapabilitiesKHR", "vkGetDeviceGroupSurfacePresentModesKHR", "vkAcquireNextImage2KHR"] 2637 for ext in api.extensions: 2638 parsedRequirements = [] 2639 for requirement in ext.requirementsList: 2640 funcNames = [] 2641 for requiredCommand in requirement.newCommands: 2642 commandName = requiredCommand.name 2643 # find function that has specified name 2644 func = None 2645 funcList = [f for f in api.functions if f.name == commandName] 2646 # if name was not found check if this is alias 2647 if len(funcList) == 0: 2648 for f in api.functions: 2649 for aliasName in f.aliasList: 2650 if aliasName == commandName: 2651 func = f 2652 break 2653 if func: 2654 break 2655 else: 2656 func = funcList[0] 2657 if func == None: 2658 if api.apiName == "vulkansc": 2659 continue 2660 # something went wrong, for "vulkan" func should always be found 2661 logging.error("%s in %s not valid" % (commandName, ext.name)) 2662 assert(False) 2663 if func.getType() == functionType: 2664 funcNames.append(commandName) 2665 condition = None 2666 if requirement.depends is not None: 2667 try: 2668 condition = transformDependsToCondition(requirement.depends, api, 'checkVersion(%s, %s, apiVersion)', 'extensionIsSupported(%s, "%s")') 2669 except Exception as e: 2670 if api.apiName != "vulkansc": 2671 raise e 2672 parsedRequirements.append((requirement.depends, condition, funcNames)) 2673 if ext.name: 2674 yield '\tif (extName == "%s")' % ext.name 2675 yield '\t{' 2676 for depends, condition, funcNames in parsedRequirements: 2677 if len(funcNames) == 0: 2678 continue 2679 indent = '\t\t' 2680 if depends is not None: 2681 yield '\t\t// Dependencies: %s' % depends 2682 yield '\t\tif (%s) {' % condition 2683 indent = '\t\t\t' 2684 for funcName in funcNames: 2685 if funcName in dg_list: 2686 yield '%sif(apiVersion >= VK_API_VERSION_1_1) functions.push_back("%s");' % (indent, funcName) 2687 else: 2688 yield '%sfunctions.push_back("%s");' % (indent, funcName) 2689 if depends is not None: 2690 yield '\t\t}' 2691 if ext.name == "VK_KHR_device_group": 2692 for dg_func in dg_list: 2693 yield '\t\tif(apiVersion < VK_API_VERSION_1_1) functions.push_back("%s");' % dg_func 2694 yield '\t\treturn;' 2695 yield '\t}' 2696 isFirstWrite = False 2697 if not isFirstWrite: 2698 yield '\tDE_FATAL("Extension name not found");' 2699 yield '}' 2700 2701 def genHelperFunctions(): 2702 yield 'bool checkVersion(uint32_t major, uint32_t minor, const uint32_t testedApiVersion)' 2703 yield '{' 2704 yield '\tuint32_t testedMajor = VK_API_VERSION_MAJOR(testedApiVersion);' 2705 yield '\tuint32_t testedMinor = VK_API_VERSION_MINOR(testedApiVersion);' 2706 yield '\t// return true when tested api version is greater' 2707 yield '\t// or equal to version represented by two uints' 2708 yield '\tif (major == testedMajor)' 2709 yield '\t\treturn minor <= testedMinor;' 2710 yield '\treturn major < testedMajor;' 2711 yield '}\n' 2712 yield 'bool extensionIsSupported(const std::vector<std::string> extNames, const std::string& ext)' 2713 yield '{' 2714 yield '\tfor (const std::string& supportedExtension : extNames)' 2715 yield '\t{' 2716 yield '\t\tif (supportedExtension == ext) return true;' 2717 yield '\t}' 2718 yield '\treturn false;' 2719 yield '}\n' 2720 2721 lines = [''] 2722 lines.extend(genHelperFunctions()) 2723 for line in writeExtensionFunctions(Function.TYPE_INSTANCE): 2724 lines += [line] 2725 lines += [''] 2726 for line in writeExtensionFunctions(Function.TYPE_DEVICE): 2727 lines += [line] 2728 lines += [''] 2729 for line in writeExtensionNameArrays(): 2730 lines += [line] 2731 2732 writeInlFile(filename, INL_HEADER, lines) 2733 2734def writeCoreFunctionalities(api, filename): 2735 functionOriginValues = ["FUNCTIONORIGIN_PLATFORM", "FUNCTIONORIGIN_INSTANCE", "FUNCTIONORIGIN_DEVICE"] 2736 2737 functionNamesPerApiVersionDict = {} 2738 for feature in api.features: 2739 if api.apiName not in feature.api.split(','): 2740 continue 2741 apiVersion = "VK_API_VERSION_" + feature.number.replace('.', '_') 2742 functionNamesPerApiVersionDict[apiVersion] = [] 2743 for r in feature.requirementsList: 2744 # skip optional promotions like for VK_EXT_host_image_copy 2745 if float(feature.number) > 1.35 and r.comment is not None and 'Promoted from ' not in r.comment: 2746 continue 2747 functionNamesPerApiVersionDict[apiVersion].extend(r.commandList) 2748 2749 lines = [ 2750 "", 2751 'enum FunctionOrigin', '{'] + [line for line in indentLines([ 2752 '\t' + functionOriginValues[0] + '\t= 0,', 2753 '\t' + functionOriginValues[1] + ',', 2754 '\t' + functionOriginValues[2]])] + [ 2755 "};", 2756 "", 2757 "typedef ::std::pair<const char*, FunctionOrigin> FunctionInfo;", 2758 "typedef ::std::vector<FunctionInfo> FunctionInfosList;", 2759 "typedef ::std::map<uint32_t, FunctionInfosList> ApisMap;", 2760 "", 2761 "void initApisMap (ApisMap& apis)", 2762 "{", 2763 " apis.clear();"] + [ 2764 " apis.insert(::std::pair<uint32_t, FunctionInfosList>(" + v + ", FunctionInfosList()));" for v in functionNamesPerApiVersionDict] + [ 2765 ""] 2766 2767 apiVersions = [] 2768 functionLines = [] 2769 for apiVersion in functionNamesPerApiVersionDict: 2770 lines += [f'\tapis[{apiVersion}] = {{'] 2771 # iterate over names of functions added with api 2772 for functionName in functionNamesPerApiVersionDict[apiVersion]: 2773 # search for data of this function in all functions list 2774 functionData = None 2775 for f in api.functions: 2776 if functionName == f.name or functionName in f.aliasList: 2777 functionData = f 2778 break 2779 if functionData == None: 2780 if api.apiName == "vulkansc": 2781 continue 2782 # something went wrong, for "vulkan" functionData should always be found 2783 assert(False) 2784 # add line corresponding to this function 2785 functionLines.append('\t\t{"' + functionName + '",\t' + functionOriginValues[functionData.getType()] + '},') 2786 # indent all functions of specified api and add them to main list 2787 lines = lines + [line for line in indentLines(functionLines)] + ["\t};"] 2788 2789 lines = lines + ["}"] 2790 writeInlFile(filename, INL_HEADER, lines) 2791 2792def camelToSnake(name): 2793 name = re.sub('([a-z])([23])D([A-Z])', r'\1_\2d\3', name) 2794 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) 2795 return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower() 2796 2797def writeDeviceFeatures2(api, filename): 2798 2799 def structInAPI(compositeObject): 2800 for c in api.compositeTypes: 2801 if c.name == compositeObject.name: 2802 return True 2803 return False 2804 2805 # helper class used to encapsulate all data needed during generation 2806 class StructureDetail: 2807 def __init__ (self, compositeObject): 2808 self.nameList = [compositeObject.name] + compositeObject.aliasList 2809 self.sType = compositeObject.members[0].values 2810 self.instanceName = 'd' + compositeObject.name[11:] 2811 self.flagName = 'is' + compositeObject.name[16:] 2812 self.extension = None 2813 self.api = None 2814 self.major = None 2815 self.minor = None 2816 structureMembers = compositeObject.members[2:] 2817 self.members = [m.name for m in structureMembers] 2818 2819 # helper extension class used in algorith below 2820 class StructureFoundContinueToNextOne(Exception): 2821 pass 2822 2823 # find structures that extend VkPhysicalDeviceFeatures2 2824 structures = [c for c in api.compositeTypes if c.structextends is not None and 'VkPhysicalDeviceFeatures2' in c.structextends] 2825 # remove structures that were added by extensions other than KHR and EXT 2826 testedStructures = [] 2827 for s in structures: 2828 if all([postfix not in s.name for postfix in EXTENSION_POSTFIXES_VENDOR]): 2829 testedStructures.append(s) 2830 2831 existingStructures = list(filter(structInAPI, testedStructures)) # remove features not found in API ( important for Vulkan SC ) 2832 testedStructureDetail = [StructureDetail(struct) for struct in existingStructures] 2833 # list of partially promoted extensions that are not marked in vk.xml as partially promoted in extension definition 2834 # note: for VK_EXT_host_image_copy there is a comment in require section for vk1.4 2835 partiallyPromotedExtensions = ['VK_EXT_pipeline_protected_access', 'VK_EXT_host_image_copy'] 2836 # iterate over all searched structures and find extensions that enabled them 2837 for structureDetail in testedStructureDetail: 2838 try: 2839 # iterate over all extensions 2840 for extension in api.extensions: 2841 for requirement in extension.requirementsList: 2842 for extensionStructure in requirement.newTypes: 2843 if extensionStructure.name in structureDetail.nameList: 2844 structureDetail.extension = extension.name 2845 if extension.promotedto is not None and extension.partiallyPromoted is False and extension.name not in partiallyPromotedExtensions: 2846 # check if extension was promoted to vulkan version or other extension; 2847 if 'VK_VERSION' in extension.promotedto: 2848 versionSplit = extension.promotedto.split('_') 2849 structureDetail.api = 0 if api.apiName == "vulkan" else 1 2850 structureDetail.major = versionSplit[-2] 2851 structureDetail.minor = versionSplit[-1] 2852 else: 2853 structureDetail.extension = extension.promotedto 2854 raise StructureFoundContinueToNextOne 2855 except StructureFoundContinueToNextOne: 2856 continue 2857 structureDetailToRemove = [] 2858 for structureDetail in testedStructureDetail: 2859 if structureDetail.major is not None or structureDetail.extension in partiallyPromotedExtensions: 2860 continue 2861 # if structure was not added with extension then check if 2862 # it was added directly with one of vulkan versions 2863 structureName = structureDetail.nameList[0] 2864 for feature in api.features: 2865 for requirement in feature.requirementsList: 2866 if structureName in requirement.typeList: 2867 if api.apiName == "vulkansc" and int(feature.number[-1]) > 2: 2868 structureDetailToRemove.append(structureDetail) 2869 else: 2870 versionSplit = feature.name.split('_') 2871 structureDetail.api = 0 if api.apiName == "vulkan" else 1 2872 structureDetail.major = versionSplit[-2] 2873 structureDetail.minor = versionSplit[-1] 2874 break 2875 if structureDetail.major is not None: 2876 break 2877 # remove structures that should not be tested for given api version 2878 for sd in structureDetailToRemove: 2879 testedStructureDetail.remove(sd) 2880 # generate file content 2881 structureDefinitions = [] 2882 featureEnabledFlags = [] 2883 clearStructures = [] 2884 structureChain = [] 2885 logStructures = [] 2886 verifyStructures = [] 2887 for index, structureDetail in enumerate(testedStructureDetail): 2888 structureName = structureDetail.nameList[0] 2889 # create two instances of each structure 2890 nameSpacing = '\t' 2891 structureDefinitions.append(structureName + nameSpacing + structureDetail.instanceName + '[count];') 2892 # create flags that check if proper extension or vulkan version is available 2893 condition = '' 2894 extension = structureDetail.extension 2895 major = structureDetail.major 2896 if extension is not None: 2897 condition = ' checkExtension(properties, "' + extension + '")' 2898 if major is not None: 2899 condition = ' ' if condition == '' else condition + ' || ' 2900 condition += 'context.contextSupports(vk::ApiVersion(' + str(structureDetail.api) + ', ' + str(major) + ', ' + str(structureDetail.minor) + ', 0))' 2901 if condition == '': 2902 condition = ' true' 2903 condition += ';' 2904 nameSpacing = '\t' * int((len(structureName) - 4) / 4) 2905 featureEnabledFlags.append('const bool' + nameSpacing + structureDetail.flagName + ' =' + condition) 2906 # clear memory of each structure 2907 clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx], 0xFF * ndx, sizeof(' + structureName + '));') 2908 # construct structure chain 2909 nextInstanceName = 'nullptr'; 2910 if index < len(testedStructureDetail)-1: 2911 nextInstanceName = '&' + testedStructureDetail[index+1].instanceName + '[ndx]' 2912 structureChain.append([ 2913 '\t\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.flagName + ' ? ' + structureDetail.sType + ' : VK_STRUCTURE_TYPE_MAX_ENUM;', 2914 '\t\t' + structureDetail.instanceName + '[ndx].pNext = nullptr;']) 2915 # construct log section 2916 logStructures.append([ 2917 '\tif (' + structureDetail.flagName + ')', 2918 '\t\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;' 2919 ]) 2920 #construct verification section 2921 verifyStructure = [] 2922 verifyStructure.append('\tif (' + structureDetail.flagName + ' &&') 2923 for index, m in enumerate(structureDetail.members): 2924 prefix = '\t\t(' if index == 0 else '\t\t ' 2925 postfix = '))' if index == len(structureDetail.members)-1 else ' ||' 2926 verifyStructure.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix) 2927 if len(structureDetail.members) == 0: 2928 verifyStructure.append('\t\tfalse)') 2929 verifyStructure.append('\t{\n\t\tTCU_FAIL("Mismatch between ' + structureName + '");\n\t}') 2930 verifyStructures.append(verifyStructure) 2931 2932 # construct file content 2933 stream = [] 2934 2935 # individual test functions 2936 for n, x in enumerate(testedStructureDetail): 2937 stream.append("tcu::TestStatus testPhysicalDeviceFeature" + x.instanceName[len('device'):]+" (Context& context)") 2938 stream.append("""{ 2939 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); 2940 const CustomInstance instance (createCustomInstanceWithExtension(context, "VK_KHR_get_physical_device_properties2")); 2941 const InstanceDriver& vki (instance.getDriver()); 2942 const int count = 2u; 2943 TestLog& log = context.getTestContext().getLog(); 2944 VkPhysicalDeviceFeatures2 extFeatures; 2945 vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(vki, physicalDevice, nullptr); 2946""") 2947 stream.append("\t"+structureDefinitions[n]) 2948 stream.append("\t"+featureEnabledFlags[n]) 2949 stream.append('') 2950 stream.append('\tfor (int ndx = 0; ndx < count; ++ndx)\n\t{') 2951 stream.append("\t" + clearStructures[n]) 2952 stream.extend(structureChain[n]) 2953 stream.append('') 2954 stream.append( 2955 '\t\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n' 2956 '\t\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n' 2957 '\t\textFeatures.pNext = &' + testedStructureDetail[n].instanceName + '[ndx];\n\n' 2958 '\t\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);') 2959 stream.append('\t}\n') 2960 stream.extend(logStructures[n]) 2961 stream.append('') 2962 stream.extend(verifyStructures[n]) 2963 stream.append('\treturn tcu::TestStatus::pass("Querying succeeded");') 2964 stream.append("}\n") 2965 2966 allApiVersions = [f.number for f in api.features] 2967 promotedTests = [] 2968 if api.apiName == "vulkan": 2969 for feature in api.features: 2970 if api.apiName not in feature.api.split(','): 2971 continue 2972 major = feature.number[0] 2973 minor = feature.number[-1] 2974 promotedFeatures = [] 2975 if feature.name == 'VK_VERSION_1_0': 2976 continue 2977 for requirement in feature.requirementsList: 2978 for type in requirement.typeList: 2979 matchedStructType = re.search(r'VkPhysicalDevice(\w+)Features', type, re.IGNORECASE) 2980 matchedCoreStructType = re.search(r'VkPhysicalDeviceVulkan(\d+)Features', type, re.IGNORECASE) 2981 if matchedStructType and not matchedCoreStructType: 2982 promotedFeatures.append(type) 2983 if promotedFeatures: 2984 testName = "createDeviceWithPromoted" + feature.number.replace('.', '') + "Structures" 2985 promotedTests.append(testName) 2986 stream.append("tcu::TestStatus " + testName + " (Context& context)") 2987 stream.append("{") 2988 stream.append( 2989 ' if (!context.contextSupports(vk::ApiVersion(0, ' + major + ', ' + minor + ', 0)))\n' 2990 ' TCU_THROW(NotSupportedError, "Vulkan ' + major + '.' + minor + ' is not supported");') 2991 stream.append(""" 2992 const PlatformInterface& platformInterface = context.getPlatformInterface(); 2993 const CustomInstance instance (createCustomInstanceFromContext(context)); 2994 const InstanceDriver& instanceDriver (instance.getDriver()); 2995 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); 2996 const uint32_t queueFamilyIndex = 0; 2997 const uint32_t queueCount = 1; 2998 const uint32_t queueIndex = 0; 2999 const float queuePriority = 1.0f; 3000 3001 const vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice); 3002 3003 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = 3004 { 3005 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 3006 nullptr, 3007 (VkDeviceQueueCreateFlags)0u, 3008 queueFamilyIndex, //queueFamilyIndex; 3009 queueCount, //queueCount; 3010 &queuePriority, //pQueuePriorities; 3011 }; 3012""") 3013 lastFeature = '' 3014 usedFeatures = [] 3015 for feature in promotedFeatures: 3016 for struct in testedStructureDetail: 3017 if (struct.instanceName in usedFeatures): 3018 continue 3019 if feature in struct.nameList: 3020 if lastFeature: 3021 stream.append("\t" + feature + " " + struct.instanceName + " = initVulkanStructure(&" + lastFeature + ");") 3022 else: 3023 stream.append("\t" + feature + " " + struct.instanceName + " = initVulkanStructure();") 3024 lastFeature = struct.instanceName 3025 usedFeatures.append(struct.instanceName) 3026 break 3027 stream.append("\tVkPhysicalDeviceFeatures2 extFeatures = initVulkanStructure(&" + lastFeature + ");") 3028 stream.append(""" 3029 instanceDriver.getPhysicalDeviceFeatures2 (physicalDevice, &extFeatures); 3030 3031 const VkDeviceCreateInfo deviceCreateInfo = 3032 { 3033 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType; 3034 &extFeatures, //pNext; 3035 (VkDeviceCreateFlags)0u, 3036 1, //queueRecordCount; 3037 &deviceQueueCreateInfo, //pRequestedQueues; 3038 0, //layerCount; 3039 nullptr, //ppEnabledLayerNames; 3040 0, //extensionCount; 3041 nullptr, //ppEnabledExtensionNames; 3042 nullptr, //pEnabledFeatures; 3043 }; 3044 3045 const Unique<VkDevice> device (createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), platformInterface, instance, instanceDriver, physicalDevice, &deviceCreateInfo)); 3046 const DeviceDriver deviceDriver (platformInterface, instance, device.get(), context.getUsedApiVersion(), context.getTestContext().getCommandLine()); 3047 const VkQueue queue = getDeviceQueue(deviceDriver, *device, queueFamilyIndex, queueIndex); 3048 3049 VK_CHECK(deviceDriver.queueWaitIdle(queue)); 3050 3051 return tcu::TestStatus::pass("Pass"); 3052} 3053""") 3054 3055 # function to create tests 3056 stream.append("void addSeparateFeatureTests (tcu::TestCaseGroup* testGroup)\n{") 3057 for x in testedStructureDetail: 3058 stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x.instanceName[len('device'):]) + '", testPhysicalDeviceFeature' + x.instanceName[len('device'):] + ');') 3059 for x in promotedTests: 3060 stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x) + '", ' + x + ');') 3061 stream.append('}\n') 3062 3063 # write out 3064 writeInlFile(filename, INL_HEADER, stream) 3065 3066class FeaturesOrPropertiesDefs: 3067 def __init__ (self, structureType, structureTypeName): 3068 self.structureType = structureType # string with most important part from structure type e.g. 'LINE_RASTERIZATION' 3069 # (for VkPhysicalDeviceLineRasterizationFeaturesEXT) without prefix nor postfix 3070 self.verSuffix = '' # string containing version, this is needed to handle corner case like e.g. 3071 # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD where 2 is after PROPERTIES 3072 self.extSuffix = '' # string with extension type e.g. '_EXT' for VkPhysicalDeviceLineRasterizationFeaturesEXT 3073 self.structureTypeName = structureTypeName # full structure name e.g. 'VkPhysicalDeviceCustomBorderColorFeaturesEXT' 3074 self.extensionName = None # name of extension that added this structure eg. 'VK_EXT_depth_clip_enable' 3075 self.nameString = None # e.g. 'VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME' 3076 self.versionString = '0' # e.g. 'VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION' 3077 self.compositeType = None # None or pointer to composite type 3078 def __iter__(self): 3079 return iter((self.structureType, self.verSuffix, self.extSuffix, self.structureTypeName, self.extensionName, self.nameString, self.versionString)) 3080 3081def generateDeviceFeaturesOrPropertiesDefs(api, FeaturesOrProperties): 3082 assert(FeaturesOrProperties in ['Features', 'Properties']) 3083 defs = [] 3084 foundStructureEnums = [] 3085 structureEnumPattern = fr'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_{FeaturesOrProperties.upper()}(\w+)' 3086 structureEnumPatternNotExtension = structureEnumPattern[:-5] + '$' 3087 structureTypePattern = fr'VkPhysicalDevice(\w+){FeaturesOrProperties}(\w+)' 3088 structureTypePatternNotExtension = structureTypePattern[:-5] + '$' 3089 structureTypeToSkipPattern = fr'VkPhysicalDeviceVulkan\d\d{FeaturesOrProperties}' 3090 structureExtendsPattern = f'VkPhysicalDevice{FeaturesOrProperties}2' 3091 # iterate over all extensions to find extension that adds enum value matching pattern; 3092 # this will always be in first requirement section 3093 for ext in api.extensions: 3094 # skip extensions that were promoted to other extensions (not vk version) 3095 if ext.promotedto is not None and "VK_VERSION" not in ext.promotedto: 3096 continue 3097 allExtendedEnums = ext.requirementsList[0].extendedEnums 3098 for extendedEnum in allExtendedEnums: 3099 matchedStructEnum = re.search(structureEnumPattern, extendedEnum.name, re.IGNORECASE) 3100 if matchedStructEnum: 3101 # find feature/property structure type name 3102 structureTypeName = "" 3103 for stRequirement in ext.requirementsList[0].newTypes: 3104 stName = stRequirement.name 3105 matchedStructType = re.search(structureTypePattern, stName, re.IGNORECASE) 3106 if matchedStructType: 3107 structureTypeName = stName 3108 break 3109 # iterate over all composite types to check if structureTypeName is not alias 3110 # this handles case where extension was promoted and with it feature/property structure 3111 structureType = None 3112 for ct in api.compositeTypes: 3113 if structureTypeName == ct.name: 3114 structureType = ct 3115 break 3116 elif structureTypeName in ct.aliasList: 3117 structureType = ct 3118 structureTypeName = structureType.name 3119 break 3120 # use data in structextends to skip structures that should not be passed to vkGetPhysicalDeviceProperties(/Features)2 function 3121 if structureType is None or structureType.structextends is None or structureExtendsPattern not in structureType.structextends: 3122 continue 3123 # meke sure that structure was not added earlier - this handles special 3124 # cases like VkPhysicalDeviceIDPropertiesKHR added by 3 extensions 3125 if len([d for d in defs if d.structureTypeName == structureTypeName]) > 0: 3126 continue 3127 foundStructureEnums.append(matchedStructEnum.group(1)) 3128 fop = FeaturesOrPropertiesDefs(matchedStructEnum.group(1), structureTypeName) 3129 fop.extensionName = ext.name 3130 fop.nameString = allExtendedEnums[1].name 3131 fop.versionString = allExtendedEnums[0].name 3132 fop.compositeType = structureType 3133 defs.append(fop) 3134 # there are cases like VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD 3135 # where 2 is after PROPERTIES - to handle this we need to split suffix to two parts 3136 fop.extSuffix = matchedStructEnum.group(2) 3137 suffixStart = fop.extSuffix.rfind('_') 3138 if suffixStart > 0: 3139 fop.verSuffix = fop.extSuffix[:suffixStart] 3140 fop.extSuffix = fop.extSuffix[suffixStart:] 3141 # accept single feature/property structure per extension - this also handles cases 3142 # like VK_KHR_variable_pointers which specify feature structure and its alias 3143 break 3144 3145 # iterate over all structures to find Feature/Property structures that were not added with extension 3146 # but with vulkan version; to do that we need to skip extension part from pattern 3147 for ct in api.compositeTypes: 3148 matchedStructType = re.search(structureTypePatternNotExtension, ct.name, re.IGNORECASE) 3149 if matchedStructType: 3150 if ct.members[0].name != "sType": 3151 continue 3152 if ct.structextends is None or structureExtendsPattern not in ct.structextends: 3153 continue 3154 matchedStructEnum = re.search(structureEnumPatternNotExtension, ct.members[0].values, re.IGNORECASE) 3155 if (matchedStructEnum.group(1) not in foundStructureEnums) and (re.match(structureTypeToSkipPattern, ct.name) == None): 3156 defs.append(FeaturesOrPropertiesDefs(matchedStructEnum.group(1), ct.name)) 3157 return defs 3158 3159def writeDeviceFeatures(api, dfDefs, filename): 3160 # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs 3161 # and construct dictionary with all of their attributes 3162 blobMembers = {} 3163 blobStructs = {} 3164 blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") 3165 for structureType in api.compositeTypes: 3166 match = blobPattern.match(structureType.name) 3167 if match: 3168 allMembers = [member.name for member in structureType.members] 3169 vkVersion = match.group(1) 3170 blobMembers[vkVersion] = allMembers[2:] 3171 blobStructs[vkVersion] = set() 3172 initFromBlobDefinitions = [] 3173 emptyInitDefinitions = [] 3174 # iterate over all feature structures 3175 allFeaturesPattern = re.compile(r"^VkPhysicalDevice\w+Features[1-9]*") 3176 nonExtFeaturesPattern = re.compile(r"^VkPhysicalDevice\w+Features[1-9]*$") 3177 for structureType in api.compositeTypes: 3178 # skip structures that are not feature structures 3179 if not allFeaturesPattern.match(structureType.name): 3180 continue 3181 # skip structures that were previously identified as blobs 3182 if blobPattern.match(structureType.name): 3183 continue 3184 # skip sType and pNext and just grab third and next attributes 3185 structureMembers = structureType.members[2:] 3186 notPartOfBlob = True 3187 if nonExtFeaturesPattern.match(structureType.name): 3188 # check if this member is part of any of the blobs 3189 for blobName, blobMemberList in blobMembers.items(): 3190 # if just one member is not part of this blob go to the next blob 3191 # (we asume that all members are part of blob - no need to check all) 3192 if structureMembers[0].name not in blobMemberList: 3193 continue 3194 # add another feature structure name to this blob 3195 blobStructs[blobName].add(structureType) 3196 # add specialization for this feature structure 3197 memberCopying = "" 3198 for member in structureMembers: 3199 memberCopying += "\tfeatureType.{0} = allFeaturesBlobs.vk{1}.{0};\n".format(member.name, blobName) 3200 wholeFunction = \ 3201 "template<> void initFeatureFromBlob<{0}>({0}& featureType, const AllFeaturesBlobs& allFeaturesBlobs)\n" \ 3202 "{{\n" \ 3203 "{1}" \ 3204 "}}".format(structureType.name, memberCopying) 3205 initFromBlobDefinitions.append(wholeFunction) 3206 notPartOfBlob = False 3207 # assuming that all members are part of blob, goto next 3208 break 3209 # add empty template definition as on Fedora there are issue with 3210 # linking using just generic template - all specializations are needed 3211 if notPartOfBlob: 3212 emptyFunction = "template<> void initFeatureFromBlob<{0}>({0}&, const AllFeaturesBlobs&) {{}}" 3213 emptyInitDefinitions.append(emptyFunction.format(structureType.name)) 3214 extensionDefines = [] 3215 makeFeatureDescDefinitions = [] 3216 featureStructWrappers = [] 3217 for idx, (sType, sVerSuffix, sExtSuffix, extStruct, _, extNameDef, specVersionDef) in enumerate(dfDefs): 3218 extensionNameDefinition = extNameDef 3219 if not extensionNameDefinition: 3220 extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) 3221 extensionDefines.append(f'#define {extensionNameDefinition} "core_feature"') 3222 # construct makeFeatureDesc template function definitions 3223 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sVerSuffix + sExtSuffix) 3224 makeFeatureDescDefinitions.append("template<> FeatureDesc makeFeatureDesc<{0}>(void) " \ 3225 "{{ return FeatureDesc{{{1}, {2}, {3}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVersionDef)) 3226 # construct CreateFeatureStruct wrapper block 3227 featureStructWrappers.append("\t{{ createFeatureStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVersionDef)) 3228 # construct function that will check for which vk version structure sType is part of blob 3229 blobChecker = "uint32_t getBlobFeaturesVersion (VkStructureType sType)\n{\n" \ 3230 "\tconst std::map<VkStructureType, uint32_t> sTypeBlobMap\n" \ 3231 "\t{\n" 3232 # iterate over blobs with list of structures 3233 for blobName in sorted(blobStructs.keys()): 3234 blobChecker += "\t\t// Vulkan{0}\n".format(blobName) 3235 # iterate over all feature structures in current blob 3236 structuresList = list(blobStructs[blobName]) 3237 structuresList = sorted(structuresList, key=lambda s: s.name) 3238 for structType in structuresList: 3239 # find definition of this structure in dfDefs 3240 structDef = None 3241 allNamesToCheck = [structType.name] 3242 if len(structType.aliasList) > 0: 3243 allNamesToCheck.extend(structType.aliasList) 3244 for structName in allNamesToCheck: 3245 structDefList = [s for s in dfDefs if s.structureTypeName == structName] 3246 if len(structDefList) > 0: 3247 structDef = structDefList[0] 3248 break 3249 sType = structDef.structureType 3250 sSuffix = structDef.verSuffix + structDef.extSuffix 3251 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix) 3252 tabs = "\t" * int((88 - len(sTypeName)) / 4) 3253 blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) 3254 blobChecker += "\t};\n\n" \ 3255 "\tauto it = sTypeBlobMap.find(sType);\n" \ 3256 "\tif(it == sTypeBlobMap.end())\n" \ 3257 "\t\treturn 0;\n" \ 3258 "\treturn it->second;\n" \ 3259 "}\n" 3260 # combine all definition lists 3261 stream = [ 3262 '#include "vkDeviceFeatures.hpp"\n', 3263 'namespace vk\n{'] 3264 stream.extend(extensionDefines) 3265 stream.append('\n') 3266 stream.extend(initFromBlobDefinitions) 3267 stream.append('\n// generic template is not enough for some compilers') 3268 stream.extend(emptyInitDefinitions) 3269 stream.append('\n') 3270 stream.extend(makeFeatureDescDefinitions) 3271 stream.append('\n') 3272 stream.append('static const FeatureStructCreationData featureStructCreationArray[]\n{') 3273 stream.extend(featureStructWrappers) 3274 stream.append('};\n') 3275 stream.append(blobChecker) 3276 stream.append('} // vk\n') 3277 writeInlFile(filename, INL_HEADER, stream) 3278 3279def writeDeviceFeatureTest(api, filename): 3280 3281 coreFeaturesPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") 3282 featureItems = [] 3283 testFunctions = [] 3284 # iterate over all feature structures 3285 allFeaturesPattern = re.compile(r"^VkPhysicalDevice\w+Features[1-9]*") 3286 for structureType in api.compositeTypes: 3287 # skip structures that are not feature structures 3288 if not allFeaturesPattern.match(structureType.name): 3289 continue 3290 # skip sType and pNext and just grab third and next attributes 3291 structureMembers = structureType.members[2:] 3292 3293 items = [] 3294 for member in structureMembers: 3295 items.append(" FEATURE_ITEM ({0}, {1}),".format(structureType.name, member.name)) 3296 3297 testBlock = """ 3298tcu::TestStatus createDeviceWithUnsupportedFeaturesTest{4} (Context& context) 3299{{ 3300 const PlatformInterface& vkp = context.getPlatformInterface(); 3301 tcu::TestLog& log = context.getTestContext().getLog(); 3302 tcu::ResultCollector resultCollector (log); 3303 const CustomInstance instance (createCustomInstanceWithExtensions(context, context.getInstanceExtensions(), nullptr, true)); 3304 const InstanceDriver& instanceDriver (instance.getDriver()); 3305 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); 3306 const uint32_t queueFamilyIndex = 0; 3307 const uint32_t queueCount = 1; 3308 const float queuePriority = 1.0f; 3309 const DeviceFeatures deviceFeaturesAll (context.getInstanceInterface(), context.getUsedApiVersion(), physicalDevice, context.getInstanceExtensions(), context.getDeviceExtensions(), true); 3310 const VkPhysicalDeviceFeatures2 deviceFeatures2 = deviceFeaturesAll.getCoreFeatures2(); 3311 int numErrors = 0; 3312 const tcu::CommandLine& commandLine = context.getTestContext().getCommandLine(); 3313 bool isSubProcess = context.getTestContext().getCommandLine().isSubProcess(); 3314{6} 3315 3316 VkPhysicalDeviceFeatures emptyDeviceFeatures; 3317 deMemset(&emptyDeviceFeatures, 0, sizeof(emptyDeviceFeatures)); 3318 3319 // Only non-core extensions will be used when creating the device. 3320 const auto& extensionNames = context.getDeviceCreationExtensions(); 3321 DE_UNREF(extensionNames); // In some cases this is not used. 3322 3323 if (const void* featuresStruct = findStructureInChain(const_cast<const void*>(deviceFeatures2.pNext), getStructureType<{0}>())) 3324 {{ 3325 static const Feature features[] = 3326 {{ 3327{1} 3328 }}; 3329 auto* supportedFeatures = reinterpret_cast<const {0}*>(featuresStruct); 3330 checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures, {5}, context.getUsedApiVersion(), commandLine); 3331 }} 3332 3333 if (numErrors > 0) 3334 return tcu::TestStatus(resultCollector.getResult(), "Enabling unsupported features didn't return VK_ERROR_FEATURE_NOT_PRESENT."); 3335 3336 return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage()); 3337}} 3338""" 3339 additionalParams = ( 'memReservationStatMax, isSubProcess' if api.apiName == 'vulkansc' else 'isSubProcess' ) 3340 additionalDefs = ( ' VkDeviceObjectReservationCreateInfo memReservationStatMax = context.getResourceInterface()->getStatMax();' if apiName == 'vulkansc' else '') 3341 featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("nullptr" if coreFeaturesPattern.match(structureType.name) else "&extensionNames"), structureType.name[len('VkPhysicalDevice'):], additionalParams, additionalDefs)) 3342 3343 testFunctions.append("createDeviceWithUnsupportedFeaturesTest" + structureType.name[len('VkPhysicalDevice'):]) 3344 3345 stream = [''] 3346 stream.extend(featureItems) 3347 stream.append(""" 3348void addSeparateUnsupportedFeatureTests (tcu::TestCaseGroup* testGroup) 3349{ 3350""") 3351 for x in testFunctions: 3352 stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x[len('createDeviceWithUnsupportedFeaturesTest'):]) + '", ' + x + ');') 3353 stream.append('}\n') 3354 3355 writeInlFile(filename, INL_HEADER, stream) 3356 3357def writeDeviceProperties(api, dpDefs, filename): 3358 # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs 3359 # and construct dictionary with all of their attributes 3360 blobMembers = {} 3361 blobStructs = {} 3362 blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Properties[0-9]*$") 3363 for structureType in api.compositeTypes: 3364 match = blobPattern.match(structureType.name) 3365 if match: 3366 allMembers = [member.name for member in structureType.members] 3367 vkVersion = match.group(1) 3368 blobMembers[vkVersion] = allMembers[2:] 3369 blobStructs[vkVersion] = set() 3370 initFromBlobDefinitions = [] 3371 emptyInitDefinitions = [] 3372 # iterate over all property structures 3373 allPropertiesPattern = re.compile(r"^VkPhysicalDevice\w+Properties[1-9]*") 3374 nonExtPropertiesPattern = re.compile(r"^VkPhysicalDevice\w+Properties[1-9]*$") 3375 for structureType in api.compositeTypes: 3376 # skip structures that are not property structures 3377 if not allPropertiesPattern.match(structureType.name): 3378 continue 3379 # skip structures that were previously identified as blobs 3380 if blobPattern.match(structureType.name): 3381 continue 3382 # skip sType and pNext and just grab third and next attributes 3383 structureMembers = structureType.members[2:] 3384 notPartOfBlob = True 3385 if nonExtPropertiesPattern.match(structureType.name): 3386 # check if this member is part of any of the blobs 3387 for blobName, blobMemberList in blobMembers.items(): 3388 # if just one member is not part of this blob go to the next blob 3389 # (we asume that all members are part of blob - no need to check all) 3390 if structureMembers[0].name not in blobMemberList: 3391 continue 3392 # add another property structure name to this blob 3393 blobStructs[blobName].add(structureType) 3394 # add specialization for this property structure 3395 memberCopying = "" 3396 for member in structureMembers: 3397 if len(member.arraySizeList) == 0: 3398 # handle special case 3399 if structureType.name == "VkPhysicalDeviceSubgroupProperties" and "subgroup" not in member.name : 3400 blobMemberName = "subgroup" + member.name[0].capitalize() + member.name[1:] 3401 memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{2};\n".format(member.name, blobName, blobMemberName) 3402 # end handling special case 3403 else: 3404 memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{0};\n".format(member.name, blobName) 3405 else: 3406 memberCopying += "\tmemcpy(propertyType.{0}, allPropertiesBlobs.vk{1}.{0}, sizeof({2}) * {3});\n".format(member.name, blobName, member.type, member.arraySizeList[0]) 3407 wholeFunction = \ 3408 "template<> void initPropertyFromBlob<{0}>({0}& propertyType, const AllPropertiesBlobs& allPropertiesBlobs)\n" \ 3409 "{{\n" \ 3410 "{1}" \ 3411 "}}".format(structureType.name, memberCopying) 3412 initFromBlobDefinitions.append(wholeFunction) 3413 notPartOfBlob = False 3414 # assuming that all members are part of blob, goto next 3415 break 3416 # add empty template definition as on Fedora there are issue with 3417 # linking using just generic template - all specializations are needed 3418 if notPartOfBlob: 3419 emptyFunction = "template<> void initPropertyFromBlob<{0}>({0}&, const AllPropertiesBlobs&) {{}}" 3420 emptyInitDefinitions.append(emptyFunction.format(structureType.name)) 3421 extensionDefines = [] 3422 makePropertyDescDefinitions = [] 3423 propertyStructWrappers = [] 3424 for idx, (sType, sVerSuffix, sExtSuffix, extStruct, _, extNameDef, specVersionDef) in enumerate(dpDefs): 3425 extensionNameDefinition = extNameDef 3426 if not extensionNameDefinition: 3427 extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) 3428 extensionDefines.append(f'#define {extensionNameDefinition} "core_property"') 3429 # construct makePropertyDesc template function definitions 3430 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sVerSuffix + sExtSuffix) 3431 makePropertyDescDefinitions.append("template<> PropertyDesc makePropertyDesc<{0}>(void) " \ 3432 "{{ return PropertyDesc{{{1}, {2}, {3}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVersionDef)) 3433 # construct CreateProperty struct wrapper block 3434 propertyStructWrappers.append("\t{{ createPropertyStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVersionDef)) 3435 # construct method that will check if structure sType is part of blob 3436 blobChecker = "uint32_t getBlobPropertiesVersion (VkStructureType sType)\n{\n" \ 3437 "\tconst std::map<VkStructureType, uint32_t> sTypeBlobMap\n" \ 3438 "\t{\n" 3439 # iterate over blobs with list of structures 3440 for blobName in sorted(blobStructs.keys()): 3441 blobChecker += "\t\t// Vulkan{0}\n".format(blobName) 3442 # iterate over all feature structures in current blob 3443 structuresList = list(blobStructs[blobName]) 3444 structuresList = sorted(structuresList, key=lambda s: s.name) 3445 for structType in structuresList: 3446 # find definition of this structure in dpDefs 3447 structName = structType.name 3448 structDef = None 3449 foundDefs = [s for s in dpDefs if s.structureTypeName == structName] 3450 if len(foundDefs) > 0: 3451 structDef = foundDefs[0] 3452 else: 3453 for alias in structType.aliasList: 3454 foundDefs = [s for s in dpDefs if s.structureTypeName == alias] 3455 if len(foundDefs) > 0: 3456 structDef = foundDefs[0] 3457 break 3458 sType = structDef.structureType 3459 sSuffix = structDef.verSuffix + structDef.extSuffix 3460 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sSuffix) 3461 tabs = "\t" * int((80 - len(sTypeName)) / 4) 3462 blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) 3463 blobChecker += "\t};\n\n" \ 3464 "\tauto it = sTypeBlobMap.find(sType);\n" \ 3465 "\tif(it == sTypeBlobMap.end())\n" \ 3466 "\t\treturn 0;\n" \ 3467 "\treturn it->second;\n" \ 3468 "}\n" 3469 # combine all definition lists 3470 stream = [ 3471 '#include "vkDeviceProperties.hpp"\n', 3472 'namespace vk\n{'] 3473 stream.extend(extensionDefines) 3474 stream.append('\n') 3475 stream.extend(initFromBlobDefinitions) 3476 stream.append('\n// generic template is not enough for some compilers') 3477 stream.extend(emptyInitDefinitions) 3478 stream.append('\n') 3479 stream.extend(makePropertyDescDefinitions) 3480 stream.append('\n') 3481 stream.append('static const PropertyStructCreationData propertyStructCreationArray[] =\n{') 3482 stream.extend(propertyStructWrappers) 3483 stream.append('};\n') 3484 stream.append(blobChecker) 3485 stream.append('} // vk\n') 3486 writeInlFile(filename, INL_HEADER, stream) 3487 3488def genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename): 3489 UNSUFFIXED_STRUCTURES = [ 3490 "CornerSampledImage", 3491 "ShaderSMBuiltins", 3492 "ShadingRateImage", 3493 "RayTracing", 3494 "RepresentativeFragmentTest", 3495 "ComputeShaderDerivatives", 3496 "MeshShader", 3497 "ShaderImageFootprint", 3498 "ExclusiveScissor", 3499 "DedicatedAllocationImageAliasing", 3500 "CoverageReductionMode", 3501 "DeviceGeneratedCommands", 3502 "InheritedViewportScissor", 3503 "PresentBarrier", 3504 "DiagnosticsConfig", 3505 "FragmentShadingRateEnums", 3506 "RayTracingMotionBlur", 3507 "ExternalMemoryRDMA", 3508 "CopyMemoryIndirect", 3509 "MemoryDecompression", 3510 "LinearColorAttachment", 3511 "OpticalFlow", 3512 "RayTracingInvocationReorder", 3513 "DisplacementMicromap"] 3514 stream = [] 3515 for fop in dfDefs: 3516 # remove VkPhysicalDevice prefix from structure name 3517 nameSubStr = fop.structureTypeName[16:] 3518 # remove extension type in some cases 3519 if nameSubStr[-3:] == "KHR": 3520 nameSubStr = nameSubStr[:-3] 3521 elif fop.compositeType and fop.compositeType.notSupportedAlias: 3522 # remove KHR also for extensions that were promoted in Vulkan but 3523 # not in VulkanSC this reduces number of ifdefs for SC in CTS code 3524 nameSubStr = nameSubStr[:-3] 3525 elif nameSubStr[-2:] == "NV": 3526 suffix = nameSubStr[-2:] 3527 nameSubStr = nameSubStr[:-2] 3528 if nameSubStr[-8:] == "Features": 3529 infix = nameSubStr[-8:] 3530 nameSubStr = nameSubStr[:-8] 3531 elif nameSubStr[-10:] == "Properties": 3532 infix = nameSubStr[-10:] 3533 nameSubStr = nameSubStr[:-10] 3534 if (nameSubStr in UNSUFFIXED_STRUCTURES): 3535 suffix = "" 3536 nameSubStr = nameSubStr + infix + suffix 3537 stream.append(pattern.format(fop.structureTypeName, nameSubStr)) 3538 writeInlFile(filename, INL_HEADER, indentLines(stream)) 3539 3540def writeDeviceFeaturesDefaultDeviceDefs(dfDefs, filename): 3541 pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceFeatures.getFeatureType<{0}>();\t}}" 3542 genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename) 3543 3544def writeDeviceFeaturesContextDecl(dfDefs, filename): 3545 pattern = "const vk::{0}&\tget{1}\t(void) const;" 3546 genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename) 3547 3548def writeDeviceFeaturesContextDefs(dfDefs, filename): 3549 pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}" 3550 genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename) 3551 3552def writeDevicePropertiesDefaultDeviceDefs(dfDefs, filename): 3553 pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceProperties.getPropertyType<{0}>();\t}}" 3554 genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename) 3555 3556def writeDevicePropertiesContextDecl(dfDefs, filename): 3557 pattern = "const vk::{0}&\tget{1}\t(void) const;" 3558 genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename) 3559 3560def writeDevicePropertiesContextDefs(dfDefs, filename): 3561 pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}" 3562 genericDeviceFeaturesOrPropertiesWriter(dfDefs, pattern, filename) 3563 3564def writeMandatoryFeatures(api, filename): 3565 3566 def structInAPI(name): 3567 for c in api.compositeTypes: 3568 if c.name == name: 3569 return True 3570 for alias in c.aliasList: 3571 if alias == name: 3572 return True 3573 return False 3574 stream = [] 3575 3576 dictStructs = {} 3577 dictData = [] 3578 extData = [] 3579 usedFeatureStructs = {} 3580 for _, data in api.additionalExtensionData: 3581 if 'mandatory_features' in data.keys(): 3582 # sort to have same results for py2 and py3 3583 listStructFeatures = sorted(data['mandatory_features'].items(), key=lambda tup: tup[0]) 3584 for structure, featuresList in listStructFeatures: 3585 for featureData in featuresList: 3586 # allow for featureless VKSC only extensions 3587 if not 'features' in featureData.keys() or 'requirements' not in featureData.keys(): 3588 continue 3589 requirements = featureData['requirements'] 3590 3591 mandatory_variant = '' 3592 try: 3593 mandatory_variant = featureData['mandatory_variant'] 3594 except KeyError: 3595 mandatory_variant = '' 3596 3597 dictData.append( [ structure, featureData['features'], requirements, mandatory_variant] ) 3598 3599 if structure == 'VkPhysicalDeviceFeatures': 3600 continue 3601 3602 # if structure is not in dict construct name of variable and add is as a first item 3603 if (structure not in dictStructs): 3604 dictStructs[structure] = ([structure[2:3].lower() + structure[3:]], mandatory_variant) 3605 # add first requirement if it is unique 3606 if requirements and (requirements[0] not in dictStructs[structure][0]): 3607 dictStructs[structure][0].append(requirements[0]) 3608 3609 usedFeatureStructs[structure] = [] 3610 3611 if requirements: 3612 for req in requirements: 3613 if '.' in req: 3614 req = req.split('.')[0] 3615 reqStruct = 'Vk' + req[0].upper() + req[1:] 3616 usedFeatureStructs[reqStruct] = [] 3617 3618 if 'mandatory_extensions' in data: 3619 mandatoryExtensions = [] 3620 for mandatoryExt in data['mandatory_extensions']: 3621 if 'extension' in mandatoryExt: 3622 extName = mandatoryExt.pop('extension') 3623 mandatoryExtensions.append((extName, mandatoryExt)) 3624 3625 for extension, extensionData in mandatoryExtensions: 3626 # requirements are actually mandatory. 3627 if 'requirements' not in extensionData: 3628 continue 3629 3630 requirements = extensionData['requirements'] 3631 mandatory_variant = '' if 'mandatory_variant' not in extensionData else extensionData['mandatory_variant'] 3632 extData.append((extension, requirements, mandatory_variant)) 3633 3634 for req in requirements: 3635 if '.' in req: 3636 req = req.split('.')[0] 3637 reqStruct = 'Vk' + req[0].upper() + req[1:] 3638 usedFeatureStructs[reqStruct] = [] 3639 3640 stream.extend(['bool canUseFeaturesStruct (const vector<VkExtensionProperties>& deviceExtensions, uint32_t usedApiVersion, const char* extension)', 3641 '{', 3642 '\treturn (isExtensionStructSupported(deviceExtensions, RequiredExtension(extension))', 3643 '\t\t\t|| isCoreDeviceExtension(usedApiVersion, extension));', 3644 '}', 3645 '', 3646 'bool checkBasicMandatoryFeatures(const vkt::Context& context)\n{', 3647 '\tif (!context.isInstanceFunctionalitySupported("VK_KHR_get_physical_device_properties2"))', 3648 '\t\tTCU_THROW(NotSupportedError, "Extension VK_KHR_get_physical_device_properties2 is not present");', 3649 '', 3650 '\tVkPhysicalDevice\t\t\t\t\tphysicalDevice\t\t= context.getPhysicalDevice();', 3651 '\tconst InstanceInterface&\t\t\tvki\t\t\t\t\t= context.getInstanceInterface();', 3652 '\tconst vector<VkExtensionProperties>\tdeviceExtensions\t= enumerateDeviceExtensionProperties(vki, physicalDevice, nullptr);', 3653 '\tconst uint32_t\t\t\t\t\t\tusedApiVersion\t\t= context.getUsedApiVersion();', 3654 '', 3655 '\ttcu::TestLog& log = context.getTestContext().getLog();', 3656 '\tvk::VkPhysicalDeviceFeatures2 coreFeatures;', 3657 '\tdeMemset(&coreFeatures, 0, sizeof(coreFeatures));', 3658 '\tcoreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;', 3659 '\tvoid** nextPtr = &coreFeatures.pNext;', 3660 '']) 3661 3662 # Find the extensions that added the required feature structs. 3663 class StructFoundContinue(Exception): 3664 pass 3665 3666 for usedStruct in usedFeatureStructs: 3667 for compType in api.compositeTypes: 3668 nameList = [compType.name] + compType.aliasList 3669 if usedStruct in nameList: 3670 # Found the official name list for the struct. 3671 for extension in api.extensions: 3672 try: 3673 for requirement in extension.requirementsList: 3674 for extensionStructure in requirement.newTypes: 3675 if extensionStructure.name in nameList: 3676 # Found extension for the struct. 3677 usedFeatureStructs[usedStruct].append(extension.name) 3678 raise StructFoundContinue 3679 except StructFoundContinue: 3680 pass 3681 3682 structList = sorted(usedFeatureStructs.items(), key=lambda tup: tup[0]) # sort to have same results for py2 and py3 3683 apiStructs = list( filter(lambda x : structInAPI(x[0]), structList)) # remove items not defined in current API 3684 varVariants = {} # Some variables are going to be declared only for specific variants. 3685 3686 for structName, extensions in apiStructs: 3687 # The variable name will be the structure name without the Vk prefix and starting in lowercase. 3688 newVar = structName[2].lower() + structName[3:] 3689 3690 metaCondition = '' 3691 if structName in dictStructs: 3692 mandatoryVariantList = dictStructs[structName][1] 3693 if len(mandatoryVariantList) > 0: 3694 mandatoryVariant = mandatoryVariantList[0] 3695 metaCondition = 'defined(CTS_USES_' + mandatoryVariant.upper() + ')' 3696 stream.append('#if ' + metaCondition) 3697 varVariants[newVar] = mandatoryVariant 3698 3699 stream.extend(['\tvk::' + structName + ' ' + newVar + ';', 3700 '\tdeMemset(&' + newVar + ', 0, sizeof(' + newVar + '));', 3701 '']) 3702 if len(extensions) > 0: 3703 canUseCond = '\tif (' 3704 for (i, extName) in enumerate(extensions): 3705 canUseCond += ' ' if i == 0 else ' || ' 3706 canUseCond += 'canUseFeaturesStruct(deviceExtensions, usedApiVersion, "' + extName + '")' 3707 canUseCond += ' )' 3708 stream.append(canUseCond) 3709 elif api.apiName == "vulkan" and structName in dictStructs: 3710 #reqs = v[0][1:] 3711 reqs = dictStructs[structName][0][1:] 3712 cond = 'if ( ' 3713 i = 0 3714 for req in reqs: 3715 if i > 0: 3716 cond = cond + ' || ' 3717 if (req.startswith("ApiVersion")): 3718 cond = cond + 'context.contextSupports(vk::' + req + ')' 3719 i += 1 3720 cond = cond + ' )' 3721 stream.append('\t' + cond) 3722 3723 stream.extend(['\t{', 3724 '\t\t' + newVar + '.sType = getStructureType<' + structName + '>();', 3725 '\t\t*nextPtr = &' + newVar + ';', 3726 '\t\tnextPtr = &' + newVar + '.pNext;', 3727 '\t}']) 3728 3729 if len(metaCondition) > 0: 3730 stream.append('#endif // ' + metaCondition) 3731 3732 stream.append('') 3733 3734 stream.extend(['\tcontext.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &coreFeatures);', 3735 '\tbool result = true;', 3736 '']) 3737 3738 for v in dictData: 3739 if not structInAPI(v[0]): # remove items not defined in current API ( important for Vulkan SC ) 3740 continue 3741 structType = v[0] 3742 structName = 'coreFeatures.features' 3743 metaCondition = '' 3744 if len(v) == 4 and v[3] != '': 3745 # for x in v[3].split('_'): 3746 metaCondition = metaCondition + ' || defined(CTS_USES_' + v[3][0].upper() + ')' 3747 stream.extend(['#if ' + metaCondition[4:]]) 3748 if v[0] != 'VkPhysicalDeviceFeatures' : 3749 structName = dictStructs[v[0]][0][0] 3750 if len(v[2]) > 0 : 3751 condition = 'if ( ' 3752 for i, req in enumerate(v[2]) : 3753 if (req.startswith("ApiVersion")): 3754 condition = condition + 'context.contextSupports(vk::' + req + ')' 3755 elif '.' in req: 3756 condition = condition + req 3757 else: 3758 condition = condition + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))' 3759 if i+1 < len(v[2]) : 3760 condition = condition + ' && ' 3761 condition = condition + ' )' 3762 stream.append('\t' + condition) 3763 stream.append('\t{') 3764 # Don't need to support an AND case since that would just be another line in the .txt 3765 reqMetaCondition = '' 3766 if len(v[1]) == 1: 3767 # If the req struct type has a mandatory variant we need to add an #ifdef block, unless we're already inside one. 3768 if len(metaCondition) == 0 and structName in varVariants: 3769 reqMetaCondition = 'defined(CTS_USES_' + varVariants[structName].upper() + ')' 3770 stream.append('#if ' + reqMetaCondition) 3771 stream.append('\t\tif ( ' + structName + '.' + v[1][0] + ' == VK_FALSE )') 3772 else: 3773 condition = 'if ( ' 3774 for i, feature in enumerate(v[1]): 3775 if i != 0: 3776 condition = condition + ' && ' 3777 condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )' 3778 condition = condition + ' )' 3779 stream.append('\t\t' + condition) 3780 featureSet = " or ".join(v[1]) 3781 stream.extend(['\t\t{', 3782 '\t\t\tlog << tcu::TestLog::Message << "Mandatory feature ' + featureSet + ' not supported" << tcu::TestLog::EndMessage;', 3783 '\t\t\tresult = false;', 3784 '\t\t}']) 3785 if reqMetaCondition != '': 3786 stream.append('#endif // ' + reqMetaCondition) 3787 stream.append('\t}') 3788 if metaCondition != '': 3789 stream.extend(['#endif // ' + metaCondition[4:], 3790 '']) 3791 else: 3792 stream.extend(['']) 3793 3794 for extension, requirements, mandatory_variant in extData: 3795 metaCondition = '' 3796 if mandatory_variant != '': 3797 metaCondition = metaCondition + ' || defined(CTS_USES_' + mandatory_variant[0].upper() + ')' 3798 stream.extend(['#if ' + metaCondition[4:]]) 3799 if len(requirements) > 0 : 3800 condition = 'if ( ' 3801 for i, req in enumerate(requirements) : 3802 if (req.startswith("ApiVersion")): 3803 condition = condition + 'context.contextSupports(vk::' + req + ')' 3804 elif '.' in req: 3805 condition = condition + req 3806 else: 3807 condition = condition + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))' 3808 if i+1 < len(requirements) : 3809 condition = condition + ' && ' 3810 condition = condition + ' )' 3811 stream.append('\t' + condition) 3812 stream.append('\t{') 3813 stream.extend(['\t\tif (!(isExtensionStructSupported(deviceExtensions, RequiredExtension("' + extension + '")) || isCoreDeviceExtension(usedApiVersion, "' + extension + '")))', 3814 '\t\t{', 3815 '\t\t\tlog << tcu::TestLog::Message << "Mandatory extension ' + extension + ' not supported" << tcu::TestLog::EndMessage;', 3816 '\t\t\tresult = false;', 3817 '\t\t}', 3818 '\t}']) 3819 if metaCondition != '': 3820 stream.extend(['#endif // ' + metaCondition[4:], 3821 '']) 3822 else: 3823 stream.append('') 3824 3825 stream.append('\treturn result;') 3826 stream.append('}\n') 3827 3828 writeInlFile(filename, INL_HEADER, stream) 3829 3830def writeExtensionList(api, filename, extensionType): 3831 extensionList = [] 3832 for extensionName, data in api.additionalExtensionData: 3833 # make sure extension name starts with VK_KHR 3834 if not extensionName.startswith('VK_KHR'): 3835 continue 3836 # make sure that this extension was registered 3837 if 'register_extension' not in data.keys(): 3838 continue 3839 # skip extensions that are not supported in Vulkan SC 3840 if api.apiName == 'vulkansc': 3841 if any(ext.name == extensionName for ext in api.notSupportedExtensions): 3842 continue 3843 # make sure extension is intended for the vulkan variant 3844 is_sc_only = False 3845 3846 if api.apiName != 'vulkansc': 3847 if 'mandatory_features' in data.keys(): 3848 for structure, listStruct in data['mandatory_features'].items(): 3849 for featureData in listStruct: 3850 mandatory_variant = '' 3851 try: 3852 mandatory_variant = featureData['mandatory_variant'] 3853 except KeyError: 3854 mandatory_variant = '' 3855 # VKSC only 3856 if 'vulkansc' in mandatory_variant: 3857 is_sc_only = True 3858 if is_sc_only: 3859 continue 3860 3861 # make sure extension has proper type 3862 if extensionType == data['register_extension']['type']: 3863 extensionList.append(extensionName) 3864 extensionList.sort() 3865 # write list of all found extensions 3866 stream = [] 3867 stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(extensionType.title())) 3868 for n in extensionList: 3869 stream.append('\t"' + n + '",') 3870 stream.append('};\n') 3871 writeInlFile(filename, INL_HEADER, stream) 3872 3873def transformDependsToCondition(depends, api, checkVersionString, checkExtensionString): 3874 depList = re.split(r'(\W+)', depends) 3875 for idx, depPart in enumerate(depList): 3876 if ',' in depPart: 3877 depList[idx] = depList[idx].replace(',', ' || ') 3878 elif '+' in depPart: 3879 depList[idx] = depList[idx].replace('+', ' && ') 3880 elif 'VK_' in depPart: 3881 if 'VK_VERSION' in depPart: 3882 if idx > 0 and ' || ' in depList[idx-1]: 3883 # some vk.xml entries include "promoted to" version preceded by logical OR operator in the extension "depends" attribute 3884 # script don't rely on this optional information and will find "promoted to" versions for all dependencies of all extensions in the below code 3885 # accordingly the one from vk.xml is ignored to avoid redundant isCompatibile() checks 3886 depList[idx-1] = depList[idx-1].replace(' || ', '') 3887 depList[idx] = '' 3888 continue 3889 # when dependency is vulkan version then replace it with proper condition 3890 depList[idx] = checkVersionString % (depPart[-3], depPart[-1]) 3891 else: 3892 # when dependency is extension check if it was promoted 3893 extNotFound = True 3894 for dExt in api.extensions: 3895 if depPart == dExt.name: 3896 depExtVector = 'vDEP' if dExt.type == 'device' else 'vIEP' 3897 isSupportedCheck = checkExtensionString % (depExtVector, depPart) 3898 if dExt.promotedto is not None: 3899 p = dExt.promotedto 3900 # check if dependency was promoted to vulkan version or other extension 3901 if 'VK_VERSION' in p: 3902 depList[idx] = f'({checkVersionString % (p[-3], p[-1])} || {isSupportedCheck})' 3903 else: 3904 depList[idx] = f'({checkExtensionString % (depExtVector, depPart)} || {isSupportedCheck})' 3905 else: 3906 depList[idx] = isSupportedCheck 3907 extNotFound = False 3908 break 3909 # for SC when extension was not found try checking also not supported 3910 # extensions and see if this extension is part of core 3911 if extNotFound and api.apiName == "vulkansc": 3912 for dExt in api.notSupportedExtensions: 3913 if depPart == dExt.name: 3914 p = dExt.promotedto 3915 if p is None: 3916 break 3917 if int(p[-1]) > 2: 3918 break 3919 extNotFound = False 3920 depList[idx] = "true" 3921 if extNotFound: 3922 assert False, f"{depPart} from dependencies ({depends}) not found" 3923 return ''.join(depList) 3924 3925def writeApiExtensionDependencyInfo(api, filename): 3926 3927 def genHelperFunctions(): 3928 yield 'using namespace tcu;' 3929 yield 'using ExtPropVect = std::vector<vk::VkExtensionProperties>;' 3930 yield 'using IsSupportedFun = bool (*)(const tcu::UVec2&, const ExtPropVect&, const ExtPropVect&);' 3931 yield 'using DependencyCheckVect = std::vector<std::pair<const char*, IsSupportedFun> >;\n' 3932 yield 'bool isCompatibile(uint32_t major, uint32_t minor, const tcu::UVec2& testedApiVersion)' 3933 yield '{' 3934 yield '\t// return true when tested api version is greater' 3935 yield '\t// or equal to version represented by two uints' 3936 yield '\tif (major == testedApiVersion.x())' 3937 yield '\t\treturn minor <= testedApiVersion.y();' 3938 yield '\treturn major < testedApiVersion.x();' 3939 yield '}\n' 3940 yield 'bool isSupported(const ExtPropVect& extensions, const char* ext)' 3941 yield '{' 3942 yield '\treturn isExtensionStructSupported(extensions, vk::RequiredExtension(ext));' 3943 yield '}\n' 3944 3945 def genExtDepArray(extType): 3946 extensionList = [] 3947 maxExtLength = 0 3948 extVector = 'vIEP' 3949 othVector = 'vDEP' 3950 if extType == 'device': 3951 extVector, othVector = othVector, extVector # swap 3952 # iterate over all extension that are of specified type and that have requirements 3953 for ext in api.extensions: 3954 if ext.type != extType: 3955 continue 3956 if ext.depends is None: 3957 continue 3958 # memorize extension name and dependencies for future vector generation 3959 extensionList.append(ext.name) 3960 # memorize max extension name and dependency length 3961 maxExtLength = max(maxExtLength, len(ext.name)) 3962 # generate check function for this extension 3963 yield f'bool check_{ext.name}(const tcu::UVec2& v, const ExtPropVect& vIEP, const ExtPropVect& vDEP)' 3964 yield '{' 3965 # check if extension was promoted; for SC we need to check vulkan version as sc10 is based on vk12 3966 if ext.promotedto is not None and 'VK_VERSION' in ext.promotedto: 3967 p = ext.promotedto 3968 yield f'\tif (isCompatibile({p[-3]}, {p[-1]}, v))' 3969 yield '\t\treturn true;\n' 3970 else: 3971 yield '\tDE_UNREF(v);' 3972 # there is a high chance that other vector won't be used 3973 yield f'\tDE_UNREF({othVector});' 3974 # check if extension is supported 3975 yield f'\n\tif (!isSupported({extVector}, "{ext.name}"))' 3976 yield '\t\treturn true;\n' 3977 # replace dependent extensions/versions with proper conditions 3978 finalCondition = transformDependsToCondition(ext.depends, api, 'isCompatibile(%s, %s, v)', 'isSupported(%s, "%s")') 3979 yield f'\t// depends attribute in xml: {ext.depends}' 3980 yield f'\treturn {finalCondition};' 3981 yield '}\n' 3982 # save list of all device/instance extensions 3983 yield 'static const DependencyCheckVect {}ExtensionDependencies'.format(extType) 3984 yield '{' 3985 for ext in extensionList: 3986 extTabCount = (maxExtLength - len(ext)) / 4 3987 eTabs = '\t'*int(round(extTabCount+1.49)) 3988 yield f'\tstd::make_pair("{ext}",{eTabs}&check_{ext}),' 3989 yield '};\n' 3990 3991 def genApiVersions(): 3992 yield 'static const std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>\treleasedApiVersions[]\t=' 3993 yield '{' 3994 for f in reversed(api.features): 3995 apiVariant = '0' if f.api == 'vulkan' else '1' 3996 major, minor = f.number.split('.') 3997 version = (int(apiVariant) << 29) | (int(major) << 22) | (int(minor) << 12) 3998 yield '\tstd::make_tuple({}, {}, {}, {}),'.format(version, apiVariant, major, minor) 3999 yield '};' 4000 4001 def parseExtensionDependencies(extDeps, ext): 4002 major, minor = 1, 0 4003 requiredVerFound = False; 4004 # return in case nothing more left to be processed 4005 if extDeps is None or extDeps == "": 4006 return major, minor, requiredVerFound 4007 ungrpPartLen = 0 4008 versionPattern = "[A-Z]+_VERSION_([0-9]+)_([0-9]+)" 4009 ungroupedPattern = r"^.*?\(+|^.*?$" 4010 # look for non-grouped part, it may include the required vulkan version 4011 ungroupPart = re.search(ungroupedPattern, extDeps) 4012 if ungroupPart is not None and ungroupPart[0].replace(r"(", "") != "": 4013 ungrpPartLen = len(ungroupPart[0].replace(r"(", "")) 4014 # is specific version explicitly requested? 4015 match = re.search(versionPattern, ungroupPart[0]) 4016 if match is not None: 4017 if len(match[0]) != len(extDeps): 4018 # there is more than just a version; check if it's accompanied by AND operator(s) 4019 ext_pattern = r".*\+*"+versionPattern+r"\++.*|.*\++"+versionPattern+r"\+*.*" 4020 match = re.search(ext_pattern, ungroupPart[0]) 4021 if match is not None: 4022 # specific version is explicitly requested 4023 major, minor = int(match[1]), int(match[2]) 4024 return major, minor, True 4025 # no explicit version is requested, continue parsing the remaining part 4026 extDeps = extDeps[ungrpPartLen:] 4027 groupedPattern = r"(.*)\+|(.*)$" 4028 match = re.search(groupedPattern, extDeps) 4029 if match is not None and match[0] != "": 4030 # groups may include the dependency "promoted to" versions accompanied by OR operator 4031 # but they don't include the extension explicit required version; continue parsing the remaining part 4032 groupLength = len(match[0]) 4033 major, minor, requiredVerFound = parseExtensionDependencies(extDeps[groupLength:], ext) 4034 return major, minor, requiredVerFound 4035 4036 def genRequiredCoreVersions(): 4037 yield 'static const std::tuple<uint32_t, uint32_t, const char*>\textensionRequiredCoreVersion[]\t =' 4038 yield '{' 4039 versionPattern = "[A-Z]+_VERSION_([0-9]+)_([0-9]+)" 4040 for ext in api.extensions: 4041 # skip video extensions 4042 if 'vulkan_video_' in ext.name: 4043 continue 4044 major, minor = 1, 0 4045 if ext.depends is not None: 4046 major, minor, requiredVerFound = parseExtensionDependencies(ext.depends, ext) 4047 if not requiredVerFound: 4048 # find all extensions that are dependencies of this one 4049 matches = re.findall(r"VK_\w+", ext.depends, re.M) 4050 for m in matches: 4051 for de in api.extensions: 4052 if de.name == m: 4053 if de.depends is not None: 4054 # check if the dependency states explicitly the required vulkan version and pick the higher one 4055 newMajor, newMinor, requiredVerFound = parseExtensionDependencies(de.depends, de) 4056 if requiredVerFound: 4057 if newMajor > major: 4058 major, minor = newMajor, newMinor 4059 elif newMajor == major and newMinor > minor: 4060 minor = newMinor 4061 break 4062 yield '\tstd::make_tuple({}, {}, "{}"),'.format(major, minor, ext.name) 4063 yield '};' 4064 4065 stream = [] 4066 stream.extend(genHelperFunctions()) 4067 stream.extend(genExtDepArray('instance')) 4068 stream.extend(genExtDepArray('device')) 4069 stream.extend(genApiVersions()) 4070 stream.extend(genRequiredCoreVersions()) 4071 4072 writeInlFile(filename, INL_HEADER, stream) 4073 4074def writeEntryPointValidation(api, filename): 4075 # keys are instance extension names and value is list of device-level functions 4076 instExtDeviceFunDict = {} 4077 # iterate over all extensions and find instance extensions 4078 for ext in api.extensions: 4079 if ext.type == "instance": 4080 # iterate over all functions instance extension adds 4081 for requirement in ext.requirementsList: 4082 for extCommand in requirement.newCommands: 4083 # to get a type of command we need to find this command definition in list of all functions 4084 for command in api.functions: 4085 if extCommand.name == command.name or extCommand.name in command.aliasList: 4086 # check if this is device-level entry-point 4087 if command.getType() == Function.TYPE_DEVICE: 4088 if ext.name not in instExtDeviceFunDict: 4089 instExtDeviceFunDict[ext.name] = [] 4090 instExtDeviceFunDict[ext.name].append(extCommand.name) 4091 stream = ['std::map<std::string, std::vector<std::string> > instExtDeviceFun', '{'] 4092 for extName in instExtDeviceFunDict: 4093 stream.append(f'\t{{ "{extName}",\n\t\t{{') 4094 for fun in instExtDeviceFunDict[extName]: 4095 stream.append(f'\t\t\t"{fun}",') 4096 stream.append('\t\t}\n\t},') 4097 stream.append('};') 4098 writeInlFile(filename, INL_HEADER, stream) 4099 4100def writeGetDeviceProcAddr(api, filename): 4101 testBlockStart = '''tcu::TestStatus testGetDeviceProcAddr (Context& context) 4102{ 4103 tcu::TestLog& log (context.getTestContext().getLog()); 4104 const PlatformInterface& platformInterface = context.getPlatformInterface(); 4105 const auto validationEnabled = context.getTestContext().getCommandLine().isValidationEnabled(); 4106 const CustomInstance instance (createCustomInstanceFromContext(context)); 4107 const InstanceDriver& instanceDriver = instance.getDriver(); 4108 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); 4109 const uint32_t queueFamilyIndex = 0; 4110 const uint32_t queueCount = 1; 4111 const float queuePriority = 1.0f; 4112 const std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice); 4113 4114 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = 4115 { 4116 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType; 4117 nullptr, // const void* pNext; 4118 (VkDeviceQueueCreateFlags)0u, // VkDeviceQueueCreateFlags flags; 4119 queueFamilyIndex, // uint32_t queueFamilyIndex; 4120 queueCount, // uint32_t queueCount; 4121 &queuePriority, // const float* pQueuePriorities; 4122 }; 4123 4124 const VkDeviceCreateInfo deviceCreateInfo = 4125 { 4126 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType; 4127 nullptr, // const void* pNext; 4128 (VkDeviceCreateFlags)0u, // VkDeviceCreateFlags flags; 4129 1u, // uint32_t queueCreateInfoCount; 4130 &deviceQueueCreateInfo, // const VkDeviceQueueCreateInfo* pQueueCreateInfos; 4131 0u, // uint32_t enabledLayerCount; 4132 nullptr, // const char* const* ppEnabledLayerNames; 4133 0u, // uint32_t enabledExtensionCount; 4134 nullptr, // const char* const* ppEnabledExtensionNames; 4135 nullptr, // const VkPhysicalDeviceFeatures* pEnabledFeatures; 4136 }; 4137 const Unique<VkDevice> device (createCustomDevice(validationEnabled, platformInterface, instance, instanceDriver, physicalDevice, &deviceCreateInfo)); 4138 const DeviceDriver deviceDriver (platformInterface, instance, device.get(), context.getUsedApiVersion(), context.getTestContext().getCommandLine()); 4139 4140 const std::vector<std::string> functions{''' 4141 testBlockEnd = ''' }; 4142 4143 bool fail = false; 4144 for (const auto& function : functions) 4145 { 4146 if (deviceDriver.getDeviceProcAddr(device.get(), function.c_str()) != nullptr) 4147 { 4148 fail = true; 4149 log << tcu::TestLog::Message << "Function " << function << " is not NULL" << tcu::TestLog::EndMessage; 4150 } 4151 } 4152 if (fail) 4153 return tcu::TestStatus::fail("Fail"); 4154 return tcu::TestStatus::pass("All functions are NULL"); 4155} 4156''' 4157 4158 def functions(functionType): 4159 for ext in api.extensions: 4160 for requirement in ext.requirementsList: 4161 for requiredCommand in requirement.newCommands: 4162 yield '\t\t"' + requiredCommand.name + '",' 4163 stream = [] 4164 stream.append('#include "tcuCommandLine.hpp"') 4165 stream.append('#include "vktTestCase.hpp"') 4166 stream.append('#include "vkPlatform.hpp"') 4167 stream.append('#include "vkDeviceUtil.hpp"') 4168 stream.append('#include "vkQueryUtil.hpp"') 4169 stream.append('#include "vktCustomInstancesDevices.hpp"') 4170 stream.append('#include "vktTestCase.hpp"') 4171 stream.append('#include "vktTestCaseUtil.hpp"') 4172 stream.append('\nnamespace vkt\n{\n') 4173 stream.append('using namespace vk;\n') 4174 stream.append(testBlockStart) 4175 stream.extend(functions(api)) 4176 stream.append(testBlockEnd) 4177 4178 # function to create tests 4179 stream.append("void addGetDeviceProcAddrTests (tcu::TestCaseGroup* testGroup)\n{") 4180 stream.append('\taddFunctionCase(testGroup, "non_enabled", testGetDeviceProcAddr);') 4181 stream.append('}\n') 4182 stream.append('}\n') 4183 4184 writeInlFile(filename, INL_HEADER, stream) 4185 4186def writeProfileTests(inlFileName, jsonFilesList): 4187 4188 # helper function; workaround for lack of information in json about limit type 4189 def getLimitMacro(propName, propComponent): 4190 maxUintPropNames = ["bufferImageGranularity", "storageTexelBufferOffsetAlignmentBytes",\ 4191 "robustUniformBufferAccessSizeAlignment", "shaderWarpsPerSM",\ 4192 "perViewPositionAllComponents", "minTexelBufferOffsetAlignment",\ 4193 "minUniformBufferOffsetAlignment"] 4194 minFloatPropNames = ["maxSamplerLodBias"] 4195 maxFloatPropNames = ["pointSizeGranularity", "lineWidthGranularity"] 4196 minDevSizePropNames = ["maxBufferSize"] 4197 if propName in maxUintPropNames: 4198 return "LIM_MAX_UINT32" 4199 elif propName in minFloatPropNames: 4200 return "LIM_MIN_FLOAT" 4201 elif propName in maxFloatPropNames: 4202 return "LIM_MAX_FLOAT" 4203 elif propName in minDevSizePropNames: 4204 return "LIM_MIN_DEVSIZE" 4205 elif propName.endswith("SampleCounts"): 4206 return "LIM_MIN_BITI32" 4207 elif not propName.startswith("max") and propName.endswith("Range"): 4208 return "LIM_MAX_FLOAT" if propComponent == 0 else "LIM_MIN_FLOAT" 4209 return "LIM_MIN_UINT32" 4210 4211 # helper function that adds property or feature structures to lists of struct initializers 4212 def constructStruct(structName, structInitNamesList, structInitList): 4213 # skip structures that already are in the chain 4214 if structName in structInitNamesList: 4215 return 4216 structInitNamesList.append(structName) 4217 # construct structure instance and connect it to chain 4218 parentStruct = "" if (len(structInitNamesList) == 3) else "&vk" + structInitNamesList[-2] 4219 structInitList.append(f"\tVkPhysicalDevice{structName} vk{structName} = initVulkanStructure({parentStruct});") 4220 4221 # helper function handling strings representing property limit checks 4222 def addPropertyEntries(structName, propName, propLimit, propertyTableItems): 4223 if propName == "driverName": 4224 return 4225 propSubItems = [(propName, propLimit)] 4226 combinedStructName = structName 4227 # checkk if propLimit is actualy a dictionary this will be the case when propName is "limits"; 4228 # in that case we have to get all sub items and add all of them to propertyTableItems 4229 if isinstance(propLimit, dict): 4230 propSubItems = propLimit.items() 4231 combinedStructName += "." + propName 4232 # usualy we will add just one item but we need to handle cases where there is more 4233 for name, limit in propSubItems: 4234 limitComponentCount = 1 4235 if isinstance(limit, list): 4236 limitComponentCount = len(limit) 4237 # handle special case like storageImageSampleCounts 4238 if limitComponentCount == 1: 4239 limit = limit[0] 4240 componentAccessFormat = "" 4241 if limitComponentCount > 1: 4242 # if limit is list of strings joint them together; 4243 # e.g. this is the case for subgroupSupportedStages 4244 if isinstance(limit[0], str): 4245 limitComponentCount = 1 4246 limit = "|".join(limit) 4247 else: 4248 componentAccessFormat = "[{}]" 4249 # handle case where limit is represented by more than one value; 4250 # in that case we will add as many entries to propertyTableItems as there are limiting values 4251 for i in range(limitComponentCount): 4252 componentAccess = componentAccessFormat.format(i) 4253 limitMacro = getLimitMacro(name, i) 4254 limitValue = "true" if limit == True else limit 4255 if limitValue == False: 4256 limitValue = "false" 4257 limitValue = limitValue[i] if limitComponentCount > 1 else limitValue 4258 propertyTableItems += [f"PN({combinedStructName}.{name}{componentAccess}), {limitMacro}({limitValue})"] 4259 4260 vkpdLen = len("VkPhysicalDevice") 4261 profilesList = [] 4262 stream = [] 4263 4264 for jsonFile in jsonFilesList: 4265 jsonContent = readFile(jsonFile) 4266 profilesDict = json.loads(jsonContent) 4267 capabilitiesDefinitionsDict = profilesDict["capabilities"] 4268 4269 for profileName, profileData in reversed(profilesDict["profiles"].items()): 4270 featureStructInitList = [] 4271 featureStructInitNamesList = ["Features", "Features2"] 4272 featureTableItems = [] 4273 propertyStructInitList = [] 4274 propertyStructInitNamesList = ["Properties", "Properties2"] 4275 propertyTableItems = [] 4276 extensionList = [] 4277 formatsList = [] 4278 highestMajor = 1 4279 highestMinor = 0 4280 4281 allCapabilities = profileData["capabilities"] + profileData.get("optionals", []) 4282 for capability in allCapabilities: 4283 capabilityList = capability if isinstance(capability, list) else [capability] 4284 for capabilityName in capabilityList: 4285 capabilityDefinition = capabilitiesDefinitionsDict[capabilityName] 4286 # identify highest required vulkan version 4287 match = re.match(r"vulkan(\d)(\d)requirements", capabilityName) 4288 if match is not None: 4289 major, minor = int(match.group(1)), int (match.group(2)) 4290 if major*10 + minor > highestMajor * 10 + highestMinor: 4291 highestMajor, highestMinor = major, minor 4292 if "features" in capabilityDefinition: 4293 featureStructList = capabilityDefinition["features"] 4294 # skip adding comment for empty requirements 4295 if len(featureStructList) == 1 and not list(featureStructList.values())[0]: 4296 continue 4297 featureTableItems.append(f"\t\t// {capabilityName}"); 4298 # iterate over required features 4299 for featureStruct in featureStructList: 4300 structName = featureStruct[vkpdLen:] 4301 constructStruct(structName, featureStructInitNamesList, featureStructInitList) 4302 for feature in featureStructList[featureStruct]: 4303 featureTableItems.append(f"vk{structName}, {feature}") 4304 featureTableItems.append("") 4305 if "properties" in capabilityDefinition: 4306 propertyStructList = capabilityDefinition["properties"] 4307 propertyTableItems.append(f"\t\t// {capabilityName}"); 4308 for propertyStruct in propertyStructList: 4309 structName = propertyStruct[vkpdLen:] 4310 constructStruct(structName, propertyStructInitNamesList, propertyStructInitList) 4311 for propName, propLimit in propertyStructList[propertyStruct].items(): 4312 addPropertyEntries("vk" + structName, propName, propLimit, propertyTableItems) 4313 propertyTableItems.append("") 4314 if "extensions" in capabilityDefinition: 4315 extensionList = [n for n in capabilityDefinition["extensions"]] 4316 if "formats" in capabilityDefinition: 4317 formatsList = capabilityDefinition["formats"] 4318 4319 # remove empty lines at the end 4320 featureTableItems.pop() 4321 propertyTableItems.pop() 4322 4323 # remove "VP_KHR_" from roadmap profile name 4324 if "VP_KHR_" in profileName: 4325 profileName = profileName[7:] 4326 # lower letters for all profile names 4327 profileName = profileName.lower() 4328 4329 # template used to get both device features and device properties 4330 structGetterTemplate = "\n"\ 4331 "\tVkPhysicalDevice{0}2 vk{0}2 = initVulkanStructure(&vk{2});\n"\ 4332 "\tauto& vk{0} = vk{0}2.{1};\n"\ 4333 "\tvki.getPhysicalDevice{0}2(pd, &vk{0}2);\n" 4334 4335 # construct function that will validate profile 4336 stream.append(f"tcu::TestStatus validate_{profileName}(Context& context)") 4337 4338 stream.append("{\n" 4339 "\tconst VkBool32 checkAlways = true;\n" 4340 "\tbool oneOrMoreChecksFailed = false;\n" 4341 "\tauto pd = context.getPhysicalDevice();\n" 4342 "\tconst auto &vki = context.getInstanceInterface();\n" 4343 "\tTestLog& log = context.getTestContext().getLog();\n") 4344 4345 stream.extend(featureStructInitList) 4346 stream.append(structGetterTemplate.format("Features", "features", featureStructInitNamesList[-1])) 4347 stream.extend(propertyStructInitList) 4348 stream.append(structGetterTemplate.format("Properties", "properties", propertyStructInitNamesList[-1])) 4349 if len(featureTableItems): 4350 stream.append("\tconst std::vector<FeatureEntry> featureTable {") 4351 stream.extend(["\t\tROADMAP_FEATURE_ITEM(" + f + ")," if ("," in f) else f for f in featureTableItems]) 4352 stream.append("\t};\n" 4353 "\tfor (const auto &testedFeature : featureTable)\n" 4354 "\t{\n" 4355 "\t if (!testedFeature.fieldPtr[0])\n" 4356 "\t {\n" 4357 "\t log << TestLog::Message\n" 4358 "\t << \"Feature \" << testedFeature.fieldName << \" is not supported\"\n" 4359 "\t << TestLog::EndMessage;\n" 4360 "\t oneOrMoreChecksFailed = true;\n" 4361 "\t }\n" 4362 "\t}\n") 4363 if len(propertyTableItems): 4364 stream.append("\tconst std::vector<FeatureLimitTableItem> propertyTable {") 4365 stream.extend(["\t\t{ PN(checkAlways), " + p + " }," if ("," in p) else p for p in propertyTableItems]) 4366 stream.append("\t};\n" 4367 "\tfor (const auto& testedProperty : propertyTable)\n" 4368 "\t oneOrMoreChecksFailed |= !validateLimit(testedProperty, log);\n") 4369 if len(extensionList): 4370 stream.append("\tstd::vector<std::string> extensionList {") 4371 stream.append('\t\t"' + '",\n\t\t"'.join(extensionList) + '"') 4372 stream.append("\t};\n" 4373 "\tconst auto deviceExtensions = enumerateDeviceExtensionProperties(vki, pd, nullptr);\n" 4374 "\tfor (const auto& testedExtension : extensionList)\n" 4375 "\t{\n" 4376 "\t if (isExtensionStructSupported(deviceExtensions, RequiredExtension(testedExtension)) ||\n" 4377 "\t context.isInstanceFunctionalitySupported(testedExtension))\n" 4378 "\t continue;\n" 4379 "\t log << TestLog::Message\n" 4380 "\t << testedExtension << \" is not supported\"\n" 4381 "\t << TestLog::EndMessage;\n" 4382 "\t oneOrMoreChecksFailed = true;\n" 4383 "\t}") 4384 if len(formatsList): 4385 stream.append("\n\tstd::vector<FormatEntry> formatsList {") 4386 for formatName, formatProperties in formatsList.items(): 4387 formatProperties = formatProperties["VkFormatProperties"] 4388 linearTilingFeatures = formatProperties["linearTilingFeatures"] 4389 linearTilingFeatures = "0" if not linearTilingFeatures else linearTilingFeatures 4390 optimalTilingFeatures = formatProperties["optimalTilingFeatures"] 4391 optimalTilingFeatures = "0" if not optimalTilingFeatures else optimalTilingFeatures 4392 bufferFeatures = formatProperties["bufferFeatures"] 4393 bufferFeatures = "0" if not bufferFeatures else bufferFeatures 4394 stream.append(f"""\t\t{{ {formatName}, "{formatName}", 4395 {{ {"|".join(linearTilingFeatures)}, 4396 {"|".join(optimalTilingFeatures)}, 4397 {"|".join(bufferFeatures)} }} }},""") 4398 stream.append("\t};\n" 4399 "\t\tVkFormatProperties supportedFormatPropertiess;\n" 4400 "\t\tfor (const auto& [f, fn, fp] : formatsList)\n" 4401 "\t\t{\n" 4402 "\t\t vki.getPhysicalDeviceFormatProperties(pd, f, &supportedFormatPropertiess);\n" 4403 "\t\t if (((fp.linearTilingFeatures & supportedFormatPropertiess.linearTilingFeatures) == fp.linearTilingFeatures) &&\n" 4404 "\t\t ((fp.optimalTilingFeatures & supportedFormatPropertiess.optimalTilingFeatures) == fp.optimalTilingFeatures) &&\n" 4405 "\t\t ((fp.bufferFeatures & supportedFormatPropertiess.bufferFeatures) == fp.bufferFeatures))\n" 4406 "\t\t continue;\n" 4407 "\t\t log << TestLog::Message\n" 4408 "\t\t << \"Required format properties for \" << fn << \" are not supported\"\n" 4409 "\t\t << TestLog::EndMessage;\n" 4410 "\t\t oneOrMoreChecksFailed = true;\n" 4411 "\t\t}\n") 4412 4413 stream.append("\n" 4414 "\tif (oneOrMoreChecksFailed)\n" 4415 "\t TCU_THROW(NotSupportedError, \"Profile not supported\");\n" 4416 "\treturn tcu::TestStatus::pass(\"Profile supported\");\n}\n") 4417 4418 profilesList.append(f"\t{{ \"{profileName}\", checkApiVersionSupport<{highestMajor}, {highestMinor}>, validate_{profileName} }},") 4419 4420 # save list of all callbacks 4421 stream.append("static const std::vector<ProfileEntry> profileEntries {") 4422 stream.extend(profilesList) 4423 stream.append("};") 4424 4425 writeInlFile(inlFileName, INL_HEADER, stream) 4426 4427def writeConformanceVersions(api, filename): 4428 logging.debug("Preparing to generate " + filename) 4429 # get list of all vulkan/vulkansc tags from git 4430 remote_urls = os.popen("git remote -v").read().split('\n') 4431 remote_url = None 4432 url_regexp = r'\bgerrit\.khronos\.org\b.*\bvk-gl-cts\b' 4433 for line in remote_urls: 4434 if re.search(url_regexp, line, re.IGNORECASE) is not None: 4435 remote_url = line.split()[1] 4436 break 4437 listOfTags = os.popen("git ls-remote -t %s" % (remote_url)).read() 4438 pattern = r"vulkan-cts-(\d).(\d).(\d).(\d)" 4439 if args.api == 'SC': 4440 pattern = r"vulkansc-cts-(\d).(\d).(\d).(\d)" 4441 matches = re.findall(pattern, listOfTags, re.M) 4442 if len(matches) == 0: 4443 return 4444 # read all text files in doc folder and find withdrawn cts versions (branches) 4445 withdrawnBranches = set() 4446 today = datetime.date.today() 4447 docFiles = glob.glob(os.path.join(os.path.dirname(__file__), "..", "doc", "*.txt")) 4448 for fileName in docFiles: 4449 if "withdrawal" not in fileName: 4450 continue 4451 fileContent = readFile(fileName) 4452 # get date when releases are withdrawn 4453 match = re.search(r"(20\d\d)-(\d\d)-(\d\d).+ withdrawn", fileContent, re.IGNORECASE) 4454 if match is not None: 4455 # check if announcement refers to date in the past 4456 if today > datetime.date(int(match[1]), int(match[2]), int(match[3])): 4457 # get names of withdrawn branches 4458 branchMatches = re.findall(pattern, fileContent, re.M) 4459 for v in branchMatches: 4460 withdrawnBranches.add((v[0], v[1], v[2], v[3])) 4461 # define helper function that will be used to add entries for both vk and sc 4462 def appendToStream(stream, versionsToAdd, maxWithdrawnVersion): 4463 addedVersions = set() 4464 for v in reversed(versionsToAdd): 4465 # add only unique versions; ignore duplicates (e.g. with "-rc1", "-rc2" postfix); 4466 # also add versions that are greater than maximal withdrawn version 4467 if v in addedVersions or v <= maxWithdrawnVersion: 4468 continue 4469 addedVersions.add(v) 4470 stream.append(f'\tmakeConformanceVersion({v[0]}, {v[1]}, {v[2]}, {v[3]}),') 4471 # save array with versions 4472 stream = ['static const VkConformanceVersion knownConformanceVersions[]', 4473 '{'] 4474 appendToStream(stream, matches, tuple('0'*4) if len(withdrawnBranches) == 0 else max(withdrawnBranches)) 4475 stream.append('};') 4476 writeInlFile(filename, INL_HEADER, stream) 4477 4478def parseCmdLineArgs(): 4479 parser = argparse.ArgumentParser(description = "Generate Vulkan INL files", 4480 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 4481 parser.add_argument("-a", 4482 "--api", 4483 dest="api", 4484 default="", 4485 help="Choose between Vulkan and Vulkan SC") 4486 parser.add_argument("-o", 4487 "--outdir", 4488 dest="outdir", 4489 default="", 4490 help="Choose output directory") 4491 parser.add_argument("-v", "--verbose", 4492 dest="verbose", 4493 action="store_true", 4494 help="Enable verbose logging") 4495 return parser.parse_args() 4496 4497if __name__ == "__main__": 4498 args = parseCmdLineArgs() 4499 initializeLogger(args.verbose) 4500 4501 # if argument was specified it is interpreted as a path to which .inl files will be written 4502 outputPath = DEFAULT_OUTPUT_DIR[args.api] if args.outdir == '' else args.outdir 4503 4504 vkTree = etree.parse(os.path.join(VULKAN_XML_DIR, "vk.xml")) 4505 apiName = "vulkansc" if args.api == 'SC' else "vulkan" 4506 4507 # Read vk.xml and generate vulkan headers from it 4508 api = API(apiName) 4509 api.build(vkTree) 4510 api.postProcess() 4511 4512 # Read video.xml 4513 if args.api != 'SC': 4514 api.build( etree.parse(os.path.join(VULKAN_XML_DIR, "video.xml")) ) 4515 4516 platformFuncs = [Function.TYPE_PLATFORM] 4517 instanceFuncs = [Function.TYPE_INSTANCE] 4518 deviceFuncs = [Function.TYPE_DEVICE] 4519 4520 dfd = generateDeviceFeaturesOrPropertiesDefs(api, 'Features') 4521 writeDeviceFeatures (api, dfd, os.path.join(outputPath, "vkDeviceFeatures.inl")) 4522 writeDeviceFeaturesDefaultDeviceDefs (dfd, os.path.join(outputPath, "vkDeviceFeaturesForDefaultDeviceDefs.inl")) 4523 writeDeviceFeaturesContextDecl (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDecl.inl")) 4524 writeDeviceFeaturesContextDefs (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDefs.inl")) 4525 writeDeviceFeatureTest (api, os.path.join(outputPath, "vkDeviceFeatureTest.inl")) 4526 4527 dpd = generateDeviceFeaturesOrPropertiesDefs(api, 'Properties') 4528 writeDeviceProperties (api, dpd, os.path.join(outputPath, "vkDeviceProperties.inl")) 4529 writeDevicePropertiesDefaultDeviceDefs (dpd, os.path.join(outputPath, "vkDevicePropertiesForDefaultDeviceDefs.inl")) 4530 writeDevicePropertiesContextDecl (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDecl.inl")) 4531 writeDevicePropertiesContextDefs (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDefs.inl")) 4532 4533 writeHandleType (api, os.path.join(outputPath, "vkHandleType.inl")) 4534 writeBasicTypes (api, os.path.join(outputPath, "vkBasicTypes.inl")) 4535 writeCompositeTypes (api, os.path.join(outputPath, "vkStructTypes.inl")) 4536 writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualPlatformInterface.inl"), platformFuncs, False) 4537 writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualInstanceInterface.inl"), instanceFuncs, False) 4538 writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualDeviceInterface.inl"), deviceFuncs, False) 4539 writeInterfaceDecl (api, os.path.join(outputPath, "vkConcretePlatformInterface.inl"), platformFuncs, True) 4540 writeInterfaceDecl (api, os.path.join(outputPath, "vkConcreteInstanceInterface.inl"), instanceFuncs, True) 4541 writeInterfaceDecl (api, os.path.join(outputPath, "vkConcreteDeviceInterface.inl"), deviceFuncs, True) 4542 writeFunctionPtrTypes (api, os.path.join(outputPath, "vkFunctionPointerTypes.inl")) 4543 writeFunctionPointers (api, os.path.join(outputPath, "vkPlatformFunctionPointers.inl"), platformFuncs) 4544 writeFunctionPointers (api, os.path.join(outputPath, "vkInstanceFunctionPointers.inl"), instanceFuncs) 4545 writeFunctionPointers (api, os.path.join(outputPath, "vkDeviceFunctionPointers.inl"), deviceFuncs) 4546 writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitPlatformFunctionPointers.inl"), platformFuncs, lambda f: f.name != "vkGetInstanceProcAddr") 4547 writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitInstanceFunctionPointers.inl"), instanceFuncs) 4548 writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitDeviceFunctionPointers.inl"), deviceFuncs) 4549 writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkPlatformDriverImpl.inl"), platformFuncs, "PlatformDriver") 4550 writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkInstanceDriverImpl.inl"), instanceFuncs, "InstanceDriver") 4551 writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkDeviceDriverImpl.inl"), deviceFuncs, "DeviceDriver") 4552 writeStrUtilProto (api, os.path.join(outputPath, "vkStrUtil.inl")) 4553 writeStrUtilImpl (api, os.path.join(outputPath, "vkStrUtilImpl.inl")) 4554 writeRefUtilProto (api, os.path.join(outputPath, "vkRefUtil.inl")) 4555 writeRefUtilImpl (api, os.path.join(outputPath, "vkRefUtilImpl.inl")) 4556 writeStructTraitsImpl (api, os.path.join(outputPath, "vkGetStructureTypeImpl.inl")) 4557 writeNullDriverImpl (api, os.path.join(outputPath, "vkNullDriverImpl.inl")) 4558 writeTypeUtil (api, os.path.join(outputPath, "vkTypeUtil.inl")) 4559 writeSupportedExtensions (api, os.path.join(outputPath, "vkSupportedExtensions.inl")) 4560 writeCoreFunctionalities (api, os.path.join(outputPath, "vkCoreFunctionalities.inl")) 4561 writeExtensionFunctions (api, os.path.join(outputPath, "vkExtensionFunctions.inl")) 4562 writeDeviceFeatures2 (api, os.path.join(outputPath, "vkDeviceFeatures2.inl")) 4563 writeMandatoryFeatures (api, os.path.join(outputPath, "vkMandatoryFeatures.inl")) 4564 writeExtensionList (api, os.path.join(outputPath, "vkInstanceExtensions.inl"), 'instance') 4565 writeExtensionList (api, os.path.join(outputPath, "vkDeviceExtensions.inl"), 'device') 4566 writeDriverIds (api, os.path.join(outputPath, "vkKnownDriverIds.inl")) 4567 writeObjTypeImpl (api, os.path.join(outputPath, "vkObjTypeImpl.inl")) 4568 writeApiExtensionDependencyInfo (api, os.path.join(outputPath, "vkApiExtensionDependencyInfo.inl")) 4569 writeEntryPointValidation (api, os.path.join(outputPath, "vkEntryPointValidation.inl")) 4570 writeGetDeviceProcAddr (api, os.path.join(outputPath, "vkGetDeviceProcAddr.inl")) 4571 #writeConformanceVersions (api, os.path.join(outputPath, "vkKnownConformanceVersions.inl")) 4572 if args.api=='SC': 4573 writeFuncPtrInterfaceSCImpl(api, os.path.join(outputPath, "vkDeviceDriverSCImpl.inl"), deviceFuncs, "DeviceDriverSC") 4574 else: 4575 profileList = [os.path.join(VULKAN_XML_DIR, "profiles", "VP_KHR_roadmap.json")] 4576 #profileList += [os.path.join(VULKAN_XML_DIR, "profiles", "VP_ANDROID_baseline_2022.json"] 4577 writeProfileTests(os.path.join(outputPath, "vkProfileTests.inl"), profileList) 4578 4579 # NOTE: when new files are generated then they should also be added to the 4580 # vk-gl-cts\external\vulkancts\framework\vulkan\CMakeLists.txt outputs list 4581