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