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 copy 27import glob 28import json 29import argparse 30from lxml import etree 31from itertools import chain 32from collections import OrderedDict 33 34sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts")) 35 36from ctsbuild.common import DEQP_DIR, execute 37from khr_util.format import indentLines, writeInlFile 38 39VULKAN_XML_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "xml") 40SCRIPTS_SRC_DIR = os.path.join(os.path.dirname(__file__), "src") 41DEFAULT_OUTPUT_DIR = { "" : os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkan"), 42 "SC" : os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkansc") } 43 44INL_HEADER = """\ 45/* WARNING: This is auto-generated file. Do not modify, since changes will 46 * be lost! Modify the generating script instead. 47 * This file was generated by /scripts/gen_framework.py 48 */\ 49 50""" 51 52DEFINITIONS = { 53 "VK_MAX_PHYSICAL_DEVICE_NAME_SIZE": "size_t", 54 "VK_MAX_EXTENSION_NAME_SIZE": "size_t", 55 "VK_MAX_DRIVER_NAME_SIZE": "size_t", 56 "VK_MAX_DRIVER_INFO_SIZE": "size_t", 57 "VK_UUID_SIZE": "size_t", 58 "VK_LUID_SIZE": "size_t", 59 "VK_MAX_MEMORY_TYPES": "size_t", 60 "VK_MAX_MEMORY_HEAPS": "size_t", 61 "VK_MAX_DESCRIPTION_SIZE": "size_t", 62 "VK_MAX_DEVICE_GROUP_SIZE": "size_t", 63 "VK_ATTACHMENT_UNUSED": "uint32_t", 64 "VK_SUBPASS_EXTERNAL": "uint32_t", 65 "VK_QUEUE_FAMILY_IGNORED": "uint32_t", 66 "VK_QUEUE_FAMILY_EXTERNAL": "uint32_t", 67 "VK_REMAINING_MIP_LEVELS": "uint32_t", 68 "VK_REMAINING_ARRAY_LAYERS": "uint32_t", 69 "VK_WHOLE_SIZE": "vk::VkDeviceSize", 70 "VK_TRUE": "vk::VkBool32", 71 "VK_FALSE": "vk::VkBool32", 72} 73 74PLATFORM_TYPES = [ 75 # VK_KHR_xlib_surface 76 (["Display","*"], ["XlibDisplayPtr"], "void*"), 77 (["Window"], ["XlibWindow"], "uintptr_t",), 78 (["VisualID"], ["XlibVisualID"], "uint32_t"), 79 80 # VK_KHR_xcb_surface 81 (["xcb_connection_t", "*"], ["XcbConnectionPtr"], "void*"), 82 (["xcb_window_t"], ["XcbWindow"], "uintptr_t"), 83 (["xcb_visualid_t"], ["XcbVisualid"], "uint32_t"), 84 85 # VK_KHR_wayland_surface 86 (["struct", "wl_display","*"], ["WaylandDisplayPtr"], "void*"), 87 (["struct", "wl_surface", "*"], ["WaylandSurfacePtr"], "void*"), 88 89 # VK_KHR_mir_surface 90 (["MirConnection", "*"], ["MirConnectionPtr"], "void*"), 91 (["MirSurface", "*"], ["MirSurfacePtr"], "void*"), 92 93 # VK_KHR_android_surface 94 (["ANativeWindow", "*"], ["AndroidNativeWindowPtr"], "void*"), 95 96 # VK_KHR_win32_surface 97 (["HINSTANCE"], ["Win32InstanceHandle"], "void*"), 98 (["HWND"], ["Win32WindowHandle"], "void*"), 99 (["HANDLE"], ["Win32Handle"], "void*"), 100 (["const", "SECURITY_ATTRIBUTES", "*"], ["Win32SecurityAttributesPtr"], "const void*"), 101 (["AHardwareBuffer", "*"], ["AndroidHardwareBufferPtr"], "void*"), 102 (["HMONITOR"], ["Win32MonitorHandle"], "void*"), 103 (["LPCWSTR"], ["Win32LPCWSTR"], "const void*"), 104 105 # VK_EXT_acquire_xlib_display 106 (["RROutput"], ["RROutput"], "void*"), 107 108 (["zx_handle_t"], ["zx_handle_t"], "uint32_t"), 109 (["GgpFrameToken"], ["GgpFrameToken"], "int32_t"), 110 (["GgpStreamDescriptor"], ["GgpStreamDescriptor"], "int32_t"), 111 (["CAMetalLayer"], ["CAMetalLayer"], "void*"), 112 (["struct", "_screen_context", "*"], ["QNXScreenContextPtr"], "void*"), 113 (["struct", "_screen_window", "*"], ["QNXScreenWindowPtr"], "void*"), 114 115 # VK_EXT_metal_objects 116 (["MTLDevice_id"], ["MTLDevice_id"], "void*"), 117 (["MTLCommandQueue_id"], ["MTLCommandQueue_id"], "void*"), 118 (["MTLBuffer_id"], ["MTLBuffer_id"], "void*"), 119 (["MTLTexture_id"], ["MTLTexture_id"], "void*"), 120 (["IOSurfaceRef"], ["IOSurfaceRef"], "void*"), 121 (["MTLSharedEvent_id"], ["MTLSharedEvent_id"], "void*"), 122] 123 124PLATFORM_TYPE_NAMESPACE = "pt" 125 126TYPE_SUBSTITUTIONS = [ 127 # Platform-specific 128 ("DWORD", "uint32_t"), 129 ("HANDLE*", PLATFORM_TYPE_NAMESPACE + "::" + "Win32Handle*"), 130] 131 132EXTENSION_POSTFIXES_STANDARD = ["KHR", "EXT"] 133EXTENSION_POSTFIXES_VENDOR = ["AMD", "ARM", "NV", 'INTEL', "NVX", "KHX", "NN", "MVK", "FUCHSIA", 'QCOM', "GGP", "QNX", "ANDROID", 'VALVE', 'HUAWEI'] 134EXTENSION_POSTFIXES = EXTENSION_POSTFIXES_STANDARD + EXTENSION_POSTFIXES_VENDOR 135 136def substituteType(object): # both CompositeMember and FunctionArgument can be passed to this function 137 for src, dst in TYPE_SUBSTITUTIONS: 138 object.type = object.type.replace(src, dst) 139 for platformType, substitute, _ in PLATFORM_TYPES: 140 platformTypeName = platformType[0] 141 platformTypeName = platformType[-2] if "*" in platformType else platformType[0] 142 if object.type == platformTypeName: 143 object.type = PLATFORM_TYPE_NAMESPACE + '::' + substitute[0] 144 object.qualifiers = None if 'struct' in platformType else object.qualifiers 145 object.qualifiers = None if 'const' in platformType else object.qualifiers 146 if "*" in platformType: 147 object.pointer = "*" if object.pointer == "**" else None 148 149class Define: 150 def __init__ (self, name, aType, alias, value): 151 self.name = name 152 self.type = aType 153 self.alias = alias 154 self.value = value 155 156class Handle: 157 def __init__ (self, name, aType, alias, parent, objtypeenum): 158 self.name = name 159 self.type = aType 160 self.alias = alias 161 self.parent = parent 162 self.objtypeenum = objtypeenum 163 164class Bitmask: 165 def __init__ (self, name, aType, requires, bitvalues): 166 self.name = name 167 self.type = aType 168 self.alias = None # initialy None but may be filled while parsing next tag 169 self.requires = requires 170 self.bitvalues = bitvalues 171 172class Enumerator: 173 def __init__ (self, name, value, bitpos): 174 self.name = name 175 self.aliasList = [] # list of strings 176 self.value = value # some enums specify value and some bitpos 177 self.bitpos = bitpos 178 self.extension = None # name of extension that added this enumerator 179 180class Enum: 181 def __init__ (self, name): 182 self.name = name 183 self.alias = None # name of enum alias or None 184 self.type = None # enum or bitmask 185 self.bitwidth = "32" 186 self.enumeratorList = [] # list of Enumerator objects 187 188 def areValuesLinear (self): 189 if self.type == 'bitmask': 190 return False 191 curIndex = 0 192 for enumerator in self.enumeratorList: 193 intValue = parseInt(enumerator.value) 194 if intValue != curIndex: 195 return False 196 curIndex += 1 197 return True 198 199class CompositeMember: 200 def __init__ (self, name, aType, pointer, qualifiers, arraySizeList, optional, limittype, values, fieldWidth): 201 self.name = name 202 self.type = aType # member type 203 self.pointer = pointer # None, '*' or '**' 204 self.qualifiers = qualifiers # 'const' or 'struct' or None 205 self.arraySizeList = arraySizeList # can contain digits or enums 206 self.optional = optional 207 self.limittype = limittype 208 self.values = values # allowed member values 209 self.fieldWidth = fieldWidth # ':' followed by number of bits 210 211 # check if type should be swaped 212 substituteType(self) 213 214class Composite: 215 def __init__ (self, name, category, allowduplicate, structextends, returnedonly, members): 216 self.name = name 217 self.category = category # is it struct or union 218 self.aliasList = [] # most composite types have single alias but there are cases like VkPhysicalDeviceVariablePointersFeatures that have 3 219 self.allowduplicate = allowduplicate 220 self.structextends = structextends 221 self.returnedonly = returnedonly 222 self.members = members # list of CompositeMember objects 223 224class FunctionArgument: 225 def __init__ (self, name, qualifiers, aType, pointer = None, secondPointerIsConst = False, arraySize = None): 226 self.name = name 227 self.qualifiers = qualifiers 228 self.type = aType 229 self.pointer = pointer # None, '*' or '**' 230 self.secondPointerIsConst = secondPointerIsConst 231 self.arraySize = arraySize 232 233 # check if type should be swaped 234 substituteType(self) 235 236class Function: 237 TYPE_PLATFORM = 0 # Not bound to anything 238 TYPE_INSTANCE = 1 # Bound to VkInstance 239 TYPE_DEVICE = 2 # Bound to VkDevice 240 241 def __init__ (self, name, returnType = None, arguments = None): 242 self.name = name 243 self.aliasList = [] 244 self.returnType = returnType 245 self.arguments = arguments # list of FunctionArgument objects 246 self.functionType = Function.TYPE_PLATFORM 247 248 # Determine function type based on first argument but use TYPE_PLATFORM for vkGetInstanceProcAddr 249 if self.name == "vkGetInstanceProcAddr": 250 return 251 assert len(self.arguments) > 0 252 firstArgType = self.arguments[0].type 253 if firstArgType in ["VkInstance", "VkPhysicalDevice"]: 254 self.functionType = Function.TYPE_INSTANCE 255 elif firstArgType in ["VkDevice", "VkCommandBuffer", "VkQueue"]: 256 self.functionType = Function.TYPE_DEVICE 257 258 def getType (self): 259 return self.functionType 260 261class FeatureRequirement: 262 def __init__ (self, comment, enumList, typeList, commandList): 263 self.comment = comment 264 self.enumList = enumList 265 self.typeList = typeList 266 self.commandList = commandList # list of strings, each representing required function 267 268class Feature: 269 def __init__ (self, api, name, number, requirementsList): 270 self.api = api 271 self.name = name 272 self.number = number 273 self.requirementsList = requirementsList # list of FeatureRequirement objects 274 275class ExtensionEnumerator: 276 def __init__ (self, name, extends, alias, value, extnumber, offset, comment): 277 self.name = name 278 self.extends = extends 279 self.alias = alias 280 self.value = value 281 self.extnumber = extnumber 282 self.offset = offset 283 self.comment = comment # note: comment is used to mark not promoted features for partially promoted extensions 284 285class ExtensionCommand: 286 def __init__ (self, name, comment): 287 self.name = name 288 self.comment = comment 289 290class ExtensionType: 291 def __init__ (self, name, comment): 292 self.name = name 293 self.comment = comment 294 295class ExtensionRequirements: 296 def __init__ (self, extensionName, extendedEnums, newCommands, newTypes): 297 self.extensionName = extensionName # None when requirements apply to all implementations of extension; 298 # string with extension name when requirements apply to implementations that also support given extension 299 self.extendedEnums = extendedEnums # list of ExtensionEnumerator objects 300 self.newCommands = newCommands # list of ExtensionCommand objects 301 self.newTypes = newTypes # list of ExtensionType objects 302 303class Extension: 304 def __init__ (self, name, number, type, requiresCore, requiredExtensions, platform, promotedto, partiallyPromoted, requirementsList): 305 self.name = name # extension name 306 self.number = number # extension version 307 self.type = type # extension type - "device" or "instance" 308 self.requiresCore = requiresCore # required core vulkan version e.g. "1.1" 309 self.requiredExtensions = requiredExtensions # list of extensions names that also need to be available on implementation or None 310 self.platform = platform # None, "win32", "ios", "android" etc. 311 self.promotedto = promotedto # vulkan version, other extension or None 312 self.partiallyPromoted = partiallyPromoted # when True then some of requirements were not promoted 313 self.requirementsList = requirementsList # list of ExtensionRequirements objects 314 315class API: 316 def __init__ (self): 317 self.versions = [] 318 self.basetypes = {} # dictionary, e.g. one of keys is VkFlags and its value is uint32_t 319 self.defines = [] 320 self.handles = [] 321 self.bitmasks = [] # list of Bitmask objects 322 self.enums = [] # list of Enum objects - each contains individual enum definition (including extension enums) 323 self.compositeTypes = [] # list of Composite objects - each contains individual structure/union definition (including extension structures) 324 self.functions = [] # list of Function objects - each contains individual command definition (including extension functions) 325 self.features = [] # list of Feature objects 326 self.extensions = [] # list of Extension objects - each contains individual extension definition 327 self.basicCTypes = [] # list of basic C types e.g. 'void', 'int8_t' 328 self.tempAliasesList = [] # list of touples used to handle aliases for enumerators that will be defined later 329 330 # read all files from extensions directory 331 additionalExtensionData = {} 332 for fileName in glob.glob(os.path.join(SCRIPTS_SRC_DIR, "extensions", "*.json")): 333 if "schema.json" in fileName: 334 continue 335 extensionName = os.path.basename(fileName)[:-5] 336 fileContent = readFile(fileName) 337 try: 338 additionalExtensionData[extensionName] = json.loads(fileContent) 339 except ValueError as err: 340 print("Error in %s: %s" % (os.path.basename(fileName), str(err))) 341 sys.exit(-1) 342 self.additionalExtensionData = sorted(additionalExtensionData.items(), key=lambda e: e[0]) 343 344 def addOrUpdateEnumerator (self, enumeratorNode, enumDefinition, extensionNumber = None): 345 name = enumeratorNode.get("name") 346 alias = enumeratorNode.get("alias") 347 # if enumerator node has alias atribute then update existing enumerator 348 if alias is not None: 349 for e in reversed(enumDefinition.enumeratorList): 350 if alias == e.name or alias in e.aliasList: 351 # make sure same alias is not already on the list; this handles special case like 352 # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR alais which is defined in three places 353 if name not in e.aliasList: 354 e.aliasList.append(name) 355 return 356 # there are cases where alias is specified for enumerator that wasn't yet defined, 357 # we need to remember those aliases and assign them after we parse whole xml 358 self.tempAliasesList.append((enumDefinition, name, alias)) 359 return 360 # calculate enumerator value if offset attribute is present 361 value = enumeratorNode.get("value") 362 if value is None: 363 value = enumeratorNode.get("offset") 364 if value is not None: 365 # check if extensionNumber should be overridden 366 extnumber = enumeratorNode.get("extnumber") 367 if extnumber is not None: 368 extensionNumber = extnumber 369 value = 1000000000 + (int(extensionNumber)-1) * 1000 + int(value) 370 # check if value should be negative 371 dir = enumeratorNode.get("dir") 372 if dir == "-": 373 value *= -1 374 # convert to string so that type matches the type in which values 375 # are stored for enums that were read from enums xml section 376 value = str(value) 377 # add new enumerator 378 enumDefinition.enumeratorList.append(Enumerator( 379 name, 380 value, 381 enumeratorNode.get("bitpos") 382 )) 383 384 def readEnum (self, enumsNode): 385 enumName = enumsNode.get("name") 386 # special case for vulkan hardcoded constants that are specified as enum in vk.xml 387 if enumName == "API Constants": 388 for enumItem in enumsNode: 389 self.defines.append(Define( 390 enumItem.get("name"), 391 enumItem.get("type"), 392 enumItem.get("alias"), 393 enumItem.get("value") 394 )) 395 return 396 # initial enum definition is read while processing types section; 397 # we need to find this enum definition and add data to it 398 enumDefinition = [enumDef for enumDef in self.enums if enumName == enumDef.name][0] 399 # add type and bitwidth to enum definition 400 enumDefinition.type = enumsNode.get("type") 401 enumDefinition.bitwidth = enumsNode.get("bitwidth") 402 if enumDefinition.bitwidth is None: 403 enumDefinition.bitwidth = "32" 404 # add components to enum definition 405 for enumeratorItem in enumsNode: 406 # skip comment tags 407 if enumeratorItem.tag != "enum": 408 continue 409 self.addOrUpdateEnumerator(enumeratorItem, enumDefinition) 410 411 def readCommand (self, commandNode): 412 protoNode = None # proto is a first child of every command node 413 # check if this is alias 414 alias = commandNode.get("alias") 415 # if node is alias then use the fact that alias definition follows aliased structure 416 if alias is not None: 417 # aliased command has usually been added recently, so we iterate in reverse order 418 found = False 419 for f in reversed(self.functions): 420 found = (f.name == alias) 421 if found: 422 f.aliasList.append(commandNode.get("name")) 423 break 424 assert found 425 # go to next node 426 return 427 # memorize all parameters 428 functionParams = [] 429 for paramNode in commandNode: 430 # memorize prototype node 431 if paramNode.tag == "proto": 432 protoNode = paramNode 433 continue 434 # skip implicitexternsyncparams 435 if paramNode.tag != "param": 436 continue 437 nameNode = paramNode.find("name") 438 typeNode = paramNode.find("type") 439 starCount = typeNode.tail.count('*') 440 functionParams.append(FunctionArgument( 441 nameNode.text, 442 paramNode.text, 443 paramNode.find("type").text, 444 '*' * starCount if starCount > 0 else None, 445 'const' in typeNode.tail, 446 nameNode.tail 447 )) 448 # memorize whole function 449 self.functions.append(Function( 450 protoNode.find("name").text, 451 protoNode.find("type").text, 452 functionParams, 453 )) 454 455 def readExtension (self, extensionNode): 456 # skip disabled extensions 457 if extensionNode.get("supported") == "disabled": 458 return 459 extensionName = extensionNode.get("name") 460 extensionNumber = extensionNode.get("number") 461 partiallyPromoted = False 462 # before reading extension data first read extension 463 # requirements by iterating over all require tags 464 requirementsList = [] 465 for requireItem in extensionNode: 466 extendedEnums = [] 467 newCommands = [] 468 newTypes = [] 469 # iterate over all children in current require tag 470 # and add them to proper list 471 for individualRequirement in requireItem: 472 requirementName = individualRequirement.get("name") 473 requirementComment = individualRequirement.get("comment") 474 # check if this requirement was not promoted and mark 475 # this extension as not fully promoted 476 if requirementComment is not None and "Not promoted to" in requirementComment: 477 partiallyPromoted = True 478 # check if this requirement describes enum, command or type 479 if individualRequirement.tag == "enum": 480 extendedEnumName = individualRequirement.get("extends") 481 extendedEnums.append(ExtensionEnumerator( 482 requirementName, 483 extendedEnumName, 484 individualRequirement.get("alias"), 485 individualRequirement.get("value"), 486 individualRequirement.get("extnumber"), 487 individualRequirement.get("offset"), 488 requirementComment)) 489 # add enumerator to proper enum from api.enums 490 if extendedEnumName is not None: 491 newEnumerator = individualRequirement.get("name") 492 # find extendedEnumName in self.enums 493 matchedEnum = [enum for enum in self.enums if enum.name == extendedEnumName][0] 494 # add enumerator only when it is not already in enum 495 if len([e for e in matchedEnum.enumeratorList if e.name == newEnumerator]) == 0: 496 self.addOrUpdateEnumerator(individualRequirement, matchedEnum, extensionNumber) 497 elif individualRequirement.tag == "command": 498 newCommands.append(ExtensionCommand(requirementName, requirementComment)) 499 elif individualRequirement.tag == "type": 500 newTypes.append(ExtensionType(requirementName, requirementComment)) 501 elif individualRequirement.tag == "comment" and "not promoted to" in individualRequirement.text: 502 # partial promotion of VK_EXT_ycbcr_2plane_444_formats and VK_EXT_4444_formats 503 # is marked with comment tag in first require section 504 partiallyPromoted = True 505 # construct requirement object and add it to the list 506 requirementsList.append(ExtensionRequirements( 507 requireItem.get("extension"), # extensionName 508 extendedEnums, # extendedEnums 509 newCommands, # newCommands 510 newTypes # newTypes 511 )) 512 # read extensions that need to be supported when current extension is suported; 513 # in xml this is single comma separated string, we split it to list of strings 514 requiredExtensions = extensionNode.get("requires") 515 if requiredExtensions is not None: 516 requiredExtensions = requiredExtensions.split(',') 517 # add extension definition to api object 518 self.extensions.append(Extension( 519 extensionName, # name 520 extensionNumber, # number 521 extensionNode.get("type"), # type 522 extensionNode.get("requiresCore"), # requiresCore 523 requiredExtensions, # requiredExtensions 524 extensionNode.get("platform"), # platform 525 extensionNode.get("promotedto"), # promotedto 526 partiallyPromoted, # partiallyPromoted 527 requirementsList # requirementsList 528 )) 529 530 def readFeature (self, featureNode): 531 requirementsList = [] 532 for requirementGroup in featureNode: 533 enumList = [] 534 typeList = [] 535 commandList = [] 536 for requirement in requirementGroup: 537 requirementName = requirement.get("name") 538 if requirement.tag == "enum": 539 enumList.append(requirementName) 540 extendedEnumName = requirement.get("extends") 541 if extendedEnumName is not None: 542 # find extended enum in api.enums list 543 for e in self.enums: 544 if extendedEnumName == e.name: 545 # read enumerator and add it to enum 546 self.addOrUpdateEnumerator(requirement, e) 547 break 548 elif requirement.tag == "type": 549 typeList.append(requirementName) 550 elif requirement.tag == "command": 551 commandList.append(requirementName) 552 requirementsList.append(FeatureRequirement( 553 requirementGroup.get("comment"), 554 enumList, 555 typeList, 556 commandList 557 )) 558 self.features.append(Feature( 559 featureNode.get("api"), 560 featureNode.get("name"), 561 featureNode.get("number"), 562 requirementsList 563 )) 564 565 def readType (self, typeNode): 566 name = typeNode.get("name") 567 alias = typeNode.get("alias") 568 category = typeNode.get("category") 569 if category == "enum": 570 if alias is None: 571 self.enums.append(Enum(name)) 572 else: 573 for e in reversed(self.enums): 574 if alias == e.name: 575 e.alias = name 576 break 577 elif category == "handle": 578 type = None 579 if alias is None: 580 name = typeNode.find("name").text 581 type = typeNode.find("type").text 582 self.handles.append(Handle( 583 name, 584 type, 585 alias, 586 typeNode.get("parent"), 587 typeNode.get("objtypeenum"), 588 )) 589 else: 590 for h in reversed(self.handles): 591 if alias == h.name: 592 h.alias = name 593 break 594 elif category == "basetype": 595 # processing only those basetypes that have type child 596 type = typeNode.find("type") 597 if type is not None: 598 self.basetypes[typeNode.find("name").text] = type.text 599 elif category == "bitmask": 600 # if node is alias then use the fact that alias definition follows aliased bitmasks; 601 # in majoriti of cases it follows directly aliased bitmasks but in some cases there 602 # is a unrelated bitmasks definition in between - to handle this traverse in reverse order 603 if alias is not None: 604 for bm in reversed(self.bitmasks): 605 if alias == bm.name: 606 bm.alias = name 607 break 608 else: 609 self.bitmasks.append(Bitmask( 610 typeNode.find("name").text, 611 typeNode.find("type").text, 612 typeNode.get("requires"), 613 typeNode.get("bitvalues") 614 )) 615 elif category in ["struct", "union"]: 616 # if node is alias then use the fact that alias definition follows aliased structure; 617 # in majoriti of cases it follows directly aliased structure but in some cases there 618 # is a unrelated structure definition in between - to handle this traverse in reverse order 619 if alias is not None: 620 for ct in reversed(self.compositeTypes): 621 if alias == ct.name: 622 ct.aliasList.append(name) 623 break 624 # go to next node 625 return 626 # read structure members 627 structMembers = [] 628 for memberNode in typeNode: 629 if memberNode.tag != "member": 630 continue 631 # handle enum nodes that can be used for arrays 632 arraySizeList = [] 633 for node in memberNode: 634 if node.tag == "enum": 635 arraySizeList.append(node.text) 636 # handle additional text after name tag; it can represent array 637 # size like in VkPipelineFragmentShadingRateEnumStateCreateInfoNV 638 # or number of bits like in VkAccelerationStructureInstanceKHR 639 nameNode = memberNode.find("name") 640 nameTail = nameNode.tail 641 fieldWidth = None 642 if nameTail: 643 if ':' in nameTail: 644 fieldWidth = nameTail.replace(':', '').replace(' ', '') 645 elif '[' in nameTail and ']' in nameTail: 646 nameTail = nameTail.replace(']', ' ').replace('[', ' ') 647 arraySizeList = nameTail.split() 648 # handle additional text after type tag; it can represent pointers like *pNext 649 memberTypeNode = memberNode.find("type") 650 pointer = memberTypeNode.tail.strip() if memberTypeNode.tail is not None else None 651 structMembers.append(CompositeMember( 652 nameNode.text, # name 653 memberTypeNode.text, # type 654 pointer, # pointer 655 memberNode.text, # qualifiers 656 arraySizeList, # arraySizeList 657 memberNode.get("optional"), # optional 658 memberNode.get("limittype"), # limittype 659 memberNode.get("values"), # values 660 fieldWidth # fieldWidth 661 )) 662 # create structure definition 663 self.compositeTypes.append(Composite( 664 name, 665 category, 666 typeNode.get("allowduplicate"), 667 typeNode.get("structextends"), 668 typeNode.get("returnedonly"), 669 structMembers 670 )) 671 elif category == "define": 672 requires = typeNode.get("requires") 673 if requires == "VK_MAKE_API_VERSION" or requires == "VK_MAKE_VIDEO_STD_VERSION": 674 value = typeNode.find("type").tail 675 value = requires + value[:value.find(')')+1] 676 self.defines.append(Define( 677 typeNode.find("name").text, 678 "uint32_t", 679 None, 680 value 681 )) 682 else: 683 requires = typeNode.get("requires") 684 if requires == 'vk_platform': 685 self.basicCTypes.append(name) 686 687 def build (self, rawVkXml): 688 # iterate over all *.xml root children 689 for rootChild in rawVkXml.getroot(): 690 691 # each enum is defined in separate enums node directly under root node 692 if rootChild.tag == "enums": 693 self.readEnum(rootChild) 694 695 # read function definitions 696 if rootChild.tag == "commands": 697 commandsNode = rootChild 698 for commandItem in commandsNode: 699 self.readCommand(commandItem) 700 701 # read vulkan versions 702 if rootChild.tag == "feature": 703 self.readFeature(rootChild) 704 705 # read extensions 706 if rootChild.tag == "extensions": 707 extensionsNode = rootChild 708 for extensionItem in extensionsNode: 709 self.readExtension(extensionItem) 710 711 # "types" is a first child of root so it's optimal to check for it 712 # last and don't repeat this check for all other iterations 713 if rootChild.tag == "types": 714 typesNode = rootChild 715 for typeItem in typesNode: 716 self.readType(typeItem) 717 718 def postProcess (self): 719 def removeExtensionFromApi(extName, structureNameList, commandNameList): 720 extObjectList = [e for e in api.extensions if e.name == extName] 721 if len(extObjectList) > 0: 722 api.extensions.remove(extObjectList[0]) 723 structObjectList = [ct for ct in api.compositeTypes if ct.name in structureNameList] 724 for s in structObjectList: 725 api.compositeTypes.remove(s) 726 commandObjectList = [f for f in api.functions if f.name in commandNameList] 727 for f in commandObjectList: 728 api.functions.remove(f) 729 730 # remove structures and commands added by VK_EXT_directfb_surface extension 731 removeExtensionFromApi("VK_EXT_directfb_surface", 732 ["VkDirectFBSurfaceCreateFlagsEXT", "VkDirectFBSurfaceCreateInfoEXT"], 733 ["vkCreateDirectFBSurfaceEXT", "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"]) 734 735 # remove structures and commands added by disabled VK_ANDROID_native_buffer extension; 736 # disabled extensions aren't read but their structures and commands will be in types and commands sections in vk.xml 737 removeExtensionFromApi("VK_ANDROID_native_buffer", 738 ["VkNativeBufferANDROID", "VkSwapchainImageCreateInfoANDROID", 739 "VkPhysicalDevicePresentationPropertiesANDROID", "VkNativeBufferUsage2ANDROID", 740 "VkSwapchainImageUsageFlagBitsANDROID", "VkSwapchainImageUsageFlagsANDROID"], 741 ["vkGetSwapchainGrallocUsageANDROID", "vkAcquireImageANDROID", 742 "vkQueueSignalReleaseImageANDROID", "vkGetSwapchainGrallocUsage2ANDROID"]) 743 744 # remove empty enums e.g. VkQueryPoolCreateFlagBits, VkDeviceCreateFlagBits 745 enumsToRemove = [enum for enum in self.enums if len(enum.enumeratorList) == 0] 746 for er in enumsToRemove: 747 self.enums.remove(er) 748 749 # add aliases to enumerators that were defined after alias (there are ~10 cases like that in vk.xml) 750 for tmpAliasTouple in self.tempAliasesList: 751 (enum, name, alias) = tmpAliasTouple 752 for e in enum.enumeratorList: 753 if e.name == alias: 754 e.aliasList.append(name) 755 break 756 self.tempAliasesList = None 757 758 # add alias for VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR (in vk.xml for this struct alias is defined before struct 759 # where in all other cases it is defined after structure definition) 760 barycentricFeaturesStruct = [c for c in api.compositeTypes if c.name == 'VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR'][0] 761 barycentricFeaturesStruct.aliasList.append('VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV') 762 763 # sort enumerators in enums 764 sortLambda = lambda enumerator: int(enumerator.bitpos) if enumerator.value is None else int(enumerator.value, 16 if 'x' in enumerator.value else 10) 765 for enum in self.enums: 766 # skip enums that have no items in enumeratorList (e.g. VkQueryPoolCreateFlagBits) or just one item 767 if len(enum.enumeratorList) < 2: 768 continue 769 # construct list of enumerators in which value and bitpos are not None 770 enumeratorsToSort = [e for e in enum.enumeratorList if e.value != e.bitpos] 771 # construct list of enumerators in which value and bitpos are equal to None 772 remainingEnumerators = [e for e in enum.enumeratorList if e.value == e.bitpos] 773 # construct sorted enumerator list with aliases at the end 774 enum.enumeratorList = sorted(enumeratorsToSort, key=sortLambda) 775 enum.enumeratorList.extend(remainingEnumerators) 776 777def prefixName (prefix, name): 778 name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name[2:]) 779 name = re.sub(r'([a-zA-Z])([0-9])', r'\1_\2', name) 780 name = name.upper() 781 return prefix + name 782 783def parseInt (value): 784 return int(value, 16 if (value[:2] == "0x") else 10) 785 786def getApiVariantIndexByName(variantName): 787 apiVariant = { 788 None : 0, 789 '' : 0, 790 'SC' : 1 791 } 792 return apiVariant[variantName] 793 794def getApiVariantNameByIndex(variantIndex): 795 apiVariant = { 796 None : '', 797 0 : '', 798 1 : 'SC' 799 } 800 return apiVariant[variantIndex] 801 802def readFile (filename): 803 with open(filename, 'rt') as f: 804 return f.read() 805 806def getInterfaceName (functionName): 807 assert functionName[:2] == "vk" 808 return functionName[2].lower() + functionName[3:] 809 810def getFunctionTypeName (functionName): 811 assert functionName[:2] == "vk" 812 return functionName[2:] + "Func" 813 814def endsWith (str, postfix): 815 return str[-len(postfix):] == postfix 816 817def writeHandleType (api, filename): 818 819 def getHandleName (name): 820 return prefixName("HANDLE_TYPE_", name) 821 822 def genHandles (): 823 yield "\t%s\t= 0," % getHandleName(api.handles[0].name) 824 for h in api.handles[1:]: 825 yield "\t%s," % getHandleName(h.name) 826 for h in api.handles: 827 if h.alias is not None: 828 yield "\t%s\t= %s," % (getHandleName(h.alias), getHandleName(h.name)) 829 yield "\tHANDLE_TYPE_LAST\t= %s + 1" % (getHandleName(api.handles[-1].name)) 830 831 def genHandlesBlock (): 832 yield "enum HandleType" 833 yield "{" 834 835 for line in indentLines(genHandles()): 836 yield line 837 838 yield "};" 839 yield "" 840 841 writeInlFile(filename, INL_HEADER, genHandlesBlock()) 842 843def getEnumValuePrefixAndPostfix (enum): 844 prefix = enum.name[0] 845 for i in range(1, len(enum.name)): 846 if enum.name[i].isupper() and not enum.name[i-1].isupper(): 847 prefix += "_" 848 prefix += enum.name[i].upper() 849 for p in EXTENSION_POSTFIXES: 850 if prefix.endswith(p): 851 return prefix[:-len(p)-1], '_'+p 852 return prefix, '' 853 854def genEnumSrc (enum): 855 yield "enum %s" % enum.name 856 yield "{" 857 lines = [] 858 for ed in enum.enumeratorList: 859 if ed.value is not None: 860 lines.append(f"\t{ed.name}\t= {ed.value},") 861 for ed in enum.enumeratorList: 862 for alias in ed.aliasList: 863 lines.append(f"\t{alias}\t= {ed.name},") 864 865 # add *_LAST item when enum is linear 866 prefix, postfix = getEnumValuePrefixAndPostfix(enum) 867 if enum.areValuesLinear(): 868 lines.append(f"\t{prefix}{postfix}_LAST,") 869 870 # add _MAX_ENUM item with the ext postifix at the end 871 lines.append(f"\t{prefix}_MAX_ENUM{postfix}\t= 0x7FFFFFFF") 872 873 for line in indentLines(lines): 874 yield line 875 876 yield "};" 877 878def genBitfieldSrc (bitfield): 879 lines = [] 880 for ev in bitfield.enumeratorList: 881 # bitfields may use mix of bitpos and values 882 if ev.bitpos is not None: 883 value = pow(2, int(ev.bitpos)) 884 lines.append(f"\t{ev.name}\t= {value:#010x},") 885 if ev.value is not None: 886 lines.append(f"\t{ev.name}\t= {ev.value},") 887 for ev in bitfield.enumeratorList: 888 for alias in ev.aliasList: 889 lines.append(f"\t{alias}\t= {ev.name},") 890 # add _MAX_ENUM item 891 prefix, postfix = getEnumValuePrefixAndPostfix(bitfield) 892 lines.append(f"\t{prefix}_MAX_ENUM{postfix}\t= 0x7FFFFFFF") 893 yield f"enum {bitfield.name}" 894 yield "{" 895 for line in indentLines(lines): 896 yield line 897 yield "};" 898 899def genBitfield64Src (bitfield64): 900 def generateEntry(lines, bitfieldName, entryName, bitpos, value): 901 if entryName is None: 902 return 903 # bitfields may use mix of bitpos and values 904 if ev.bitpos is not None: 905 v = pow(2, int(bitpos)) 906 lines.append(f"static const {bitfieldName} {entryName}\t= {v:#010x}ULL;") 907 if value is not None: 908 lines.append(f"static const {bitfieldName} {entryName}\t= {value}ULL;") 909 910 yield f"typedef uint64_t {bitfield64.name};" 911 lines = [] 912 for ev in bitfield64.enumeratorList: 913 generateEntry(lines, bitfield64.name, ev.name, ev.bitpos, ev.value) 914 for alias in ev.aliasList: 915 generateEntry(lines, bitfield64.name, alias, ev.bitpos, ev.value) 916 # write indented lines 917 for line in indentLines(lines): 918 yield line 919 yield "" 920 921def genDefinesSrc (apiName, defines): 922 def genLines (defines): 923 for d in defines: 924 if d.alias is not None: 925 continue 926 defineType = DEFINITIONS.get(d.name, d.type) 927 yield f"#define {d.name}\t(static_cast<{defineType}>\t({d.value}))" 928 for line in indentLines(genLines(defines)): 929 yield line 930 # add VK_API_MAX_FRAMEWORK_VERSION 931 major, minor = api.features[-1].number.split('.') 932 yield f"#define VK_API_MAX_FRAMEWORK_VERSION\tVK{apiName}_API_VERSION_{major}_{minor}" 933 934def genHandlesSrc (handles): 935 def genLines (handles): 936 for h in handles: 937 handleType = h.type 938 handleObjtype = h.objtypeenum 939 if h.alias is not None: 940 # search for aliased handle 941 for searchedHandle in handles: 942 if h.alias == searchedHandle.name: 943 handleType = searchedHandle.type 944 handleObjtype = searchedHandle.objtypeenum 945 break 946 yield f"{handleType}\t({h.name},\tHANDLE{handleObjtype[9:]});" 947 for line in indentLines(genLines(handles)): 948 yield line 949 950def genHandlesSrc (handles): 951 def genLines (handles): 952 for h in handles: 953 handleType = h.type 954 handleObjtype = h.objtypeenum 955 line = f"{handleType}\t({{}},\tHANDLE{handleObjtype[9:]});" 956 yield line.format(h.name) 957 if h.alias is not None: 958 yield line.format(h.alias) 959 960 for line in indentLines(genLines(handles)): 961 yield line 962 963def writeBasicTypes (apiName, api, filename): 964 965 def gen (): 966 967 for line in genDefinesSrc(apiName, api.defines): 968 yield line 969 yield "" 970 971 for line in genHandlesSrc(api.handles): 972 yield line 973 yield "" 974 975 for enum in api.enums: 976 if len(enum.enumeratorList) == 0: 977 continue 978 if enum.type == "bitmask": 979 if enum.bitwidth == "32": 980 for line in genBitfieldSrc(enum): 981 yield line 982 else: 983 for line in genBitfield64Src(enum): 984 yield line 985 else: 986 for line in genEnumSrc(enum): 987 yield line 988 if enum.alias is not None: 989 yield f"typedef {enum.name} {enum.alias};" 990 yield "" 991 992 for bitmask in api.bitmasks: 993 plainType = api.basetypes[bitmask.type] 994 yield f"typedef {plainType} {bitmask.name};\n" 995 if bitmask.alias: 996 yield f"typedef {bitmask.name} {bitmask.alias};\n" 997 998 yield "" 999 for line in indentLines(["VK_DEFINE_PLATFORM_TYPE(%s,\t%s)" % (s[0], c) for n, s, c in PLATFORM_TYPES]): 1000 yield line 1001 yield "" 1002 1003 for ext in api.extensions: 1004 firstRequirementEnums = ext.requirementsList[0].extendedEnums 1005 for e in firstRequirementEnums: 1006 if e.extends is None and e.value is not None: 1007 yield "#define " + e.name + " " + e.value 1008 1009 writeInlFile(filename, INL_HEADER, gen()) 1010 1011def writeCompositeTypes (api, filename): 1012 # function that returns definition of structure member 1013 def memberAsString (member): 1014 result = '' 1015 if member.qualifiers: 1016 result += member.qualifiers 1017 result += member.type 1018 if member.pointer: 1019 result += member.pointer 1020 result += '\t' + member.name 1021 for size in member.arraySizeList: 1022 result += f"[{size}]" 1023 if member.fieldWidth: 1024 result += f":{member.fieldWidth}" 1025 return result 1026 1027 # function that prints single structure definition 1028 def genCompositeTypeSrc (type): 1029 structLines = "%s %s\n{\n" % (type.category, type.name) 1030 for line in indentLines(['\t'+memberAsString(m)+';' for m in type.members]): 1031 structLines += line + '\n' 1032 return structLines + "};\n" 1033 1034 # function that prints all structure definitions and alias typedefs 1035 def gen (): 1036 # structures in xml are not ordered in a correct way for C++ 1037 # we need to save structures that are used in other structures first 1038 allStructureNamesList = [s.name for s in api.compositeTypes] 1039 commonTypesList = api.basicCTypes + ['VkStructureType'] 1040 savedStructureNamesList = [] 1041 delayedStructureObjectsList = [] 1042 1043 # helper function that checks if all structure members were already saved 1044 def canStructBeSaved(compositeObject): 1045 for m in compositeObject.members: 1046 # check first commonTypesList to speed up the algorithm 1047 if m.type in commonTypesList: 1048 continue 1049 # make sure that member is not of same type as compositeObject 1050 # (this hadles cases like VkBaseOutStructure) 1051 if m.type == compositeObject.name: 1052 continue 1053 # if member is of compositeType that was not saved we cant save it now 1054 if m.type in allStructureNamesList and m.type not in savedStructureNamesList: 1055 return False 1056 return True 1057 1058 # iterate over all composite types 1059 lastDelayedComposite = None 1060 for ct in api.compositeTypes: 1061 # check if one of delayed structures can be saved 1062 delayedButSaved = [] 1063 for dct in delayedStructureObjectsList: 1064 if lastDelayedComposite != dct and canStructBeSaved(dct): 1065 yield genCompositeTypeSrc(dct) 1066 delayedButSaved.append(dct) 1067 lastDelayedComposite = None 1068 for dsct in delayedButSaved: 1069 savedStructureNamesList.append(dsct.name) 1070 delayedStructureObjectsList.remove(dsct) 1071 # check if current structure can be saved 1072 if canStructBeSaved(ct): 1073 yield genCompositeTypeSrc(ct) 1074 savedStructureNamesList.append(ct.name) 1075 else: 1076 delayedStructureObjectsList.append(ct) 1077 # memorize structure that was delayed in last iteration to 1078 # avoid calling for it canStructBeSaved in next iteration 1079 lastDelayedComposite = ct 1080 # save remaining delayed composite types (~4 video related structures) 1081 while len(delayedStructureObjectsList) > 0: 1082 for dct in delayedStructureObjectsList: 1083 if canStructBeSaved(dct): 1084 yield genCompositeTypeSrc(dct) 1085 savedStructureNamesList.append(dct.name) 1086 delayedStructureObjectsList.remove(dct) 1087 break 1088 # write all alias typedefs 1089 for ct in api.compositeTypes: 1090 for alias in ct.aliasList: 1091 yield "typedef %s %s;" % (ct.name, alias) 1092 yield "" 1093 1094 writeInlFile(filename, INL_HEADER, gen()) 1095 1096def argListToStr (args): 1097 def argumentToString(arg): 1098 # args can be instance of FunctionArgument or CompositeMember 1099 # but CompositeMember has no arraySize atrribute nor secondPointerIsConst 1100 workingOnFunctionArgument = True if hasattr(arg, 'arraySize') else False 1101 result = '' 1102 if arg.qualifiers: 1103 result += arg.qualifiers 1104 result += arg.type 1105 if arg.pointer: 1106 if workingOnFunctionArgument and arg.secondPointerIsConst: 1107 result += '* const*' 1108 else: 1109 result += arg.pointer 1110 result += ' ' + arg.name 1111 if workingOnFunctionArgument: 1112 if arg.arraySize: 1113 result += arg.arraySize 1114 return result 1115 return ", ".join(argumentToString(arg) for arg in args) 1116 1117def writeInterfaceDecl (api, filename, functionTypes, concrete): 1118 def genProtos (): 1119 postfix = "" if concrete else " = 0" 1120 for function in api.functions: 1121 if not function.getType() in functionTypes: 1122 continue 1123 yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments), postfix) 1124 1125 writeInlFile(filename, INL_HEADER, indentLines(genProtos())) 1126 1127def writeFunctionPtrTypes (api, filename): 1128 def genTypes (): 1129 pattern = "typedef VKAPI_ATTR {}\t(VKAPI_CALL* {})\t({});" 1130 for function in api.functions: 1131 argList = argListToStr(function.arguments) 1132 yield pattern.format(function.returnType, getFunctionTypeName(function.name), argList) 1133 for alias in function.aliasList: 1134 yield pattern.format(function.returnType, getFunctionTypeName(alias), argList) 1135 1136 writeInlFile(filename, INL_HEADER, indentLines(genTypes())) 1137 1138def writeFunctionPointers (api, filename, functionTypes): 1139 def FunctionsYielder (): 1140 for function in api.functions: 1141 if function.getType() in functionTypes: 1142 interfaceName = getInterfaceName(function.name) 1143 functionTypeName = getFunctionTypeName(function.name) 1144 yield f"{functionTypeName}\t{interfaceName};" 1145 if function.getType() == Function.TYPE_INSTANCE: 1146 for alias in function.aliasList: 1147 interfaceName = getInterfaceName(alias) 1148 functionTypeName = getFunctionTypeName(alias) 1149 yield f"{functionTypeName}\t{interfaceName};" 1150 1151 writeInlFile(filename, INL_HEADER, indentLines(FunctionsYielder())) 1152 1153def writeInitFunctionPointers (api, filename, functionTypes, cond = None): 1154 def makeInitFunctionPointers (): 1155 for function in api.functions: 1156 if function.getType() in functionTypes and (cond == None or cond(function)): 1157 interfaceName = getInterfaceName(function.name) 1158 functionTypeName = getFunctionTypeName(function.name) 1159 yield f"m_vk.{interfaceName}\t= ({functionTypeName})\tGET_PROC_ADDR(\"{function.name}\");" 1160 for alias in function.aliasList: 1161 yield f"if (!m_vk.{interfaceName})" 1162 yield f" m_vk.{interfaceName}\t= ({functionTypeName})\tGET_PROC_ADDR(\"{alias}\");" 1163 if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].type == "VkPhysicalDevice": 1164 interfaceName = getInterfaceName(alias) 1165 functionTypeName = getFunctionTypeName(alias) 1166 yield f"m_vk.{interfaceName}\t= ({functionTypeName})\tGET_PROC_ADDR(\"{alias}\");" 1167 1168 lines = [line.replace(' ', '\t') for line in indentLines(makeInitFunctionPointers())] 1169 writeInlFile(filename, INL_HEADER, lines) 1170 1171def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className): 1172 def makeFuncPtrInterfaceImpl (): 1173 for function in api.functions: 1174 if function.getType() in functionTypes: 1175 yield "" 1176 yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function.name), argListToStr(function.arguments)) 1177 yield "{" 1178 if function.name == "vkEnumerateInstanceVersion": 1179 yield " if (m_vk.enumerateInstanceVersion)" 1180 yield " return m_vk.enumerateInstanceVersion(pApiVersion);" 1181 yield "" 1182 yield " *pApiVersion = VK_API_VERSION_1_0;" 1183 yield " return VK_SUCCESS;" 1184 elif function.getType() == Function.TYPE_INSTANCE and function.arguments[0].type == "VkPhysicalDevice" and len(function.aliasList) > 0: 1185 yield " vk::VkPhysicalDeviceProperties props;" 1186 yield " m_vk.getPhysicalDeviceProperties(physicalDevice, &props);" 1187 yield " if (props.apiVersion >= VK_API_VERSION_1_1)" 1188 yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.name), ", ".join(a.name for a in function.arguments)) 1189 yield " else" 1190 yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.aliasList[0]), ", ".join(a.name for a in function.arguments)) 1191 else: 1192 yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.name), ", ".join(a.name for a in function.arguments)) 1193 yield "}" 1194 1195 writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl()) 1196 1197def writeFuncPtrInterfaceSCImpl (api, filename, functionTypes, className): 1198 normFuncs = { 1199 "createGraphicsPipelines" : "\t\treturn createGraphicsPipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1200 "createComputePipelines" : "\t\treturn createComputePipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1201 "createSampler" : "\t\treturn createSamplerHandlerNorm(device, pCreateInfo, pAllocator, pSampler);", 1202 "createSamplerYcbcrConversion" : "\t\treturn createSamplerYcbcrConversionHandlerNorm(device, pCreateInfo, pAllocator, pYcbcrConversion);", 1203 "createDescriptorSetLayout" : "\t\treturn createDescriptorSetLayoutHandlerNorm(device, pCreateInfo, pAllocator, pSetLayout);", 1204 "createPipelineLayout" : "\t\treturn createPipelineLayoutHandlerNorm(device, pCreateInfo, pAllocator, pPipelineLayout);", 1205 "createRenderPass" : "\t\treturn createRenderPassHandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);", 1206 "createRenderPass2" : "\t\treturn createRenderPass2HandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);", 1207 "createCommandPool" : "\t\treturn createCommandPoolHandlerNorm(device, pCreateInfo, pAllocator, pCommandPool);", 1208 "resetCommandPool" : "\t\treturn resetCommandPoolHandlerNorm(device, commandPool, flags);", 1209 "createFramebuffer" : "\t\treturn createFramebufferHandlerNorm(device, pCreateInfo, pAllocator, pFramebuffer);", 1210 } 1211 statFuncs = { 1212 "destroyDevice" : "\t\tdestroyDeviceHandler(device, pAllocator);", 1213 "createDescriptorSetLayout" : "\t\tcreateDescriptorSetLayoutHandlerStat(device, pCreateInfo, pAllocator, pSetLayout);", 1214 "destroyDescriptorSetLayout" : "\t\tdestroyDescriptorSetLayoutHandler(device, descriptorSetLayout, pAllocator);", 1215 "createImageView" : "\t\tcreateImageViewHandler(device, pCreateInfo, pAllocator, pView);", 1216 "destroyImageView" : "\t\tdestroyImageViewHandler(device, imageView, pAllocator);", 1217 "createSemaphore" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(semaphoreRequestCount,1);\n\t\t*pSemaphore = Handle<HANDLE_TYPE_SEMAPHORE>(m_resourceInterface->incResourceCounter());\n\t}", 1218 "destroySemaphore" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(semaphore,semaphoreRequestCount,1);\n\t}", 1219 "createFence" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(fenceRequestCount,1);\n\t\t*pFence = Handle<HANDLE_TYPE_FENCE>(m_resourceInterface->incResourceCounter());\n\t}", 1220 "destroyFence" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(fence,fenceRequestCount,1);\n\t}", 1221 "allocateMemory" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(deviceMemoryRequestCount,1);\n\t\t*pMemory = Handle<HANDLE_TYPE_DEVICE_MEMORY>(m_resourceInterface->incResourceCounter());\n\t}", 1222 "createBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferRequestCount,1);\n\t\t*pBuffer = Handle<HANDLE_TYPE_BUFFER>(m_resourceInterface->incResourceCounter());\n\t}", 1223 "destroyBuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(buffer,bufferRequestCount,1);\n\t}", 1224 "createImage" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(imageRequestCount,1);\n\t\t*pImage = Handle<HANDLE_TYPE_IMAGE>(m_resourceInterface->incResourceCounter());\n\t}", 1225 "destroyImage" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(image,imageRequestCount,1);\n\t}", 1226 "createEvent" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(eventRequestCount,1);\n\t\t*pEvent = Handle<HANDLE_TYPE_EVENT>(m_resourceInterface->incResourceCounter());\n\t}", 1227 "destroyEvent" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(event,eventRequestCount,1);\n\t}", 1228 "createQueryPool" : "\t\tcreateQueryPoolHandler(device, pCreateInfo, pAllocator, pQueryPool);", 1229 "createBufferView" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferViewRequestCount,1);\n\t\t*pView = Handle<HANDLE_TYPE_BUFFER_VIEW>(m_resourceInterface->incResourceCounter());\n\t}", 1230 "destroyBufferView" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(bufferView,bufferViewRequestCount,1);\n\t}", 1231 "createPipelineLayout" : "\t\tcreatePipelineLayoutHandlerStat(device, pCreateInfo, pAllocator, pPipelineLayout);", 1232 "destroyPipelineLayout" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineLayout,pipelineLayoutRequestCount,1);\n\t}", 1233 "createRenderPass" : "\t\tcreateRenderPassHandlerStat(device, pCreateInfo, pAllocator, pRenderPass);", 1234 "createRenderPass2" : "\t\tcreateRenderPass2HandlerStat(device, pCreateInfo, pAllocator, pRenderPass);", 1235 "destroyRenderPass" : "\t\tdestroyRenderPassHandler(device, renderPass, pAllocator);", 1236 "createGraphicsPipelines" : "\t\tcreateGraphicsPipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1237 "createComputePipelines" : "\t\tcreateComputePipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);", 1238 "destroyPipeline" : "\t\tdestroyPipelineHandler(device, pipeline, pAllocator);", 1239 "createSampler" : "\t\tcreateSamplerHandlerStat(device, pCreateInfo, pAllocator, pSampler);", 1240 "destroySampler" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(sampler,samplerRequestCount,1);\n\t}", 1241 "createDescriptorPool" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(descriptorPoolRequestCount,1);\n\t\t*pDescriptorPool = Handle<HANDLE_TYPE_DESCRIPTOR_POOL>(m_resourceInterface->incResourceCounter());\n\t}", 1242 "resetDescriptorPool" : "\t\tresetDescriptorPoolHandlerStat(device, descriptorPool, flags);", 1243 "allocateDescriptorSets" : "\t\tallocateDescriptorSetsHandlerStat(device, pAllocateInfo, pDescriptorSets);", 1244 "freeDescriptorSets" : "\t\tfreeDescriptorSetsHandlerStat(device, descriptorPool, descriptorSetCount, pDescriptorSets);", 1245 "createFramebuffer" : "\t\tcreateFramebufferHandlerStat(device, pCreateInfo, pAllocator, pFramebuffer);", 1246 "destroyFramebuffer" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(framebuffer,framebufferRequestCount,1);\n\t}", 1247 "createCommandPool" : "\t\tcreateCommandPoolHandlerStat(device, pCreateInfo, pAllocator, pCommandPool);", 1248 "resetCommandPool" : "\t\tresetCommandPoolHandlerStat(device, commandPool, flags);", 1249 "allocateCommandBuffers" : "\t\tallocateCommandBuffersHandler(device, pAllocateInfo, pCommandBuffers);", 1250 "freeCommandBuffers" : "\t\tfreeCommandBuffersHandler(device, commandPool, commandBufferCount, pCommandBuffers);", 1251 "createSamplerYcbcrConversion" : "\t\tcreateSamplerYcbcrConversionHandlerStat(device, pCreateInfo, pAllocator, pYcbcrConversion);", 1252 "destroySamplerYcbcrConversion" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(ycbcrConversion,samplerYcbcrConversionRequestCount,1);\n\t}", 1253 "getDescriptorSetLayoutSupport" : "\t\tgetDescriptorSetLayoutSupportHandler(device, pCreateInfo, pSupport);", 1254# "" : "surfaceRequestCount", 1255# "" : "swapchainRequestCount", 1256# "" : "displayModeRequestCount" 1257 "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}", 1258 "getBufferMemoryRequirements" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}", 1259 "getImageMemoryRequirements" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}", 1260 "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}", 1261 "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}", 1262 "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}", 1263 "createPipelineCache" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(pipelineCacheRequestCount,1);\n\t\t*pPipelineCache = Handle<HANDLE_TYPE_PIPELINE_CACHE>(m_resourceInterface->incResourceCounter());\n\t}", 1264 "destroyPipelineCache" : "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineCache,pipelineCacheRequestCount,1);\n\t}", 1265 "cmdUpdateBuffer" : "\t\tincreaseCommandBufferSize(commandBuffer, dataSize);", 1266 "getDeviceQueue" : "\t\tm_vk.getDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);", 1267 } 1268 1269 statReturns = { 1270 "VkResult" : "return VK_SUCCESS;", 1271 "VkDeviceAddress" : "return 0u;", 1272 "uint64_t" : "return 0u;", 1273 } 1274 def makeFuncPtrInterfaceStatisticsImpl (): 1275 for function in api.functions: 1276 if function.getType() in functionTypes and not function.isAlias: 1277 yield "" 1278 yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), argListToStr(function.arguments)) 1279 yield "{" 1280 if ( getInterfaceName(function) in normFuncs ) or ( getInterfaceName(function) in statFuncs ): 1281 yield "\tstd::lock_guard<std::mutex> lock(functionMutex);" 1282 if getInterfaceName(function) != "getDeviceProcAddr" : 1283 yield "\tif (m_normalMode)" 1284 if getInterfaceName(function) in normFuncs : 1285 yield "%s" % ( normFuncs[getInterfaceName(function)] ) 1286 else: 1287 yield "\t\t%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments)) 1288 if getInterfaceName(function) in statFuncs : 1289 yield "\telse" 1290 yield "%s" % ( statFuncs[getInterfaceName(function)] ) 1291 elif getInterfaceName(function)[:3] == "cmd" : 1292 yield "\telse" 1293 yield "\t\tincreaseCommandBufferSize(commandBuffer, 0u);" 1294 if function.returnType in statReturns: 1295 yield "\t%s" % ( statReturns[function.returnType] ) 1296 yield "}" 1297 1298 writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceStatisticsImpl()) 1299 1300def writeStrUtilProto (api, filename): 1301 def makeStrUtilProto (): 1302 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"]): 1303 yield line 1304 yield "" 1305 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"]): 1306 yield line 1307 yield "" 1308 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"]): 1309 yield line 1310 yield "" 1311 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]): 1312 yield line 1313 yield "" 1314 for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.compositeTypes]): 1315 yield line 1316 1317 writeInlFile(filename, INL_HEADER, makeStrUtilProto()) 1318 1319def writeStrUtilImpl (api, filename): 1320 def makeStrUtilImpl (): 1321 for line in indentLines(["template<> const char*\tgetTypeName<%s>\t(void) { return \"%s\";\t}" % (handle.name, handle.name) for handle in api.handles]): 1322 yield line 1323 1324 yield "" 1325 yield "namespace %s" % PLATFORM_TYPE_NAMESPACE 1326 yield "{" 1327 1328 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): 1329 yield line 1330 1331 yield "}" 1332 1333 savedBitmasks = [] 1334 for enum in api.enums: 1335 if enum.type == "enum": 1336 yield "" 1337 yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name) 1338 yield "{" 1339 yield "\tswitch (value)" 1340 yield "\t{" 1341 enumValues = [] 1342 lastValue = 0x7FFFFFFF 1343 for e in enum.enumeratorList: 1344 enumValues.append(f"\t\tcase {e.name}:\treturn \"{e.name}\";") 1345 enumValues.append("\t\tdefault:\treturn DE_NULL;") 1346 for line in indentLines(enumValues): 1347 yield line 1348 yield "\t}" 1349 yield "}" 1350 elif enum.type == "bitmask": 1351 # find bitfield that uses those bitmasks 1352 foundBitmask = None 1353 for bitmask in api.bitmasks: 1354 if bitmask.requires == enum.name or bitmask.bitvalues == enum.name: 1355 foundBitmask = bitmask 1356 break 1357 savedBitmasks.append(foundBitmask.name) 1358 bitSize = "64" if foundBitmask.type == "VkFlags64" else "32" 1359 yield "" 1360 yield f"tcu::Format::Bitfield<{bitSize}> get{bitmask.name[2:]}Str ({bitmask.name} value)" 1361 yield "{" 1362 yield "\tstatic const tcu::Format::BitDesc s_desc[] =" 1363 yield "\t{" 1364 for line in indentLines([f"\t\ttcu::Format::BitDesc({e.name},\t\"{e.name}\")," for e in enum.enumeratorList]): 1365 yield line 1366 yield "\t};" 1367 yield f"\treturn tcu::Format::Bitfield<{bitSize}>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));" 1368 yield "}" 1369 1370 for bitmask in api.bitmasks: 1371 if bitmask.name not in savedBitmasks: 1372 bitSize = "64" if bitmask.type == "VkFlags64" else "32" 1373 yield "" 1374 yield f"tcu::Format::Bitfield<{bitSize}> get{bitmask.name[2:]}Str ({bitmask.name} value)" 1375 yield "{" 1376 yield f"\treturn tcu::Format::Bitfield<{bitSize}>(value, DE_NULL, DE_NULL);" 1377 yield "}" 1378 1379 bitfieldTypeNames = set([bitmask.name for bitmask in api.bitmasks]) 1380 1381 for type in api.compositeTypes: 1382 yield "" 1383 yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % type.name 1384 yield "{" 1385 yield "\ts << \"%s = {\\n\";" % type.name 1386 for member in type.members: 1387 memberName = member.name 1388 valFmt = None 1389 newLine = "" 1390 if member.type in bitfieldTypeNames: 1391 operator = '*' if member.pointer == '*' else '' 1392 valFmt = "get%sStr(%svalue.%s)" % (member.type[2:], operator, member.name) 1393 elif member.type == "char" and member.pointer == '*': 1394 valFmt = "getCharPtrStr(value.%s)" % member.name 1395 elif member.type == PLATFORM_TYPE_NAMESPACE + "::Win32LPCWSTR": 1396 valFmt = "getWStr(value.%s)" % member.name 1397 elif len(member.arraySizeList) > 0: 1398 singleDimensional = len(member.arraySizeList) == 1 1399 if member.name in ["extensionName", "deviceName", "layerName", "description"]: 1400 valFmt = "(const char*)value.%s" % member.name 1401 elif singleDimensional and (member.type == 'char' or member.type == 'uint8_t'): 1402 newLine = "'\\n' << " 1403 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) 1404 else: 1405 if member.name == "memoryTypes" or member.name == "memoryHeaps": 1406 endIter = "DE_ARRAY_BEGIN(value.%s) + value.%sCount" % (member.name, member.name[:-1]) 1407 else: 1408 endIter = "DE_ARRAY_END(value.%s)" % member.name 1409 newLine = "'\\n' << " 1410 valFmt = "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), %s)" % (member.name, endIter) 1411 memberName = member.name 1412 else: 1413 valFmt = "value.%s" % member.name 1414 yield ("\ts << \"\\t%s = \" << " % memberName) + newLine + valFmt + " << '\\n';" 1415 yield "\ts << '}';" 1416 yield "\treturn s;" 1417 yield "}" 1418 writeInlFile(filename, INL_HEADER, makeStrUtilImpl()) 1419 1420def writeObjTypeImpl (api, filename): 1421 def makeObjTypeImpl (): 1422 1423 yield "namespace vk" 1424 yield "{" 1425 1426 yield "template<typename T> VkObjectType getObjectType (void);" 1427 1428 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]): 1429 yield line 1430 1431 yield "}" 1432 1433 writeInlFile(filename, INL_HEADER, makeObjTypeImpl()) 1434 1435class ConstructorFunction: 1436 def __init__ (self, type, name, objectType, ifaceArgs, arguments): 1437 self.type = type 1438 self.name = name 1439 self.objectType = objectType 1440 self.ifaceArgs = ifaceArgs 1441 self.arguments = arguments 1442 1443def getConstructorFunctions (api): 1444 funcs = [] 1445 1446 ifacesDict = { 1447 Function.TYPE_PLATFORM: [FunctionArgument("vk", "const ", "PlatformInterface&")], 1448 Function.TYPE_INSTANCE: [FunctionArgument("vk", "const ", "InstanceInterface&")], 1449 Function.TYPE_DEVICE: [FunctionArgument("vk", "const ", "DeviceInterface&")]} 1450 1451 for function in api.functions: 1452 if (function.name[:8] == "vkCreate" or function.name == "vkAllocateMemory") and not "createInfoCount" in [a.name for a in function.arguments]: 1453 if function.name == "vkCreateDisplayModeKHR": 1454 continue # No way to delete display modes (bug?) 1455 1456 ifaceArgs = [] 1457 if function.name == "vkCreateDevice": 1458 ifaceArgs = [FunctionArgument("vkp", "const ", "PlatformInterface&"), 1459 FunctionArgument("instance", "", "VkInstance")] 1460 ifaceArgs.extend(ifacesDict[function.getType()]) 1461 1462 assert (function.arguments[-2].type == "VkAllocationCallbacks" and \ 1463 "const" in function.arguments[-2].qualifiers and \ 1464 function.arguments[-2].pointer == "*") 1465 1466 objectType = function.arguments[-1].type 1467 arguments = function.arguments[:-1] 1468 funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function.name), objectType, ifaceArgs, arguments)) 1469 return funcs 1470 1471def addVersionDefines(versionSpectrum): 1472 output = ["#define " + ver.getDefineName() + " " + ver.getInHex() for ver in versionSpectrum if not ver.isStandardVersion()] 1473 return output 1474 1475def writeRefUtilProto (api, filename): 1476 functions = getConstructorFunctions(api) 1477 1478 def makeRefUtilProto (): 1479 unindented = [] 1480 for line in indentLines(["Move<%s>\t%s\t(%s = DE_NULL);" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments)) for function in functions]): 1481 yield line 1482 1483 writeInlFile(filename, INL_HEADER, makeRefUtilProto()) 1484 1485def writeRefUtilImpl (api, filename): 1486 functions = getConstructorFunctions(api) 1487 1488 def makeRefUtilImpl (): 1489 yield "namespace refdetails" 1490 yield "{" 1491 yield "" 1492 1493 for function in api.functions: 1494 if function.getType() == Function.TYPE_DEVICE \ 1495 and (function.name[:9] == "vkDestroy" or function.name == "vkFreeMemory") \ 1496 and not function.name == "vkDestroyDevice": 1497 objectType = function.arguments[-2].type 1498 yield "template<>" 1499 yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType) 1500 yield "{" 1501 yield "\tm_deviceIface->%s(m_device, obj, m_allocator);" % (getInterfaceName(function.name)) 1502 yield "}" 1503 yield "" 1504 1505 yield "} // refdetails" 1506 yield "" 1507 1508 dtorDict = { 1509 Function.TYPE_PLATFORM: "object", 1510 Function.TYPE_INSTANCE: "instance", 1511 Function.TYPE_DEVICE: "device" 1512 } 1513 1514 for function in functions: 1515 deleterArgsString = '' 1516 if function.name == "createDevice": 1517 # createDevice requires two additional parameters to setup VkDevice deleter 1518 deleterArgsString = "vkp, instance, object, " + function.arguments[-1].name 1519 else: 1520 deleterArgsString = "vk, %s, %s" % (dtorDict[function.type], function.arguments[-1].name) 1521 1522 yield "Move<%s> %s (%s)" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments)) 1523 yield "{" 1524 yield "\t%s object = 0;" % function.objectType 1525 yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"])) 1526 yield "\treturn Move<%s>(check<%s>(object), Deleter<%s>(%s));" % (function.objectType, function.objectType, function.objectType, deleterArgsString) 1527 yield "}" 1528 yield "" 1529 1530 writeInlFile(filename, INL_HEADER, makeRefUtilImpl()) 1531 1532def writeStructTraitsImpl (api, filename): 1533 def gen (): 1534 for cType in api.compositeTypes: 1535 if cType.category == "struct" and cType.members[0].name == "sType" and cType.name != "VkBaseOutStructure" and cType.name != "VkBaseInStructure": 1536 yield "template<> VkStructureType getStructureType<%s> (void)" % cType.name 1537 yield "{" 1538 yield "\treturn %s;" % cType.members[0].values 1539 yield "}" 1540 yield "" 1541 1542 writeInlFile(filename, INL_HEADER, gen()) 1543 1544def writeNullDriverImpl (api, filename): 1545 def genNullDriverImpl (): 1546 specialFuncNames = [ 1547 "vkCreateGraphicsPipelines", 1548 "vkCreateComputePipelines", 1549 "vkCreateRayTracingPipelinesNV", 1550 "vkCreateRayTracingPipelinesKHR", 1551 "vkGetInstanceProcAddr", 1552 "vkGetDeviceProcAddr", 1553 "vkEnumeratePhysicalDevices", 1554 "vkEnumerateInstanceExtensionProperties", 1555 "vkEnumerateDeviceExtensionProperties", 1556 "vkGetPhysicalDeviceFeatures", 1557 "vkGetPhysicalDeviceFeatures2KHR", 1558 "vkGetPhysicalDeviceProperties", 1559 "vkGetPhysicalDeviceProperties2KHR", 1560 "vkGetPhysicalDeviceQueueFamilyProperties", 1561 "vkGetPhysicalDeviceMemoryProperties", 1562 "vkGetPhysicalDeviceFormatProperties", 1563 "vkGetPhysicalDeviceImageFormatProperties", 1564 "vkGetDeviceQueue", 1565 "vkGetBufferMemoryRequirements", 1566 "vkGetBufferMemoryRequirements2KHR", 1567 "vkGetImageMemoryRequirements", 1568 "vkGetImageMemoryRequirements2KHR", 1569 "vkAllocateMemory", 1570 "vkMapMemory", 1571 "vkUnmapMemory", 1572 "vkAllocateDescriptorSets", 1573 "vkFreeDescriptorSets", 1574 "vkResetDescriptorPool", 1575 "vkAllocateCommandBuffers", 1576 "vkFreeCommandBuffers", 1577 "vkCreateDisplayModeKHR", 1578 "vkCreateSharedSwapchainsKHR", 1579 "vkGetPhysicalDeviceExternalBufferPropertiesKHR", 1580 "vkGetPhysicalDeviceImageFormatProperties2KHR", 1581 "vkGetMemoryAndroidHardwareBufferANDROID", 1582 ] 1583 1584 specialFuncs = [f for f in api.functions if f.name in specialFuncNames] 1585 createFuncs = [f for f in api.functions if (f.name[:8] == "vkCreate" or f.name == "vkAllocateMemory") and not f in specialFuncs] 1586 destroyFuncs = [f for f in api.functions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs] 1587 dummyFuncs = [f for f in api.functions if f not in specialFuncs + createFuncs + destroyFuncs] 1588 1589 def getHandle (name): 1590 for handle in api.handles: 1591 if handle.name == name: 1592 return handle 1593 raise Exception("No such handle: %s" % name) 1594 1595 for function in createFuncs: 1596 objectType = function.arguments[-1].type 1597 argsStr = ", ".join([a.name for a in function.arguments[:-1]]) 1598 1599 yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments)) 1600 yield "{" 1601 yield "\tDE_UNREF(%s);" % function.arguments[-2].name 1602 1603 if getHandle(objectType).type == "VK_DEFINE_NON_DISPATCHABLE_HANDLE": 1604 yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr) 1605 else: 1606 yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr) 1607 yield "}" 1608 yield "" 1609 1610 for function in destroyFuncs: 1611 objectArg = function.arguments[-2] 1612 1613 yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments)) 1614 yield "{" 1615 for arg in function.arguments[:-2]: 1616 yield "\tDE_UNREF(%s);" % arg.name 1617 1618 if getHandle(objectArg.type).type == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE': 1619 yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name) 1620 else: 1621 yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name) 1622 1623 yield "}" 1624 yield "" 1625 1626 for function in dummyFuncs: 1627 yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function.name), argListToStr(function.arguments)) 1628 yield "{" 1629 for arg in function.arguments: 1630 yield "\tDE_UNREF(%s);" % arg.name 1631 if function.returnType != "void": 1632 yield "\treturn VK_SUCCESS;" 1633 yield "}" 1634 yield "" 1635 1636 def genFuncEntryTable (type, name): 1637 1638 entries = [] 1639 pattern = "\tVK_NULL_FUNC_ENTRY(%s,\t%s)," 1640 for f in api.functions: 1641 if f.getType() != type: 1642 continue 1643 entries.append(pattern % (f.name, getInterfaceName(f.name))) 1644 1645 yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name 1646 yield "{" 1647 1648 for line in indentLines(entries): 1649 yield line 1650 yield "};" 1651 yield "" 1652 1653 # Func tables 1654 for line in genFuncEntryTable(Function.TYPE_PLATFORM, "s_platformFunctions"): 1655 yield line 1656 1657 for line in genFuncEntryTable(Function.TYPE_INSTANCE, "s_instanceFunctions"): 1658 yield line 1659 1660 for line in genFuncEntryTable(Function.TYPE_DEVICE, "s_deviceFunctions"): 1661 yield line 1662 1663 writeInlFile(filename, INL_HEADER, genNullDriverImpl()) 1664 1665def writeTypeUtil (api, filename): 1666 # Structs filled by API queries are not often used in test code 1667 QUERY_RESULT_TYPES = set([ 1668 "VkPhysicalDeviceFeatures", 1669 "VkPhysicalDeviceLimits", 1670 "VkFormatProperties", 1671 "VkImageFormatProperties", 1672 "VkPhysicalDeviceSparseProperties", 1673 "VkQueueFamilyProperties", 1674 "VkMemoryType", 1675 "VkMemoryHeap", 1676 "StdVideoH264SpsVuiFlags", 1677 "StdVideoH264SpsFlags", 1678 "StdVideoH264PpsFlags", 1679 "StdVideoDecodeH264PictureInfoFlags", 1680 "StdVideoDecodeH264ReferenceInfoFlags", 1681 "StdVideoDecodeH264MvcElementFlags", 1682 "StdVideoEncodeH264SliceHeaderFlags", 1683 "StdVideoEncodeH264PictureInfoFlags", 1684 "StdVideoEncodeH264ReferenceInfoFlags", 1685 "StdVideoEncodeH264RefMgmtFlags", 1686 "StdVideoEncodeH264ReferenceInfoFlags", 1687 "StdVideoH265HrdFlags", 1688 "StdVideoH265VpsFlags", 1689 "StdVideoH265SpsVuiFlags", 1690 "StdVideoH265SpsFlags", 1691 "StdVideoH265PpsFlags", 1692 "StdVideoDecodeH265PictureInfoFlags", 1693 "StdVideoDecodeH265ReferenceInfoFlags", 1694 "StdVideoEncodeH265PictureInfoFlags", 1695 "StdVideoEncodeH265SliceSegmentHeaderFlags", 1696 "StdVideoEncodeH265ReferenceModificationFlags", 1697 "StdVideoEncodeH265ReferenceInfoFlags", 1698 "StdVideoEncodeH265SliceSegmentHeaderFlags", 1699 "StdVideoH265ProfileTierLevelFlags", 1700 "StdVideoH265ShortTermRefPicSetFlags", 1701 ]) 1702 1703 def isSimpleStruct (type): 1704 def hasArrayMember (type): 1705 for member in type.members: 1706 if len(member.arraySizeList) > 0: 1707 return True 1708 return False 1709 1710 def hasCompositeMember (type): 1711 for member in type.members: 1712 if member.pointer is not None and '*' not in member.pointer: 1713 match = [c for c in api.compositeTypes if member.type == c.name] 1714 if len(match) > 0: 1715 return True 1716 return False 1717 1718 return type.category == "struct" and \ 1719 type.members[0].type != "VkStructureType" and \ 1720 not type.name in QUERY_RESULT_TYPES and \ 1721 not hasArrayMember(type) and \ 1722 not hasCompositeMember(type) 1723 1724 def gen (): 1725 for type in api.compositeTypes: 1726 if not isSimpleStruct(type): 1727 continue 1728 1729 name = type.name[2:] if type.name[:2].lower() == "vk" else type.name 1730 1731 yield "" 1732 yield "inline %s make%s (%s)" % (type.name, name, argListToStr(type.members)) 1733 yield "{" 1734 yield "\t%s res;" % type.name 1735 for line in indentLines(["\tres.%s\t= %s;" % (m.name, m.name) for m in type.members]): 1736 yield line 1737 yield "\treturn res;" 1738 yield "}" 1739 1740 writeInlFile(filename, INL_HEADER, gen()) 1741 1742def writeDriverIds(api, filename): 1743 driverIdsString = [] 1744 driverIdsString.append("static const struct\n" 1745 "{\n" 1746 "\tstd::string driver;\n" 1747 "\tuint32_t id;\n" 1748 "} driverIds [] =\n" 1749 "{") 1750 driverItems = dict() 1751 driverIdEnum = [enum for enum in api.enums if enum.name == 'VkDriverId'][0] 1752 for enumerator in driverIdEnum.enumeratorList: 1753 driverIdsString.append(f"\t{{\"{enumerator.name}\", {enumerator.value}}},") 1754 driverItems[enumerator.name] = enumerator.value 1755 for enumerator in driverIdEnum.enumeratorList: 1756 if len(enumerator.aliasList) > 0: 1757 driverIdsString.append(f"\t{{\"{enumerator.aliasList[0]}\", {enumerator.value}}},\t// {enumerator.name}") 1758 driverIdsString.append("\t{\"VK_DRIVER_ID_MAX_ENUM\", 0x7FFFFFFF}") 1759 driverIdsString.append("};") 1760 1761 writeInlFile(filename, INL_HEADER, driverIdsString) 1762 1763def writeSupportedExtensions(apiName, api, filename): 1764 1765 def writeExtensionsForVersions(map): 1766 result = [] 1767 for version in map: 1768 result.append(" if (coreVersion >= " + str(version) + ")") 1769 result.append(" {") 1770 for extension in map[version]: 1771 result.append(' dst.push_back("' + extension.name + '");') 1772 result.append(" }") 1773 1774 if not map: 1775 result.append(" DE_UNREF(coreVersion);") 1776 1777 return result 1778 1779 instanceMap = {} 1780 deviceMap = {} 1781 1782 for ext in api.extensions: 1783 if ext.promotedto is None or "VK_VERSION" not in ext.promotedto: 1784 continue 1785 # skip partialy promoted extensions 1786 if ext.partiallyPromoted is True: 1787 continue 1788 major = int(ext.promotedto[-3]) 1789 minor = int(ext.promotedto[-1]) 1790 currVersion = "VK_API_VERSION_" + ext.promotedto[-3:] 1791 # VulkanSC is based on Vulkan 1.2. Any Vulkan version greater than 1.2 should be excluded 1792 if apiName=='SC' and major==1 and minor>2: 1793 continue 1794 if ext.type == 'instance': 1795 list = instanceMap.get(currVersion) 1796 instanceMap[currVersion] = list + [ext] if list else [ext] 1797 else: 1798 list = deviceMap.get(currVersion) 1799 deviceMap[currVersion] = list + [ext] if list else [ext] 1800 1801 # add list of extensions missing in Vulkan SC specification 1802 if apiName == 'SC': 1803 for extensionName, data in api.additionalExtensionData: 1804 # make sure that this extension was registered 1805 if 'register_extension' not in data.keys(): 1806 continue 1807 # save array containing 'device' or 'instance' string followed by the optional vulkan version in which this extension is core; 1808 # note that register_extension section is also required for partialy promoted extensions like VK_EXT_extended_dynamic_state2 1809 # but those extensions should not fill 'core' tag 1810 match = re.match("(\d).(\d).(\d).(\d)", data['register_extension']['core']) 1811 if match != None: 1812 currVersion = Version([int(match.group(1)), int(match.group(2)), int(match.group(3)), int(match.group(4))]) 1813 ext = Extension(extensionName, 0, 0, 0, 0, 0, 0, 0, 0, 0) 1814 if currVersion.api==0 and currVersion.major==1 and currVersion.minor>2: 1815 continue 1816 if data['register_extension']['type'] == 'instance': 1817 list = instanceMap.get(currVersion) 1818 instanceMap[currVersion] = list + [ext] if list else [ext] 1819 else: 1820 list = deviceMap.get(currVersion) 1821 deviceMap[currVersion] = list + [ext] if list else [ext] 1822 1823 lines = [ 1824 "", 1825 "void getCoreDeviceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(deviceMap) != 0 or apiName == 'SC' else ""), 1826 "{"] + writeExtensionsForVersions(deviceMap) + [ 1827 "}", 1828 "", 1829 "void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(instanceMap) != 0 or apiName == 'SC' else ""), 1830 "{"] + writeExtensionsForVersions(instanceMap) + [ 1831 "}", 1832 ""] 1833 writeInlFile(filename, INL_HEADER, lines) 1834 1835 1836def writeExtensionFunctions (api, filename): 1837 1838 def writeExtensionNameArrays (): 1839 instanceExtensionNames = [f"\t\"{ext.name}\"," for ext in api.extensions if ext.type == "instance"] 1840 deviceExtensionNames = [f"\t\"{ext.name}\"," for ext in api.extensions if ext.type == "device"] 1841 yield '::std::string instanceExtensionNames[] =\n{' 1842 for instanceExtName in instanceExtensionNames: 1843 yield instanceExtName 1844 yield '};\n' 1845 yield '::std::string deviceExtensionNames[] =\n{' 1846 for deviceExtName in deviceExtensionNames: 1847 yield deviceExtName 1848 yield '};' 1849 1850 def writeExtensionFunctions (functionType): 1851 isFirstWrite = True 1852 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 1853 if functionType == Function.TYPE_INSTANCE: 1854 yield 'void getInstanceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{' 1855 dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"] 1856 elif functionType == Function.TYPE_DEVICE: 1857 yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{' 1858 dg_list = ["vkGetDeviceGroupPresentCapabilitiesKHR", "vkGetDeviceGroupSurfacePresentModesKHR", "vkAcquireNextImage2KHR"] 1859 for ext in api.extensions: 1860 funcNames = [] 1861 for requirement in ext.requirementsList: 1862 for requiredCommand in requirement.newCommands: 1863 commandName = requiredCommand.name 1864 # find function that has specified name 1865 func = None 1866 funcList = [f for f in api.functions if f.name == commandName] 1867 # if name was not found check if this is alias 1868 if len(funcList) == 0: 1869 for f in api.functions: 1870 for aliasName in f.aliasList: 1871 if aliasName == commandName: 1872 func = f 1873 break 1874 else: 1875 func = funcList[0] 1876 if func.getType() == functionType: 1877 # only add functions with same vendor as extension 1878 # this is a workaroudn for entrypoints requiring more 1879 # than one excetions and lack of the dependency in vk.xml 1880 vendor = ext.name.split('_')[1] 1881 if func.name.endswith(vendor): 1882 funcNames.append(func.name) 1883 if ext.name: 1884 yield '\tif (extName == "%s")' % ext.name 1885 yield '\t{' 1886 for funcName in funcNames: 1887 if funcName in dg_list: 1888 yield '\t\tif(apiVersion >= VK_API_VERSION_1_1) functions.push_back("%s");' % funcName 1889 else: 1890 yield '\t\tfunctions.push_back("%s");' % funcName 1891 if ext.name == "VK_KHR_device_group": 1892 for dg_func in dg_list: 1893 yield '\t\tif(apiVersion < VK_API_VERSION_1_1) functions.push_back("%s");' % dg_func 1894 yield '\t\treturn;' 1895 yield '\t}' 1896 isFirstWrite = False 1897 if not isFirstWrite: 1898 yield '\tDE_FATAL("Extension name not found");' 1899 yield '}' 1900 1901 lines = [''] 1902 for line in writeExtensionFunctions(Function.TYPE_INSTANCE): 1903 lines += [line] 1904 lines += [''] 1905 for line in writeExtensionFunctions(Function.TYPE_DEVICE): 1906 lines += [line] 1907 lines += [''] 1908 for line in writeExtensionNameArrays(): 1909 lines += [line] 1910 1911 writeInlFile(filename, INL_HEADER, lines) 1912 1913def writeCoreFunctionalities(api, filename): 1914 functionOriginValues = ["FUNCTIONORIGIN_PLATFORM", "FUNCTIONORIGIN_INSTANCE", "FUNCTIONORIGIN_DEVICE"] 1915 1916 functionNamesPerApiVersionDict = {} 1917 for feature in api.features: 1918 apiVersion = "VK_API_VERSION_" + feature.number.replace('.', '_') 1919 functionNamesPerApiVersionDict[apiVersion] = [] 1920 for r in feature.requirementsList: 1921 functionNamesPerApiVersionDict[apiVersion].extend(r.commandList) 1922 1923 lines = [ 1924 "", 1925 'enum FunctionOrigin', '{'] + [line for line in indentLines([ 1926 '\t' + functionOriginValues[0] + '\t= 0,', 1927 '\t' + functionOriginValues[1] + ',', 1928 '\t' + functionOriginValues[2]])] + [ 1929 "};", 1930 "", 1931 "typedef ::std::pair<const char*, FunctionOrigin> FunctionInfo;", 1932 "typedef ::std::vector<FunctionInfo> FunctionInfosList;", 1933 "typedef ::std::map<uint32_t, FunctionInfosList> ApisMap;", 1934 "", 1935 "void initApisMap (ApisMap& apis)", 1936 "{", 1937 " apis.clear();"] + [ 1938 " apis.insert(::std::pair<uint32_t, FunctionInfosList>(" + v + ", FunctionInfosList()));" for v in functionNamesPerApiVersionDict] + [ 1939 ""] 1940 1941 apiVersions = [] 1942 functionLines = [] 1943 for apiVersion in functionNamesPerApiVersionDict: 1944 # iterate over names of functions added with api 1945 for functionName in functionNamesPerApiVersionDict[apiVersion]: 1946 # search for data of this function in all functions list 1947 functionData = None 1948 for f in api.functions: 1949 if functionName == f.name: 1950 functionData = f 1951 break 1952 assert(functionData != None) 1953 # add line coresponding to this function 1954 functionLines.append('\tapis[{0}].push_back(FunctionInfo("' + functionName + '",\t' + functionOriginValues[functionData.getType()] + '));') 1955 # functions for every api version should also include all functions from previous versions 1956 specializedLines = [line.format(apiVersion) for line in functionLines] 1957 # indent all functions of specified api and add them to main list 1958 lines = lines + [line for line in indentLines(specializedLines)] + [""] 1959 1960 lines = lines + ["}"] 1961 writeInlFile(filename, INL_HEADER, lines) 1962 1963def camelToSnake(name): 1964 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) 1965 return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower() 1966 1967def writeDeviceFeatures2(api, filename): 1968 1969 def structInAPI(compositeObject): 1970 for c in api.compositeTypes: 1971 if c.name == compositeObject.name: 1972 return True 1973 return False 1974 1975 # helper class used to encapsulate all data needed during generation 1976 class StructureDetail: 1977 def __init__ (self, compositeObject): 1978 self.nameList = [compositeObject.name] + compositeObject.aliasList 1979 self.sType = compositeObject.members[0].values 1980 self.instanceName = 'd' + compositeObject.name[11:] 1981 self.flagName = 'is' + compositeObject.name[16:] 1982 self.extension = None 1983 self.api = None 1984 self.major = None 1985 self.minor = None 1986 structureMembers = compositeObject.members[2:] 1987 self.members = [m.name for m in structureMembers] 1988 1989 # helper extension class used in algorith below 1990 class StructureFoundContinueToNextOne(Exception): 1991 pass 1992 1993 # find structures that extend VkPhysicalDeviceFeatures2 1994 structures = [c for c in api.compositeTypes if c.structextends is not None and 'VkPhysicalDeviceFeatures2' in c.structextends] 1995 # remove structures that were added by extensions other than KHR and EXT 1996 testedStructures = [] 1997 for s in structures: 1998 if all([postfix not in s.name for postfix in EXTENSION_POSTFIXES_VENDOR]): 1999 testedStructures.append(s) 2000 2001 existingStructures = list(filter(structInAPI, testedStructures)) # remove features not found in API ( important for Vulkan SC ) 2002 testedStructureDetail = [StructureDetail(struct) for struct in existingStructures] 2003 # iterate over all searched structures and find extensions that enabled them 2004 for structureDetail in testedStructureDetail: 2005 try: 2006 # iterate over all extensions 2007 for extension in api.extensions: 2008 for requirement in extension.requirementsList: 2009 for extensionStructure in requirement.newTypes: 2010 if extensionStructure.name in structureDetail.nameList: 2011 structureDetail.extension = extension.name 2012 if extension.promotedto is not None and extension.partiallyPromoted is False: 2013 # check if extension was promoted to vulkan version or other extension 2014 if 'VK_VERSION' in extension.promotedto: 2015 versionSplit = extension.promotedto.split('_') 2016 structureDetail.api = 0 # TODO handle this for Vulkan SC 2017 structureDetail.major = versionSplit[-2] 2018 structureDetail.minor = versionSplit[-1] 2019 else: 2020 structureDetail.extension = extension.promotedto 2021 raise StructureFoundContinueToNextOne 2022 except StructureFoundContinueToNextOne: 2023 continue 2024 for structureDetail in testedStructureDetail: 2025 if structureDetail.major is not None: 2026 continue 2027 # if structure was not added with extension then check if 2028 # it was added directly with one of vulkan versions 2029 structureName = structureDetail.nameList[0] 2030 for feature in api.features: 2031 for requirement in feature.requirementsList: 2032 if structureName in requirement.typeList: 2033 versionSplit = feature.name.split('_') 2034 structureDetail.api = 0 # TODO handle this for Vulkan SC 2035 structureDetail.major = versionSplit[-2] 2036 structureDetail.minor = versionSplit[-1] 2037 break 2038 if structureDetail.major is not None: 2039 break 2040 # generate file content 2041 structureDefinitions = [] 2042 featureEnabledFlags = [] 2043 clearStructures = [] 2044 structureChain = [] 2045 logStructures = [] 2046 verifyStructures = [] 2047 for index, structureDetail in enumerate(testedStructureDetail): 2048 structureName = structureDetail.nameList[0] 2049 # create two instances of each structure 2050 nameSpacing = '\t' 2051 structureDefinitions.append(structureName + nameSpacing + structureDetail.instanceName + '[count];') 2052 # create flags that check if proper extension or vulkan version is available 2053 condition = '' 2054 extension = structureDetail.extension 2055 major = structureDetail.major 2056 if extension is not None: 2057 condition = ' checkExtension(properties, "' + extension + '")' 2058 if major is not None: 2059 condition = ' ' if condition == '' else condition + ' || ' 2060 condition += 'context.contextSupports(vk::ApiVersion(' + str(structureDetail.api) + ', ' + str(major) + ', ' + str(structureDetail.minor) + ', 0))' 2061 if condition == '': 2062 condition = 'true' 2063 condition += ';' 2064 nameSpacing = '\t' * int((len(structureName) - 4) / 4) 2065 featureEnabledFlags.append('const bool' + nameSpacing + structureDetail.flagName + ' =' + condition) 2066 # clear memory of each structure 2067 clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx], 0xFF * ndx, sizeof(' + structureName + '));') 2068 # construct structure chain 2069 nextInstanceName = 'DE_NULL'; 2070 if index < len(testedStructureDetail)-1: 2071 nextInstanceName = '&' + testedStructureDetail[index+1].instanceName + '[ndx]' 2072 structureChain.append([ 2073 '\t\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.flagName + ' ? ' + structureDetail.sType + ' : VK_STRUCTURE_TYPE_MAX_ENUM;', 2074 '\t\t' + structureDetail.instanceName + '[ndx].pNext = DE_NULL;']) 2075 # construct log section 2076 logStructures.append([ 2077 '\tif (' + structureDetail.flagName + ')', 2078 '\t\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;' 2079 ]) 2080 #construct verification section 2081 verifyStructure = [] 2082 verifyStructure.append('\tif (' + structureDetail.flagName + ' &&') 2083 for index, m in enumerate(structureDetail.members): 2084 prefix = '\t\t(' if index == 0 else '\t\t ' 2085 postfix = '))' if index == len(structureDetail.members)-1 else ' ||' 2086 verifyStructure.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix) 2087 if len(structureDetail.members) == 0: 2088 verifyStructure.append('\t\tfalse)') 2089 verifyStructure.append('\t{\n\t\tTCU_FAIL("Mismatch between ' + structureName + '");\n\t}') 2090 verifyStructures.append(verifyStructure) 2091 2092 # construct file content 2093 stream = [] 2094 2095 # individual test functions 2096 for n, x in enumerate(testedStructureDetail): 2097 stream.append("tcu::TestStatus testPhysicalDeviceFeature" + x.instanceName[len('device'):]+" (Context& context)") 2098 stream.append("""{ 2099 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); 2100 const CustomInstance instance (createCustomInstanceWithExtension(context, "VK_KHR_get_physical_device_properties2")); 2101 const InstanceDriver& vki (instance.getDriver()); 2102 const int count = 2u; 2103 TestLog& log = context.getTestContext().getLog(); 2104 VkPhysicalDeviceFeatures2 extFeatures; 2105 vector<VkExtensionProperties> properties = enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL); 2106""") 2107 stream.append("\t"+structureDefinitions[n]) 2108 stream.append("\t"+featureEnabledFlags[n]) 2109 stream.append('') 2110 stream.append('\tfor (int ndx = 0; ndx < count; ++ndx)\n\t{') 2111 stream.append("\t" + clearStructures[n]) 2112 stream.extend(structureChain[n]) 2113 stream.append('') 2114 stream.append( 2115 '\t\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n' 2116 '\t\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n' 2117 '\t\textFeatures.pNext = &' + testedStructureDetail[n].instanceName + '[ndx];\n\n' 2118 '\t\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);') 2119 stream.append('\t}\n') 2120 stream.extend(logStructures[n]) 2121 stream.append('') 2122 stream.extend(verifyStructures[n]) 2123 stream.append('\treturn tcu::TestStatus::pass("Querying succeeded");') 2124 stream.append("}\n") 2125 2126 allApiVersions = [f.number for f in api.features] 2127 promotedTests = [] 2128 for feature in api.features: 2129 major = feature.number[0] 2130 minor = feature.number[-1] 2131 promotedFeatures = [] 2132 if feature.name == 'VK_VERSION_1_0': 2133 continue 2134 for requirement in feature.requirementsList: 2135 for type in requirement.typeList: 2136 matchedStructType = re.search(f'VkPhysicalDevice(\w+)Features', type, re.IGNORECASE) 2137 matchedCoreStructType = re.search(f'VkPhysicalDeviceVulkan(\d+)Features', type, re.IGNORECASE) 2138 if matchedStructType and not matchedCoreStructType: 2139 promotedFeatures.append(type) 2140 if promotedFeatures: 2141 testName = "createDeviceWithPromoted" + feature.number.replace('.', '') + "Structures" 2142 promotedTests.append(testName) 2143 stream.append("tcu::TestStatus " + testName + " (Context& context)") 2144 stream.append("{") 2145 stream.append( 2146 ' if (!context.contextSupports(vk::ApiVersion(0, ' + major + ', ' + minor + ', 0)))\n' 2147 ' TCU_THROW(NotSupportedError, "Vulkan ' + major + '.' + minor + ' is not supported");') 2148 stream.append(""" 2149 const PlatformInterface& platformInterface = context.getPlatformInterface(); 2150 const CustomInstance instance (createCustomInstanceFromContext(context)); 2151 const InstanceDriver& instanceDriver (instance.getDriver()); 2152 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); 2153 const deUint32 queueFamilyIndex = 0; 2154 const deUint32 queueCount = 1; 2155 const deUint32 queueIndex = 0; 2156 const float queuePriority = 1.0f; 2157 2158 const vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice); 2159 2160 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = 2161 { 2162 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 2163 DE_NULL, 2164 (VkDeviceQueueCreateFlags)0u, 2165 queueFamilyIndex, //queueFamilyIndex; 2166 queueCount, //queueCount; 2167 &queuePriority, //pQueuePriorities; 2168 }; 2169""") 2170 lastFeature = '' 2171 usedFeatures = [] 2172 for feature in promotedFeatures: 2173 for struct in testedStructureDetail: 2174 if (struct.instanceName in usedFeatures): 2175 continue 2176 if feature in struct.nameList: 2177 if lastFeature: 2178 stream.append("\t" + feature + " " + struct.instanceName + " = initVulkanStructure(&" + lastFeature + ");") 2179 else: 2180 stream.append("\t" + feature + " " + struct.instanceName + " = initVulkanStructure();") 2181 lastFeature = struct.instanceName 2182 usedFeatures.append(struct.instanceName) 2183 break 2184 stream.append("\tVkPhysicalDeviceFeatures2 extFeatures = initVulkanStructure(&" + lastFeature + ");") 2185 stream.append(""" 2186 instanceDriver.getPhysicalDeviceFeatures2 (physicalDevice, &extFeatures); 2187 2188 const VkDeviceCreateInfo deviceCreateInfo = 2189 { 2190 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType; 2191 &extFeatures, //pNext; 2192 (VkDeviceCreateFlags)0u, 2193 1, //queueRecordCount; 2194 &deviceQueueCreateInfo, //pRequestedQueues; 2195 0, //layerCount; 2196 DE_NULL, //ppEnabledLayerNames; 2197 0, //extensionCount; 2198 DE_NULL, //ppEnabledExtensionNames; 2199 DE_NULL, //pEnabledFeatures; 2200 }; 2201 2202 const Unique<VkDevice> device (createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), platformInterface, instance, instanceDriver, physicalDevice, &deviceCreateInfo)); 2203 const DeviceDriver deviceDriver (platformInterface, instance, device.get()); 2204 const VkQueue queue = getDeviceQueue(deviceDriver, *device, queueFamilyIndex, queueIndex); 2205 2206 VK_CHECK(deviceDriver.queueWaitIdle(queue)); 2207 2208 return tcu::TestStatus::pass("Pass"); 2209} 2210""") 2211 2212 # function to create tests 2213 stream.append("void addSeparateFeatureTests (tcu::TestCaseGroup* testGroup)\n{") 2214 for x in testedStructureDetail: 2215 stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x.instanceName[len('device'):]) + '", "' + x.nameList[0] + '", testPhysicalDeviceFeature' + x.instanceName[len('device'):] + ');') 2216 for x in promotedTests: 2217 stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x) + '", "", ' + x + ');') 2218 stream.append('}\n') 2219 2220 # write out 2221 writeInlFile(filename, INL_HEADER, stream) 2222 2223def generateDeviceFeaturesOrPropertiesDefs(api, FeaturesOrProperties): 2224 assert(FeaturesOrProperties in ['Features', 'Properties']) 2225 defs = [] 2226 foundStructureEnums = [] 2227 structureEnumPattern = f'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_{FeaturesOrProperties.upper()}(\w+)' 2228 structureEnumPatternNotExtension = structureEnumPattern[:-5] + '$' 2229 structureTypePattern = f'VkPhysicalDevice(\w+){FeaturesOrProperties}(\w+)' 2230 structureTypePatternNotExtension = structureTypePattern[:-5] + '$' 2231 structureTypeToSkipPattern = f'VkPhysicalDeviceVulkan\d\d{FeaturesOrProperties}' 2232 structureExtendsPattern = f'VkPhysicalDevice{FeaturesOrProperties}2' 2233 # iterate over all extensions to find extension that adds enum value matching pattern; 2234 # this will always be in first requirement section 2235 for ext in api.extensions: 2236 # skip extensions that were promoted to other extensions (not vk version) 2237 if ext.promotedto is not None and "VK_VERSION" not in ext.promotedto: 2238 continue 2239 allExtendedEnums = ext.requirementsList[0].extendedEnums 2240 for extendedEnum in allExtendedEnums: 2241 matchedStructEnum = re.search(structureEnumPattern, extendedEnum.name, re.IGNORECASE) 2242 if matchedStructEnum: 2243 # find feature/property structure type name 2244 structureTypeName = "" 2245 for stRequirement in ext.requirementsList[0].newTypes: 2246 stName = stRequirement.name 2247 matchedStructType = re.search(structureTypePattern, stName, re.IGNORECASE) 2248 if matchedStructType: 2249 structureTypeName = stName 2250 break 2251 # iterate over all composite types to check if structureTypeName is not alias 2252 # this handles case where extension was promoted and with it feature/property structure 2253 structureType = None 2254 for ct in api.compositeTypes: 2255 if structureTypeName == ct.name: 2256 structureType = ct 2257 break 2258 elif structureTypeName in ct.aliasList: 2259 structureType = ct 2260 structureTypeName = structureType.name 2261 break 2262 # use data in structextends to skip structures that should not be passed to vkGetPhysicalDeviceProperties(/Features)2 function 2263 if structureType.structextends is None or structureExtendsPattern not in structureType.structextends: 2264 continue 2265 # meke sure that structure was not added earlier - this handles special 2266 # cases like VkPhysicalDeviceIDPropertiesKHR added by 3 extensions 2267 if len([d for d in defs if d[3] == structureTypeName]) > 0: 2268 continue 2269 # there are cases like VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD 2270 # where 2 is after PROPERTIES - to handle this we need to split suffix to two parts 2271 sSuffix = matchedStructEnum.group(2) 2272 sVerSuffix = '' 2273 sExtSuffix = sSuffix 2274 suffixStart = sSuffix.rfind('_') 2275 if suffixStart > 0: 2276 sVerSuffix = sSuffix[:suffixStart] 2277 sExtSuffix = sSuffix[suffixStart:] 2278 foundStructureEnums.append(matchedStructEnum.group(1)) 2279 defs.append( (matchedStructEnum.group(1), sVerSuffix, sExtSuffix, structureTypeName,\ 2280 ext.name, allExtendedEnums[1].name, allExtendedEnums[0].name) ) 2281 # accept single feature/property structure per extension - this also handles cases 2282 # like VK_KHR_variable_pointers which specify feature structure and its alias 2283 break 2284 2285 # iterate over all structures to find Feature/Property structures that were not added with extension 2286 # but with vulkan version; to do that we need to skip extension part from pattern 2287 for ct in api.compositeTypes: 2288 matchedStructType = re.search(structureTypePatternNotExtension, ct.name, re.IGNORECASE) 2289 if matchedStructType: 2290 if ct.members[0].name != "sType": 2291 continue 2292 if ct.structextends is None or structureExtendsPattern not in ct.structextends: 2293 continue 2294 matchedStructEnum = re.search(structureEnumPatternNotExtension, ct.members[0].values, re.IGNORECASE) 2295 if (matchedStructEnum.group(1) not in foundStructureEnums) and (re.match(structureTypeToSkipPattern, ct.name) == None): 2296 defs.append( (matchedStructEnum.group(1), '', '', ct.name, None, None, '0') ) 2297 return defs 2298 2299def generateDevicePropertiesDefs(apiName, src): 2300 # look for definitions 2301 ptrnSType = r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_PROPERTIES(\w*)\s*=' 2302 matches = re.findall(ptrnSType, src, re.M) 2303 matches = sorted(matches, key=lambda m: m[0]) 2304 # hardcoded list of core extensions having properties and missing from Vulkan SC 2305 missingVulkanSCExt = \ 2306 '#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME \"VK_KHR_depth_stencil_resolve\"\n' \ 2307 '#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME \"VK_EXT_descriptor_indexing\"\n' \ 2308 '#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME \"VK_KHR_driver_properties\"\n' \ 2309 '#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME \"VK_KHR_shader_float_controls\"\n' \ 2310 '#define VK_KHR_MAINTENANCE3_EXTENSION_NAME \"VK_KHR_maintenance3\"\n' \ 2311 '#define VK_KHR_MULTIVIEW_EXTENSION_NAME \"VK_KHR_multiview\"\n' \ 2312 '#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME \"VK_EXT_sampler_filter_minmax\"\n' \ 2313 '#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME \"VK_KHR_timeline_semaphore\"\n' 2314 # construct final list 2315 defs = [] 2316 for sType, sSuffix in matches: 2317 # handle special cases 2318 if sType in {'VULKAN_1_1', 'VULKAN_1_2', 'VULKAN_1_3', 'VULKAN_SC_1_0', 'GROUP', 'MEMORY_BUDGET', 'MEMORY', 'TOOL'}: 2319 continue 2320 # there are cases like VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD 2321 # where 2 is after PROPERTIES - to handle this we need to split suffix to two parts 2322 sVerSuffix = '' 2323 sExtSuffix = sSuffix 2324 suffixStart = sSuffix.rfind('_') 2325 if suffixStart > 0: 2326 sVerSuffix = sSuffix[:suffixStart] 2327 sExtSuffix = sSuffix[suffixStart:] 2328 # handle special case 2329 if sType == "ID": 2330 structName = sType 2331 else: 2332 structName = re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '') 2333 ptrnStructName = r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Properties' + sSuffix.replace('_', '') + ')' 2334 matchStructName = re.search(ptrnStructName, src, re.M) 2335 if matchStructName: 2336 extType = sType 2337 if apiName == 'SC': 2338 if extType == "MAINTENANCE_3": 2339 extType = "MAINTENANCE3" 2340 elif extType == "MAINTENANCE_4": 2341 extType = "MAINTENANCE4" 2342 elif extType == "POINT_CLIPPING": 2343 extType = "MAINTENANCE2" 2344 # end handling special cases 2345 ptrnExtensionName = r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix +'[_0-9]*_EXTENSION_NAME).+$' 2346 matchExtensionName = re.search(ptrnExtensionName, src, re.M) 2347 if matchExtensionName is None and apiName=='SC': 2348 matchExtensionName = re.search(ptrnExtensionName, missingVulkanSCExt, re.M) 2349 ptrnSpecVersion = r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix + '[_0-9]*_SPEC_VERSION).+$' 2350 matchSpecVersion = re.search(ptrnSpecVersion, src, re.M) 2351 defs.append( (sType, sVerSuffix, sExtSuffix, matchStructName.group(1), \ 2352 matchExtensionName.group(0) if matchExtensionName else None, 2353 matchExtensionName.group(1) if matchExtensionName else None, 2354 matchSpecVersion.group (1) if matchSpecVersion else '0') ) 2355 return defs 2356 2357def writeDeviceFeatures(api, dfDefs, filename): 2358 # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs 2359 # and construct dictionary with all of their attributes 2360 blobMembers = {} 2361 blobStructs = {} 2362 blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") 2363 for structureType in api.compositeTypes: 2364 match = blobPattern.match(structureType.name) 2365 if match: 2366 allMembers = [member.name for member in structureType.members] 2367 vkVersion = match.group(1) 2368 blobMembers[vkVersion] = allMembers[2:] 2369 blobStructs[vkVersion] = set() 2370 initFromBlobDefinitions = [] 2371 emptyInitDefinitions = [] 2372 # iterate over all feature structures 2373 allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*") 2374 nonExtFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*$") 2375 for structureType in api.compositeTypes: 2376 # skip structures that are not feature structures 2377 if not allFeaturesPattern.match(structureType.name): 2378 continue 2379 # skip structures that were previously identified as blobs 2380 if blobPattern.match(structureType.name): 2381 continue 2382 # skip sType and pNext and just grab third and next attributes 2383 structureMembers = structureType.members[2:] 2384 notPartOfBlob = True 2385 if nonExtFeaturesPattern.match(structureType.name): 2386 # check if this member is part of any of the blobs 2387 for blobName, blobMemberList in blobMembers.items(): 2388 # if just one member is not part of this blob go to the next blob 2389 # (we asume that all members are part of blob - no need to check all) 2390 if structureMembers[0].name not in blobMemberList: 2391 continue 2392 # add another feature structure name to this blob 2393 blobStructs[blobName].add(structureType) 2394 # add specialization for this feature structure 2395 memberCopying = "" 2396 for member in structureMembers: 2397 memberCopying += "\tfeatureType.{0} = allFeaturesBlobs.vk{1}.{0};\n".format(member.name, blobName) 2398 wholeFunction = \ 2399 "template<> void initFeatureFromBlob<{0}>({0}& featureType, const AllFeaturesBlobs& allFeaturesBlobs)\n" \ 2400 "{{\n" \ 2401 "{1}" \ 2402 "}}".format(structureType.name, memberCopying) 2403 initFromBlobDefinitions.append(wholeFunction) 2404 notPartOfBlob = False 2405 # assuming that all members are part of blob, goto next 2406 break 2407 # add empty template definition as on Fedora there are issue with 2408 # linking using just generic template - all specializations are needed 2409 if notPartOfBlob: 2410 emptyFunction = "template<> void initFeatureFromBlob<{0}>({0}&, const AllFeaturesBlobs&) {{}}" 2411 emptyInitDefinitions.append(emptyFunction.format(structureType.name)) 2412 extensionDefines = [] 2413 makeFeatureDescDefinitions = [] 2414 featureStructWrappers = [] 2415 for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extName, extNameDef, specVersionDef) in enumerate(dfDefs): 2416 extensionNameDefinition = extNameDef 2417 if not extensionNameDefinition: 2418 extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) 2419 extensionDefines.append(f'#define {extensionNameDefinition} "not_existent_feature"') 2420 # construct makeFeatureDesc template function definitions 2421 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sVerSuffix + sExtSuffix) 2422 makeFeatureDescDefinitions.append("template<> FeatureDesc makeFeatureDesc<{0}>(void) " \ 2423 "{{ return FeatureDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVersionDef, len(dfDefs)-idx)) 2424 # construct CreateFeatureStruct wrapper block 2425 featureStructWrappers.append("\t{{ createFeatureStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVersionDef)) 2426 # construct function that will check for which vk version structure sType is part of blob 2427 blobChecker = "deUint32 getBlobFeaturesVersion (VkStructureType sType)\n{\n" \ 2428 "\tconst std::map<VkStructureType, deUint32> sTypeBlobMap\n" \ 2429 "\t{\n" 2430 # iterate over blobs with list of structures 2431 for blobName in sorted(blobStructs.keys()): 2432 blobChecker += "\t\t// Vulkan{0}\n".format(blobName) 2433 # iterate over all feature structures in current blob 2434 structuresList = list(blobStructs[blobName]) 2435 structuresList = sorted(structuresList, key=lambda s: s.name) 2436 for structType in structuresList: 2437 # find definition of this structure in dfDefs 2438 structDef = None 2439 allNamesToCheck = [structType.name] 2440 if len(structType.aliasList) > 0: 2441 allNamesToCheck.extend(structType.aliasList) 2442 for structName in allNamesToCheck: 2443 structDefList = [s for s in dfDefs if s[3] == structName] 2444 if len(structDefList) > 0: 2445 structDef = structDefList[0] 2446 break 2447 sType = structDef[0] 2448 sSuffix = structDef[1] + structDef[2] 2449 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix) 2450 tabs = "\t" * int((88 - len(sTypeName)) / 4) 2451 blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) 2452 blobChecker += "\t};\n\n" \ 2453 "\tauto it = sTypeBlobMap.find(sType);\n" \ 2454 "\tif(it == sTypeBlobMap.end())\n" \ 2455 "\t\treturn 0;\n" \ 2456 "\treturn it->second;\n" \ 2457 "}\n" 2458 # combine all definition lists 2459 stream = [ 2460 '#include "vkDeviceFeatures.hpp"\n', 2461 'namespace vk\n{'] 2462 stream.extend(extensionDefines) 2463 stream.append('\n') 2464 stream.extend(initFromBlobDefinitions) 2465 stream.append('\n// generic template is not enough for some compilers') 2466 stream.extend(emptyInitDefinitions) 2467 stream.append('\n') 2468 stream.extend(makeFeatureDescDefinitions) 2469 stream.append('\n') 2470 stream.append('static const FeatureStructCreationData featureStructCreationArray[]\n{') 2471 stream.extend(featureStructWrappers) 2472 stream.append('};\n') 2473 stream.append(blobChecker) 2474 stream.append('} // vk\n') 2475 writeInlFile(filename, INL_HEADER, stream) 2476 2477def writeDeviceFeatureTest(apiName, api, filename): 2478 2479 coreFeaturesPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$") 2480 featureItems = [] 2481 testFunctions = [] 2482 # iterate over all feature structures 2483 allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*") 2484 for structureType in api.compositeTypes: 2485 # skip structures that are not feature structures 2486 if not allFeaturesPattern.match(structureType.name): 2487 continue 2488 # skip sType and pNext and just grab third and next attributes 2489 structureMembers = structureType.members[2:] 2490 2491 items = [] 2492 for member in structureMembers: 2493 items.append(" FEATURE_ITEM ({0}, {1}),".format(structureType.name, member.name)) 2494 2495 testBlock = """ 2496tcu::TestStatus createDeviceWithUnsupportedFeaturesTest{4} (Context& context) 2497{{ 2498 const PlatformInterface& vkp = context.getPlatformInterface(); 2499 tcu::TestLog& log = context.getTestContext().getLog(); 2500 tcu::ResultCollector resultCollector (log); 2501 const CustomInstance instance (createCustomInstanceWithExtensions(context, context.getInstanceExtensions(), DE_NULL, true)); 2502 const InstanceDriver& instanceDriver (instance.getDriver()); 2503 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); 2504 const deUint32 queueFamilyIndex = 0; 2505 const deUint32 queueCount = 1; 2506 const float queuePriority = 1.0f; 2507 const DeviceFeatures deviceFeaturesAll (context.getInstanceInterface(), context.getUsedApiVersion(), physicalDevice, context.getInstanceExtensions(), context.getDeviceExtensions(), DE_TRUE); 2508 const VkPhysicalDeviceFeatures2 deviceFeatures2 = deviceFeaturesAll.getCoreFeatures2(); 2509 int numErrors = 0; 2510 bool isSubProcess = context.getTestContext().getCommandLine().isSubProcess(); 2511{6} 2512 2513 VkPhysicalDeviceFeatures emptyDeviceFeatures; 2514 deMemset(&emptyDeviceFeatures, 0, sizeof(emptyDeviceFeatures)); 2515 2516 // Only non-core extensions will be used when creating the device. 2517 vector<const char*> coreExtensions; 2518 getCoreDeviceExtensions(context.getUsedApiVersion(), coreExtensions); 2519 vector<string> nonCoreExtensions(removeExtensions(context.getDeviceExtensions(), coreExtensions)); 2520 2521 vector<const char*> extensionNames; 2522 extensionNames.reserve(nonCoreExtensions.size()); 2523 for (const string& extension : nonCoreExtensions) 2524 extensionNames.push_back(extension.c_str()); 2525 2526 if (const void* featuresStruct = findStructureInChain(const_cast<const void*>(deviceFeatures2.pNext), getStructureType<{0}>())) 2527 {{ 2528 static const Feature features[] = 2529 {{ 2530{1} 2531 }}; 2532 auto* supportedFeatures = reinterpret_cast<const {0}*>(featuresStruct); 2533 checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures, {5}); 2534 }} 2535 2536 if (numErrors > 0) 2537 return tcu::TestStatus(resultCollector.getResult(), "Enabling unsupported features didn't return VK_ERROR_FEATURE_NOT_PRESENT."); 2538 else 2539 return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage()); 2540}} 2541""" 2542 additionalParams = ( 'memReservationStatMax, isSubProcess' if apiName == 'SC' else 'isSubProcess' ) 2543 additionalDefs = ( ' VkDeviceObjectReservationCreateInfo memReservationStatMax = context.getResourceInterface()->getStatMax();' if apiName == 'SC' else '') 2544 featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("DE_NULL" if coreFeaturesPattern.match(structureType.name) else "&extensionNames"), structureType.name[len('VkPhysicalDevice'):], additionalParams, additionalDefs)) 2545 2546 testFunctions.append("createDeviceWithUnsupportedFeaturesTest" + structureType.name[len('VkPhysicalDevice'):]) 2547 2548 stream = [''] 2549 stream.extend(featureItems) 2550 stream.append(""" 2551void addSeparateUnsupportedFeatureTests (tcu::TestCaseGroup* testGroup) 2552{ 2553""") 2554 for x in testFunctions: 2555 stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x[len('createDeviceWithUnsupportedFeaturesTest'):]) + '", "' + x + '", ' + x + ');') 2556 stream.append('}\n') 2557 2558 writeInlFile(filename, INL_HEADER, stream) 2559 2560def writeDeviceProperties(api, dpDefs, filename): 2561 # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs 2562 # and construct dictionary with all of their attributes 2563 blobMembers = {} 2564 blobStructs = {} 2565 blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Properties[0-9]*$") 2566 for structureType in api.compositeTypes: 2567 match = blobPattern.match(structureType.name) 2568 if match: 2569 allMembers = [member.name for member in structureType.members] 2570 vkVersion = match.group(1) 2571 blobMembers[vkVersion] = allMembers[2:] 2572 blobStructs[vkVersion] = set() 2573 initFromBlobDefinitions = [] 2574 emptyInitDefinitions = [] 2575 # iterate over all property structures 2576 allPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*") 2577 nonExtPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*$") 2578 for structureType in api.compositeTypes: 2579 # skip structures that are not property structures 2580 if not allPropertiesPattern.match(structureType.name): 2581 continue 2582 # skip structures that were previously identified as blobs 2583 if blobPattern.match(structureType.name): 2584 continue 2585 # skip sType and pNext and just grab third and next attributes 2586 structureMembers = structureType.members[2:] 2587 notPartOfBlob = True 2588 if nonExtPropertiesPattern.match(structureType.name): 2589 # check if this member is part of any of the blobs 2590 for blobName, blobMemberList in blobMembers.items(): 2591 # if just one member is not part of this blob go to the next blob 2592 # (we asume that all members are part of blob - no need to check all) 2593 if structureMembers[0].name not in blobMemberList: 2594 continue 2595 # add another property structure name to this blob 2596 blobStructs[blobName].add(structureType) 2597 # add specialization for this property structure 2598 memberCopying = "" 2599 for member in structureMembers: 2600 if len(member.arraySizeList) == 0: 2601 # handle special case 2602 if structureType.name == "VkPhysicalDeviceSubgroupProperties" and "subgroup" not in member.name : 2603 blobMemberName = "subgroup" + member.name[0].capitalize() + member.name[1:] 2604 memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{2};\n".format(member.name, blobName, blobMemberName) 2605 # end handling special case 2606 else: 2607 memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{0};\n".format(member.name, blobName) 2608 else: 2609 memberCopying += "\tmemcpy(propertyType.{0}, allPropertiesBlobs.vk{1}.{0}, sizeof({2}) * {3});\n".format(member.name, blobName, member.type, member.arraySizeList[0]) 2610 wholeFunction = \ 2611 "template<> void initPropertyFromBlob<{0}>({0}& propertyType, const AllPropertiesBlobs& allPropertiesBlobs)\n" \ 2612 "{{\n" \ 2613 "{1}" \ 2614 "}}".format(structureType.name, memberCopying) 2615 initFromBlobDefinitions.append(wholeFunction) 2616 notPartOfBlob = False 2617 # assuming that all members are part of blob, goto next 2618 break 2619 # add empty template definition as on Fedora there are issue with 2620 # linking using just generic template - all specializations are needed 2621 if notPartOfBlob: 2622 emptyFunction = "template<> void initPropertyFromBlob<{0}>({0}&, const AllPropertiesBlobs&) {{}}" 2623 emptyInitDefinitions.append(emptyFunction.format(structureType.name)) 2624 extensionDefines = [] 2625 makePropertyDescDefinitions = [] 2626 propertyStructWrappers = [] 2627 for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extName, extNameDef, specVersionDef) in enumerate(dpDefs): 2628 extensionNameDefinition = extNameDef 2629 if not extensionNameDefinition: 2630 extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType) 2631 extensionDefines.append(f'#define {extensionNameDefinition} "core_property"') 2632 # construct makePropertyDesc template function definitions 2633 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sVerSuffix + sExtSuffix) 2634 makePropertyDescDefinitions.append("template<> PropertyDesc makePropertyDesc<{0}>(void) " \ 2635 "{{ return PropertyDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVersionDef, len(dpDefs)-idx)) 2636 # construct CreateProperty struct wrapper block 2637 propertyStructWrappers.append("\t{{ createPropertyStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVersionDef)) 2638 # construct method that will check if structure sType is part of blob 2639 blobChecker = "deUint32 getBlobPropertiesVersion (VkStructureType sType)\n{\n" \ 2640 "\tconst std::map<VkStructureType, deUint32> sTypeBlobMap\n" \ 2641 "\t{\n" 2642 # iterate over blobs with list of structures 2643 for blobName in sorted(blobStructs.keys()): 2644 blobChecker += "\t\t// Vulkan{0}\n".format(blobName) 2645 # iterate over all feature structures in current blob 2646 structuresList = list(blobStructs[blobName]) 2647 structuresList = sorted(structuresList, key=lambda s: s.name) 2648 for structType in structuresList: 2649 # find definition of this structure in dpDefs 2650 structName = structType.name 2651 structDef = None 2652 foundDefs = [s for s in dpDefs if s[3] == structName] 2653 if len(foundDefs) > 0: 2654 structDef = foundDefs[0] 2655 else: 2656 for alias in structType.aliasList: 2657 foundDefs = [s for s in dpDefs if s[3] == alias] 2658 if len(foundDefs) > 0: 2659 structDef = foundDefs[0] 2660 break 2661 sType = structDef[0] 2662 sSuffix = structDef[1] + structDef[2] 2663 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sSuffix) 2664 tabs = "\t" * int((80 - len(sTypeName)) / 4) 2665 blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1]) 2666 blobChecker += "\t};\n\n" \ 2667 "\tauto it = sTypeBlobMap.find(sType);\n" \ 2668 "\tif(it == sTypeBlobMap.end())\n" \ 2669 "\t\treturn 0;\n" \ 2670 "\treturn it->second;\n" \ 2671 "}\n" 2672 # combine all definition lists 2673 stream = [ 2674 '#include "vkDeviceProperties.hpp"\n', 2675 'namespace vk\n{'] 2676 stream.extend(extensionDefines) 2677 stream.append('\n') 2678 stream.extend(initFromBlobDefinitions) 2679 stream.append('\n// generic template is not enough for some compilers') 2680 stream.extend(emptyInitDefinitions) 2681 stream.append('\n') 2682 stream.extend(makePropertyDescDefinitions) 2683 stream.append('\n') 2684 stream.append('static const PropertyStructCreationData propertyStructCreationArray[] =\n{') 2685 stream.extend(propertyStructWrappers) 2686 stream.append('};\n') 2687 stream.append(blobChecker) 2688 stream.append('} // vk\n') 2689 writeInlFile(filename, INL_HEADER, stream) 2690 2691def genericDeviceFeaturesWriter(dfDefs, pattern, filename): 2692 stream = [] 2693 for _, _, _, extStruct, _, _, _ in dfDefs: 2694 nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "") 2695 stream.append(pattern.format(extStruct, nameSubStr)) 2696 writeInlFile(filename, INL_HEADER, indentLines(stream)) 2697 2698def writeDeviceFeaturesDefaultDeviceDefs(dfDefs, filename): 2699 pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceFeatures.getFeatureType<{0}>();\t}}" 2700 genericDeviceFeaturesWriter(dfDefs, pattern, filename) 2701 2702def writeDeviceFeaturesContextDecl(dfDefs, filename): 2703 pattern = "const vk::{0}&\tget{1}\t(void) const;" 2704 genericDeviceFeaturesWriter(dfDefs, pattern, filename) 2705 2706def writeDeviceFeaturesContextDefs(dfDefs, filename): 2707 pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}" 2708 genericDeviceFeaturesWriter(dfDefs, pattern, filename) 2709 2710def genericDevicePropertiesWriter(dfDefs, pattern, filename): 2711 stream = [] 2712 for _, _, _, extStruct, _, _, _ in dfDefs: 2713 nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "") 2714 if extStruct == "VkPhysicalDeviceRayTracingPropertiesNV": 2715 nameSubStr += "NV" 2716 stream.append(pattern.format(extStruct, nameSubStr)) 2717 writeInlFile(filename, INL_HEADER, indentLines(stream)) 2718 2719def writeDevicePropertiesDefaultDeviceDefs(dfDefs, filename): 2720 pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceProperties.getPropertyType<{0}>();\t}}" 2721 genericDevicePropertiesWriter(dfDefs, pattern, filename) 2722 2723def writeDevicePropertiesContextDecl(dfDefs, filename): 2724 pattern = "const vk::{0}&\tget{1}\t(void) const;" 2725 genericDevicePropertiesWriter(dfDefs, pattern, filename) 2726 2727def writeDevicePropertiesContextDefs(dfDefs, filename): 2728 pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}" 2729 genericDevicePropertiesWriter(dfDefs, pattern, filename) 2730 2731def writeMandatoryFeatures(api, filename): 2732 2733 def structInAPI(name): 2734 for c in api.compositeTypes: 2735 if c.name == name: 2736 return True 2737 for alias in c.aliasList: 2738 if alias == name: 2739 return True 2740 return False 2741 stream = [] 2742 2743 dictStructs = {} 2744 dictData = [] 2745 usedFeatureStructs = {} 2746 for _, data in api.additionalExtensionData: 2747 if 'mandatory_features' not in data.keys(): 2748 continue 2749 # sort to have same results for py2 and py3 2750 listStructFeatures = sorted(data['mandatory_features'].items(), key=lambda tup: tup[0]) 2751 for structure, featuresList in listStructFeatures: 2752 for featureData in featuresList: 2753 # allow for featureless VKSC only extensions 2754 if not 'features' in featureData.keys() or 'requirements' not in featureData.keys(): 2755 continue 2756 requirements = featureData['requirements'] 2757 2758 mandatory_variant = '' 2759 try: 2760 mandatory_variant = featureData['mandatory_variant'] 2761 except KeyError: 2762 mandatory_variant = '' 2763 2764 dictData.append( [ structure, featureData['features'], requirements, mandatory_variant] ) 2765 2766 if structure == 'VkPhysicalDeviceFeatures': 2767 continue 2768 2769 # if structure is not in dict construct name of variable and add is as a first item 2770 if (structure not in dictStructs): 2771 dictStructs[structure] = ([structure[2:3].lower() + structure[3:]], mandatory_variant) 2772 # add first requirement if it is unique 2773 if requirements and (requirements[0] not in dictStructs[structure][0]): 2774 dictStructs[structure][0].append(requirements[0]) 2775 2776 usedFeatureStructs[structure] = [] 2777 2778 if requirements: 2779 for req in requirements: 2780 if '.' in req: 2781 reqStruct = 'Vk' + req[0].upper() + req[1:] 2782 usedFeatureStructs[reqStruct] = [] 2783 2784 stream.extend(['bool canUseFeaturesStruct (const vector<VkExtensionProperties>& deviceExtensions, uint32_t usedApiVersion, const char* extension)', 2785 '{', 2786 '\treturn (isExtensionStructSupported(deviceExtensions, RequiredExtension(extension))', 2787 '\t\t\t|| isCoreDeviceExtension(usedApiVersion, extension));', 2788 '}', 2789 '', 2790 'bool checkMandatoryFeatures(const vkt::Context& context)\n{', 2791 '\tif (!context.isInstanceFunctionalitySupported("VK_KHR_get_physical_device_properties2"))', 2792 '\t\tTCU_THROW(NotSupportedError, "Extension VK_KHR_get_physical_device_properties2 is not present");', 2793 '', 2794 '\tVkPhysicalDevice\t\t\t\t\tphysicalDevice\t\t= context.getPhysicalDevice();', 2795 '\tconst InstanceInterface&\t\t\tvki\t\t\t\t\t= context.getInstanceInterface();', 2796 '\tconst vector<VkExtensionProperties>\tdeviceExtensions\t= enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL);', 2797 '\tconst uint32_t\t\t\t\t\t\tusedApiVersion\t\t= context.getUsedApiVersion();', 2798 '', 2799 '\ttcu::TestLog& log = context.getTestContext().getLog();', 2800 '\tvk::VkPhysicalDeviceFeatures2 coreFeatures;', 2801 '\tdeMemset(&coreFeatures, 0, sizeof(coreFeatures));', 2802 '\tcoreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;', 2803 '\tvoid** nextPtr = &coreFeatures.pNext;', 2804 '']) 2805 2806 # Find the extensions that added the required feature structs. 2807 class StructFoundContinue(Exception): 2808 pass 2809 2810 for usedStruct in usedFeatureStructs: 2811 for compType in api.compositeTypes: 2812 nameList = [compType.name] + compType.aliasList 2813 if usedStruct in nameList: 2814 # Found the official name list for the struct. 2815 for extension in api.extensions: 2816 try: 2817 for requirement in extension.requirementsList: 2818 for extensionStructure in requirement.newTypes: 2819 if extensionStructure.name in nameList: 2820 # Found extension for the struct. 2821 usedFeatureStructs[usedStruct].append(extension.name) 2822 raise StructFoundContinue 2823 except StructFoundContinue: 2824 pass 2825 2826 structList = sorted(usedFeatureStructs.items(), key=lambda tup: tup[0]) # sort to have same results for py2 and py3 2827 apiStructs = list( filter(lambda x : structInAPI(x[0]), structList)) # remove items not defined in current API 2828 2829 for structName, extensions in apiStructs: 2830 metaCondition = '' 2831 if structName in dictStructs: 2832 mandatoryVariantList = dictStructs[structName][1] 2833 if len(mandatoryVariantList) > 0: 2834 mandatoryVariant = mandatoryVariantList[0] 2835 metaCondition = 'defined(CTS_USES_' + mandatoryVariant.upper() + ')' 2836 stream.append('#if ' + metaCondition) 2837 2838 # The variable name will be the structure name without the Vk prefix and starting in lowercase. 2839 newVar = structName[2].lower() + structName[3:] 2840 2841 stream.extend(['\tvk::' + structName + ' ' + newVar + ';', 2842 '\tdeMemset(&' + newVar + ', 0, sizeof(' + newVar + '));', 2843 '']) 2844 2845 if len(extensions) > 0: 2846 canUseCond = '\tif (' 2847 for (i, extName) in enumerate(extensions): 2848 canUseCond += ' ' if i == 0 else ' || ' 2849 canUseCond += 'canUseFeaturesStruct(deviceExtensions, usedApiVersion, "' + extName + '")' 2850 canUseCond += ' )' 2851 stream.append(canUseCond) 2852 else: 2853 #reqs = v[0][1:] 2854 if structName in dictStructs: 2855 reqs = dictStructs[structName][0][1:] 2856 cond = 'if ( ' 2857 for i, req in enumerate(reqs): 2858 if i > 0: 2859 cond = cond + ' || ' 2860 if (req.startswith("ApiVersion")): 2861 cond = cond + 'context.contextSupports(vk::' + req + ')' 2862 cond = cond + ' )' 2863 stream.append('\t' + cond) 2864 2865 stream.extend(['\t{', 2866 '\t\t' + newVar + '.sType = getStructureType<' + structName + '>();', 2867 '\t\t*nextPtr = &' + newVar + ';', 2868 '\t\tnextPtr = &' + newVar + '.pNext;', 2869 '\t}']) 2870 2871 if len(metaCondition) > 0: 2872 stream.append('#endif // ' + metaCondition) 2873 2874 stream.append('') 2875 2876 stream.extend(['\tcontext.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &coreFeatures);', 2877 '\tbool result = true;', 2878 '']) 2879 2880 for v in dictData: 2881 if not structInAPI(v[0]): # remove items not defined in current API ( important for Vulkan SC ) 2882 continue 2883 structType = v[0]; 2884 structName = 'coreFeatures.features'; 2885 metaCondition = '' 2886 if len(v) == 4 and v[3] != '': 2887 # for x in v[3].split('_'): 2888 metaCondition = metaCondition + ' || defined(CTS_USES_' + v[3][0].upper() + ')' 2889 stream.extend(['#if ' + metaCondition[4:]]) 2890 if v[0] != 'VkPhysicalDeviceFeatures' : 2891 structName = dictStructs[v[0]][0][0] 2892 if len(v[2]) > 0 : 2893 condition = 'if ( ' 2894 for i, req in enumerate(v[2]) : 2895 if (req.startswith("ApiVersion")): 2896 condition = condition + 'context.contextSupports(vk::' + req + ')' 2897 elif '.' in req: 2898 condition = condition + req 2899 else: 2900 condition = condition + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))' 2901 if i+1 < len(v[2]) : 2902 condition = condition + ' && ' 2903 condition = condition + ' )' 2904 stream.append('\t' + condition) 2905 stream.append('\t{') 2906 # Don't need to support an AND case since that would just be another line in the .txt 2907 if len(v[1]) == 1: 2908 stream.append('\t\tif ( ' + structName + '.' + v[1][0] + ' == VK_FALSE )') 2909 else: 2910 condition = 'if ( ' 2911 for i, feature in enumerate(v[1]): 2912 if i != 0: 2913 condition = condition + ' && ' 2914 condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )' 2915 condition = condition + ' )' 2916 stream.append('\t\t' + condition) 2917 featureSet = " or ".join(v[1]) 2918 stream.extend(['\t\t{', 2919 '\t\t\tlog << tcu::TestLog::Message << "Mandatory feature ' + featureSet + ' not supported" << tcu::TestLog::EndMessage;', 2920 '\t\t\tresult = false;', 2921 '\t\t}', 2922 '\t}']) 2923 if metaCondition != '': 2924 stream.extend(['#endif // ' + metaCondition[4:], 2925 '']) 2926 else: 2927 stream.extend(['']) 2928 2929 stream.append('\treturn result;') 2930 stream.append('}\n') 2931 writeInlFile(filename, INL_HEADER, stream) 2932 2933def writeExtensionList(apiName, api, filename, extensionType): 2934 extensionList = [] 2935 for extensionName, data in api.additionalExtensionData: 2936 # make sure extension name starts with VK_KHR 2937 if not extensionName.startswith('VK_KHR'): 2938 continue 2939 # make sure that this extension was registered 2940 if 'register_extension' not in data.keys(): 2941 continue 2942 # make sure extension is intended for the vulkan variant 2943 is_sc_only = False 2944 2945 if apiName != 'SC': 2946 if 'mandatory_features' in data.keys(): 2947 for structure, listStruct in data['mandatory_features'].items(): 2948 for featureData in listStruct: 2949 mandatory_variant = '' 2950 try: 2951 mandatory_variant = featureData['mandatory_variant'] 2952 except KeyError: 2953 mandatory_variant = '' 2954 # VKSC only 2955 if 'vulkansc' in mandatory_variant: 2956 is_sc_only = True 2957 if is_sc_only: 2958 continue 2959 2960 # make sure extension has proper type 2961 if extensionType == data['register_extension']['type']: 2962 extensionList.append(extensionName) 2963 extensionList.sort() 2964 # write list of all found extensions 2965 stream = [] 2966 stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(extensionType.title())) 2967 for n in extensionList: 2968 stream.append('\t"' + n + '",') 2969 stream.append('};\n') 2970 writeInlFile(filename, INL_HEADER, stream) 2971 2972def writeApiExtensionDependencyInfo(api, filename): 2973 2974 def isExtensionInCore(ext, apiMajor, apiMinor): 2975 if ext.promotedto is None: 2976 return False 2977 if 'VK_VERSION' not in ext.promotedto: 2978 return False 2979 extMajor = ext.promotedto[-3] 2980 extMinor = ext.promotedto[-1] 2981 if apiMajor > extMajor: 2982 return True 2983 if apiMajor == extMajor and apiMinor >= extMinor: 2984 return True 2985 return False 2986 2987 def genExtDepArray(extType): 2988 yield 'static const std::tuple<deUint32, deUint32, deUint32, const char*, const char*>\t{}ExtensionDependencies[]\t='.format(extType) 2989 yield '{' 2990 allApiVersions = [f.number for f in api.features] 2991 # iterate over all extension that are of specified type and that have requirements 2992 for ext in api.extensions: 2993 if ext.type != extType: 2994 continue 2995 if ext.requiredExtensions is None: 2996 continue 2997 apiVariant = '0' 2998 # iterate over all api versions 2999 for apiVersion in allApiVersions: 3000 major, minor = apiVersion.split('.') 3001 if ext.requiresCore is not None: 3002 requiresCoreMajor, requiresCoreMinor = ext.requiresCore.split('.') 3003 if major < requiresCoreMajor or minor < requiresCoreMinor: 3004 continue 3005 if isExtensionInCore(ext, major, minor): 3006 continue 3007 # iterate over all requirements and add to the list those that are 3008 # applicable for currently processed api version 3009 for r in ext.requiredExtensions: 3010 # find required extension and make sure it is not part of core for this or previous api version 3011 requiredExtensionList = [re for re in api.extensions if re.name == r] 3012 if len(requiredExtensionList) > 0: 3013 requiredExtension = requiredExtensionList[0] 3014 if isExtensionInCore(requiredExtension, major, minor): 3015 continue 3016 yield '\tstd::make_tuple({}, {}, {}, "{}", "{}"),'.format(apiVariant, major, minor, ext.name, r) 3017 yield '};' 3018 3019 def genApiVersions(): 3020 yield 'static const std::tuple<deUint32, deUint32, deUint32, deUint32>\treleasedApiVersions[]\t=' 3021 yield '{' 3022 for f in reversed(api.features): 3023 apiVariant = '0' if f.api == 'vulkan' else '1' 3024 major, minor = f.number.split('.') 3025 version = (int(apiVariant) << 29) | (int(major) << 22) | (int(minor) << 12) 3026 yield '\tstd::make_tuple({}, {}, {}, {}),'.format(version, apiVariant, major, minor) 3027 yield '};' 3028 3029 def genRequiredCoreVersions(): 3030 yield 'static const std::tuple<deUint32, deUint32, const char*>\textensionRequiredCoreVersion[]\t =' 3031 yield '{' 3032 for ext in api.extensions: 3033 # skip video extensions 3034 if 'vulkan_video_' in ext.name: 3035 continue 3036 major, minor = '1', '0' 3037 if ext.requiresCore is not None: 3038 major, minor = ext.requiresCore.split('.') 3039 yield '\tstd::make_tuple({}, {}, "{}"),'.format(major, minor, ext.name) 3040 yield '};' 3041 3042 stream = [] 3043 stream.extend(genExtDepArray('instance')) 3044 stream.extend(genExtDepArray('device')) 3045 stream.extend(genApiVersions()) 3046 stream.extend(genRequiredCoreVersions()) 3047 3048 writeInlFile(filename, INL_HEADER, stream) 3049 3050def writeEntryPointValidation(api, filename): 3051 # keys are instance extension names and value is list of device-level functions 3052 instExtDeviceFunDict = {} 3053 # iterate over all extensions and find instance extensions 3054 for ext in api.extensions: 3055 if ext.type == "instance": 3056 # iterate over all functions instance extension adds 3057 for requirement in ext.requirementsList: 3058 for extCommand in requirement.newCommands: 3059 # to get a type of command we need to find this command definition in list of all functions 3060 for command in api.functions: 3061 if extCommand.name == command.name or extCommand.name in command.aliasList: 3062 # check if this is device-level entry-point 3063 if command.getType() == Function.TYPE_DEVICE: 3064 if ext.name not in instExtDeviceFunDict: 3065 instExtDeviceFunDict[ext.name] = [] 3066 instExtDeviceFunDict[ext.name].append(extCommand.name) 3067 stream = ['std::map<std::string, std::vector<std::string> > instExtDeviceFun', '{'] 3068 for extName in instExtDeviceFunDict: 3069 stream.append(f'\t{{ "{extName}",\n\t\t{{') 3070 for fun in instExtDeviceFunDict[extName]: 3071 stream.append(f'\t\t\t"{fun}",') 3072 stream.append('\t\t}\n\t},') 3073 stream.append('};') 3074 writeInlFile(filename, INL_HEADER, stream) 3075 3076def parseCmdLineArgs(): 3077 parser = argparse.ArgumentParser(description = "Generate Vulkan INL files", 3078 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 3079 parser.add_argument("-a", 3080 "--api", 3081 dest="api", 3082 default="", 3083 help="Choose between Vulkan and Vulkan SC") 3084 parser.add_argument("-o", 3085 "--outdir", 3086 dest="outdir", 3087 default="", 3088 help="Choose output directory") 3089 return parser.parse_args() 3090 3091if __name__ == "__main__": 3092 args = parseCmdLineArgs() 3093 3094 # if argument was specified it is interpreted as a path to which .inl files will be written 3095 outputPath = DEFAULT_OUTPUT_DIR[args.api] if args.outdir == '' else args.outdir 3096 3097 currentDir = os.getcwd() 3098 api = API() 3099 3100 if args.api == '': 3101 3102 # Read vk.xml and generate vulkan headers from it 3103 os.chdir(VULKAN_XML_DIR) 3104 api.build( etree.parse("vk.xml") ) 3105 api.build( etree.parse("video.xml") ) 3106 api.postProcess() 3107 3108 elif args.api=='SC': 3109 # At the moment structure of vk.xml for Vulkan SC is not final. 3110 # For time being we will use old version of gen_framework script that 3111 # was saved as gen_framework_sc (it still parses vulkan_sc_core.h) 3112 os.chdir(os.path.dirname(__file__)) 3113 pythonExecutable = sys.executable or "python" 3114 print("Executing gen_framework_sc.py") 3115 execute([pythonExecutable, "gen_framework_sc.py", "--api", "SC"]) 3116 exit (0) 3117 3118 os.chdir(currentDir) 3119 3120 platformFuncs = [Function.TYPE_PLATFORM] 3121 instanceFuncs = [Function.TYPE_INSTANCE] 3122 deviceFuncs = [Function.TYPE_DEVICE] 3123 3124 dfd = generateDeviceFeaturesOrPropertiesDefs(api, 'Features') 3125 writeDeviceFeatures (api, dfd, os.path.join(outputPath, "vkDeviceFeatures.inl")) 3126 writeDeviceFeaturesDefaultDeviceDefs (dfd, os.path.join(outputPath, "vkDeviceFeaturesForDefaultDeviceDefs.inl")) 3127 writeDeviceFeaturesContextDecl (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDecl.inl")) 3128 writeDeviceFeaturesContextDefs (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDefs.inl")) 3129 writeDeviceFeatureTest (args.api, api, os.path.join(outputPath, "vkDeviceFeatureTest.inl")) 3130 3131 dpd = generateDeviceFeaturesOrPropertiesDefs(api, 'Properties') 3132 writeDeviceProperties (api, dpd, os.path.join(outputPath, "vkDeviceProperties.inl")) 3133 writeDevicePropertiesDefaultDeviceDefs (dpd, os.path.join(outputPath, "vkDevicePropertiesForDefaultDeviceDefs.inl")) 3134 writeDevicePropertiesContextDecl (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDecl.inl")) 3135 writeDevicePropertiesContextDefs (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDefs.inl")) 3136 3137 writeHandleType (api, os.path.join(outputPath, "vkHandleType.inl")) 3138 writeBasicTypes (args.api, api, os.path.join(outputPath, "vkBasicTypes.inl")) 3139 writeCompositeTypes (api, os.path.join(outputPath, "vkStructTypes.inl")) 3140 writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualPlatformInterface.inl"), platformFuncs, False) 3141 writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualInstanceInterface.inl"), instanceFuncs, False) 3142 writeInterfaceDecl (api, os.path.join(outputPath, "vkVirtualDeviceInterface.inl"), deviceFuncs, False) 3143 writeInterfaceDecl (api, os.path.join(outputPath, "vkConcretePlatformInterface.inl"), platformFuncs, True) 3144 writeInterfaceDecl (api, os.path.join(outputPath, "vkConcreteInstanceInterface.inl"), instanceFuncs, True) 3145 writeInterfaceDecl (api, os.path.join(outputPath, "vkConcreteDeviceInterface.inl"), deviceFuncs, True) 3146 writeFunctionPtrTypes (api, os.path.join(outputPath, "vkFunctionPointerTypes.inl")) 3147 writeFunctionPointers (api, os.path.join(outputPath, "vkPlatformFunctionPointers.inl"), platformFuncs) 3148 writeFunctionPointers (api, os.path.join(outputPath, "vkInstanceFunctionPointers.inl"), instanceFuncs) 3149 writeFunctionPointers (api, os.path.join(outputPath, "vkDeviceFunctionPointers.inl"), deviceFuncs) 3150 writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitPlatformFunctionPointers.inl"), platformFuncs, lambda f: f.name != "vkGetInstanceProcAddr") 3151 writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitInstanceFunctionPointers.inl"), instanceFuncs) 3152 writeInitFunctionPointers (api, os.path.join(outputPath, "vkInitDeviceFunctionPointers.inl"), deviceFuncs) 3153 writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkPlatformDriverImpl.inl"), platformFuncs, "PlatformDriver") 3154 writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkInstanceDriverImpl.inl"), instanceFuncs, "InstanceDriver") 3155 writeFuncPtrInterfaceImpl (api, os.path.join(outputPath, "vkDeviceDriverImpl.inl"), deviceFuncs, "DeviceDriver") 3156 if args.api=='SC': 3157 writeFuncPtrInterfaceSCImpl (api, os.path.join(outputPath, "vkDeviceDriverSCImpl.inl"), deviceFuncs, "DeviceDriverSC") 3158 writeStrUtilProto (api, os.path.join(outputPath, "vkStrUtil.inl")) 3159 writeStrUtilImpl (api, os.path.join(outputPath, "vkStrUtilImpl.inl")) 3160 writeRefUtilProto (api, os.path.join(outputPath, "vkRefUtil.inl")) 3161 writeRefUtilImpl (api, os.path.join(outputPath, "vkRefUtilImpl.inl")) 3162 writeStructTraitsImpl (api, os.path.join(outputPath, "vkGetStructureTypeImpl.inl")) 3163 writeNullDriverImpl (api, os.path.join(outputPath, "vkNullDriverImpl.inl")) 3164 writeTypeUtil (api, os.path.join(outputPath, "vkTypeUtil.inl")) 3165 writeSupportedExtensions (args.api, api, os.path.join(outputPath, "vkSupportedExtensions.inl")) 3166 writeCoreFunctionalities (api, os.path.join(outputPath, "vkCoreFunctionalities.inl")) 3167 writeExtensionFunctions (api, os.path.join(outputPath, "vkExtensionFunctions.inl")) 3168 writeDeviceFeatures2 (api, os.path.join(outputPath, "vkDeviceFeatures2.inl")) 3169 writeMandatoryFeatures (api, os.path.join(outputPath, "vkMandatoryFeatures.inl")) 3170 writeExtensionList (args.api, api, os.path.join(outputPath, "vkInstanceExtensions.inl"), 'instance') 3171 writeExtensionList (args.api, api, os.path.join(outputPath, "vkDeviceExtensions.inl"), 'device') 3172 writeDriverIds (api, os.path.join(outputPath, "vkKnownDriverIds.inl")) 3173 writeObjTypeImpl (api, os.path.join(outputPath, "vkObjTypeImpl.inl")) 3174 writeApiExtensionDependencyInfo (api, os.path.join(outputPath, "vkApiExtensionDependencyInfo.inl")) 3175 writeEntryPointValidation (api, os.path.join(outputPath, "vkEntryPointValidation.inl")) 3176 3177 # NOTE: when new files are generated then they should also be added to the 3178 # vk-gl-cts\external\vulkancts\framework\vulkan\CMakeLists.txt outputs list 3179