1# Copyright 2018 Google LLC 2# SPDX-License-Identifier: MIT 3from typing import Dict, Optional, List, Set, Union 4from xml.etree.ElementTree import Element 5 6from generator import noneStr 7 8from copy import copy 9from dataclasses import dataclass 10from string import whitespace 11 12# Holds information about core Vulkan objects 13# and the API calls that are used to create/destroy each one. 14class HandleInfo(object): 15 def __init__(self, name, createApis, destroyApis): 16 self.name = name 17 self.createApis = createApis 18 self.destroyApis = destroyApis 19 20 def isCreateApi(self, apiName): 21 return apiName == self.createApis or (apiName in self.createApis) 22 23 def isDestroyApi(self, apiName): 24 if self.destroyApis is None: 25 return False 26 return apiName == self.destroyApis or (apiName in self.destroyApis) 27 28DISPATCHABLE_HANDLE_TYPES = [ 29 "VkInstance", 30 "VkPhysicalDevice", 31 "VkDevice", 32 "VkQueue", 33 "VkCommandBuffer", 34] 35 36NON_DISPATCHABLE_HANDLE_TYPES = [ 37 "VkDeviceMemory", 38 "VkBuffer", 39 "VkBufferView", 40 "VkImage", 41 "VkImageView", 42 "VkShaderModule", 43 "VkDescriptorPool", 44 "VkDescriptorSetLayout", 45 "VkDescriptorSet", 46 "VkSampler", 47 "VkPipeline", 48 "VkPipelineLayout", 49 "VkRenderPass", 50 "VkFramebuffer", 51 "VkPipelineCache", 52 "VkCommandPool", 53 "VkFence", 54 "VkSemaphore", 55 "VkEvent", 56 "VkQueryPool", 57 "VkSamplerYcbcrConversion", 58 "VkSamplerYcbcrConversionKHR", 59 "VkDescriptorUpdateTemplate", 60 "VkSurfaceKHR", 61 "VkSwapchainKHR", 62 "VkDisplayKHR", 63 "VkDisplayModeKHR", 64 "VkObjectTableNVX", 65 "VkIndirectCommandsLayoutNVX", 66 "VkValidationCacheEXT", 67 "VkDebugReportCallbackEXT", 68 "VkDebugUtilsMessengerEXT", 69 "VkAccelerationStructureNV", 70 "VkIndirectCommandsLayoutNV", 71 "VkAccelerationStructureKHR", 72 "VkPrivateDataSlot", 73] 74 75CUSTOM_HANDLE_CREATE_TYPES = [ 76 "VkPhysicalDevice", 77 "VkQueue", 78 "VkPipeline", 79 "VkDeviceMemory", 80 "VkDescriptorSet", 81 "VkCommandBuffer", 82 "VkRenderPass", 83] 84 85HANDLE_TYPES = list(sorted(list(set(DISPATCHABLE_HANDLE_TYPES + 86 NON_DISPATCHABLE_HANDLE_TYPES + CUSTOM_HANDLE_CREATE_TYPES)))) 87 88HANDLE_INFO = {} 89 90for h in HANDLE_TYPES: 91 if h in CUSTOM_HANDLE_CREATE_TYPES: 92 if h == "VkPhysicalDevice": 93 HANDLE_INFO[h] = \ 94 HandleInfo( 95 "VkPhysicalDevice", 96 "vkEnumeratePhysicalDevices", None) 97 if h == "VkQueue": 98 HANDLE_INFO[h] = \ 99 HandleInfo( 100 "VkQueue", 101 ["vkGetDeviceQueue", "vkGetDeviceQueue2"], 102 None) 103 if h == "VkPipeline": 104 HANDLE_INFO[h] = \ 105 HandleInfo( 106 "VkPipeline", 107 ["vkCreateGraphicsPipelines", "vkCreateComputePipelines"], 108 "vkDestroyPipeline") 109 if h == "VkDeviceMemory": 110 HANDLE_INFO[h] = \ 111 HandleInfo("VkDeviceMemory", 112 "vkAllocateMemory", ["vkFreeMemory", "vkFreeMemorySyncGOOGLE"]) 113 if h == "VkDescriptorSet": 114 HANDLE_INFO[h] = \ 115 HandleInfo("VkDescriptorSet", "vkAllocateDescriptorSets", 116 "vkFreeDescriptorSets") 117 if h == "VkCommandBuffer": 118 HANDLE_INFO[h] = \ 119 HandleInfo("VkCommandBuffer", "vkAllocateCommandBuffers", 120 "vkFreeCommandBuffers") 121 if h == "VkRenderPass": 122 HANDLE_INFO[h] = \ 123 HandleInfo( 124 "VkRenderPass", 125 ["vkCreateRenderPass", "vkCreateRenderPass2", "vkCreateRenderPass2KHR"], 126 "vkDestroyRenderPass") 127 else: 128 HANDLE_INFO[h] = \ 129 HandleInfo(h, "vkCreate" + h[2:], "vkDestroy" + h[2:]) 130 131EXCLUDED_APIS = [ 132 "vkEnumeratePhysicalDeviceGroups", 133] 134 135EXPLICITLY_ABI_PORTABLE_TYPES = [ 136 "VkResult", 137 "VkBool32", 138 "VkSampleMask", 139 "VkFlags", 140 "VkDeviceSize", 141] 142 143EXPLICITLY_ABI_NON_PORTABLE_TYPES = [ 144 "size_t" 145] 146 147NON_ABI_PORTABLE_TYPE_CATEGORIES = [ 148 "handle", 149 "funcpointer", 150] 151 152# A class for holding the parameter indices corresponding to various 153# attributes about a VkDeviceMemory, such as the handle, size, offset, etc. 154@dataclass 155class DeviceMemoryInfoParameterIndices: 156 handle: int = -1 157 offset: int = -1 158 size: int = -1 159 typeIndex: int = -1 160 typeBits: int = -1 161 162DEVICE_MEMORY_STRUCTS = { 163 "VkMemoryAllocateInfo": {"1": DeviceMemoryInfoParameterIndices(typeIndex = 3)}, 164 "VkMemoryRequirements": {"1": DeviceMemoryInfoParameterIndices(typeBits = 2)}, 165 "VkMappedMemoryRange": {"1": DeviceMemoryInfoParameterIndices(handle = 2, offset = 3, size = 4)}, 166 "VkSparseMemoryBind": {"1": DeviceMemoryInfoParameterIndices(handle = 2, offset = 3)}, 167 "VkSparseImageMemoryBind": {"1": DeviceMemoryInfoParameterIndices(handle = 3, offset = 4)}, 168 "VkWin32KeyedMutexAcquireReleaseInfoNV": {"1": DeviceMemoryInfoParameterIndices(handle = 3), "2": DeviceMemoryInfoParameterIndices(handle = 7)}, 169 "VkMemoryWin32HandlePropertiesKHR": {"1": DeviceMemoryInfoParameterIndices(typeBits = 2)}, 170 "VkMemoryGetWin32HandleInfoKHR": {"1": DeviceMemoryInfoParameterIndices(handle = 2)}, 171 "VkMemoryFdPropertiesKHR": {"1": DeviceMemoryInfoParameterIndices(typeBits = 2)}, 172 "VkMemoryGetFdInfoKHR": {"1": DeviceMemoryInfoParameterIndices(handle = 2)}, 173 "VkWin32KeyedMutexAcquireReleaseInfoKHR": {"1": DeviceMemoryInfoParameterIndices(handle = 3), "2": DeviceMemoryInfoParameterIndices(handle = 7)}, 174 "VkBindBufferMemoryInfo": {"1": DeviceMemoryInfoParameterIndices(handle = 3, offset = 4)}, 175 "VkBindImageMemoryInfo": {"1": DeviceMemoryInfoParameterIndices(handle = 3, offset = 4)}, 176 "VkMemoryHostPointerPropertiesEXT": {"1": DeviceMemoryInfoParameterIndices(typeBits = 2)}, 177 "VkAndroidHardwareBufferPropertiesANDROID": {"1": DeviceMemoryInfoParameterIndices(typeBits = 3)}, 178 "VkMemoryGetAndroidHardwareBufferInfoANDROID": {"1": DeviceMemoryInfoParameterIndices(handle = 2)}, 179 "VkBindAccelerationStructureMemoryInfoNV": {"1": DeviceMemoryInfoParameterIndices(handle = 3, offset = 4)}, 180 "VkDeviceMemoryOpaqueCaptureAddressInfo": {"1": DeviceMemoryInfoParameterIndices(handle = 2)}, 181} 182 183DEVICE_MEMORY_COMMANDS = { 184 "vkFreeMemory": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 185 "vkMapMemory": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 186 "vkUnmapMemory": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 187 "vkGetDeviceMemoryCommitment": {"1": DeviceMemoryInfoParameterIndices(handle = 1, offset = 2)}, 188 "vkBindBufferMemory": {"1": DeviceMemoryInfoParameterIndices(handle = 2, offset = 3)}, 189 "vkBindImageMemory": {"1": DeviceMemoryInfoParameterIndices(handle = 2, offset = 3)}, 190 "vkGetBlobGOOGLE": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 191 "vkGetMemoryWin32HandleNV": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 192 "vkMapMemoryIntoAddressSpaceGOOGLE": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 193 "vkGetMemoryHostAddressInfoGOOGLE": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 194 "vkFreeMemorySyncGOOGLE": {"1": DeviceMemoryInfoParameterIndices(handle = 1)}, 195} 196 197TRIVIAL_TRANSFORMED_TYPES = [ 198 "VkPhysicalDeviceExternalImageFormatInfo", 199 "VkPhysicalDeviceExternalBufferInfo", 200 "VkExternalMemoryImageCreateInfo", 201 "VkExternalMemoryBufferCreateInfo", 202 "VkExportMemoryAllocateInfo", 203 "VkExternalImageFormatProperties", 204 "VkExternalBufferProperties", 205] 206 207NON_TRIVIAL_TRANSFORMED_TYPES = [ 208 "VkExternalMemoryProperties", 209 "VkImageCreateInfo", 210] 211 212TRANSFORMED_TYPES = TRIVIAL_TRANSFORMED_TYPES + NON_TRIVIAL_TRANSFORMED_TYPES 213 214STRUCT_STREAM_FEATURE = { 215 "VkPhysicalDeviceShaderFloat16Int8Features": "VULKAN_STREAM_FEATURE_SHADER_FLOAT16_INT8_BIT", 216 "VkPhysicalDeviceShaderFloat16Int8FeaturesKHR": "VULKAN_STREAM_FEATURE_SHADER_FLOAT16_INT8_BIT", 217 "VkPhysicalDeviceFloat16Int8FeaturesKHR": "VULKAN_STREAM_FEATURE_SHADER_FLOAT16_INT8_BIT", 218} 219 220STRUCT_MEMBER_STREAM_FEATURE = { 221 "VkGraphicsPipelineCreateInfo.pVertexInputState": "VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT", 222 "VkGraphicsPipelineCreateInfo.pInputAssemblyState": "VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT", 223 "VkGraphicsPipelineCreateInfo.pRasterizationState": "VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT", 224} 225 226STRUCT_ENV_STR = { 227 "VkGraphicsPipelineCreateInfo": { 228 "hasTessellation": "(arrayany pStages 0 stageCount (lambda ((s VkPipelineShaderStageCreateInfo)) (or (eq (getfield s stage) VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) (eq (getfield s stage) VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))))", 229 "hasRasterization" : "(or (if (eq 0 pRasterizationState) 0 (not (getfield pRasterizationState rasterizerDiscardEnable))) (if (eq 0 pDynamicState) 0 (arrayany (getfield pDynamicState pDynamicStates) 0 (getfield pDynamicState dynamicStateCount) (lambda ((s VkDynamicState)) (eq s VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE)))))" 230 }, 231} 232 233STRUCT_MEMBER_FILTER_VAR = { 234 "VkGraphicsPipelineCreateInfo.pTessellationState": "hasTessellation", 235 "VkGraphicsPipelineCreateInfo.pViewportState": "hasRasterization", 236 "VkGraphicsPipelineCreateInfo.pMultisampleState": "hasRasterization", 237 "VkGraphicsPipelineCreateInfo.pDepthStencilState": "hasRasterization", 238 "VkGraphicsPipelineCreateInfo.pColorBlendState": "hasRasterization", 239 "VkWriteDescriptorSet.pImageInfo": "descriptorType", 240 "VkWriteDescriptorSet.pBufferInfo": "descriptorType", 241 "VkWriteDescriptorSet.pTexelBufferView": "descriptorType", 242 "VkFramebufferCreateInfo.pAttachments": "flags", 243} 244 245STRUCT_MEMBER_FILTER_VALS = { 246 "VkWriteDescriptorSet.pImageInfo": [ 247 "VK_DESCRIPTOR_TYPE_SAMPLER", 248 "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER", 249 "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE", 250 "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE", 251 "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT" 252 ], 253 "VkWriteDescriptorSet.pBufferInfo": [ 254 "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER", 255 "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC", 256 "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER", 257 "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC", 258 ], 259 "VkWriteDescriptorSet.pTexelBufferView": [ 260 "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER", 261 "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER", 262 ], 263} 264 265STRUCT_MEMBER_FILTER_FUNC = { 266 "VkFramebufferCreateInfo.pAttachments": "(eq (bitwise_and flags VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) 0)", 267} 268 269# vk.xml added optional to some of the existing fields. For backward compatibility 270# we need to ignore those optionals. 271# We might want to add more complex safety checks in future. 272STRUCT_MEMBER_IGNORE_OPTIONAL = { 273 "VkSubmitInfo.pWaitDstStageMask", 274 "VkPipelineLayoutCreateInfo.pSetLayouts", 275 "VkGraphicsPipelineCreateInfo.pStages", 276 "VkPipelineColorBlendStateCreateInfo.pAttachments", 277 "VkFramebufferCreateInfo.attachmentCount", 278 "VkFramebufferCreateInfo.pAttachments", 279 "VkVideoProfileInfoKHR.chromaBitDepth", 280 "VkVideoDecodeInfoKHR.pSetupReferenceSlot", 281 "vkCmdBindDescriptorSets.pDescriptorSets", 282 "vkCmdBindDescriptorSets.local_pDescriptorSets", 283 "vkCmdBindVertexBuffers.pBuffers", 284 "vkCmdBindVertexBuffers.local_pBuffers", 285 "vkCmdClearColorImage.pColor", 286 "vkCmdClearColorImage.local_pColor", 287} 288 289# Holds information about a Vulkan type instance (i.e., not a type definition). 290# Type instances are used as struct field definitions or function parameters, 291# to be later fed to code generation. 292# VulkanType instances can be constructed in two ways: 293# 1. From an XML tag with <type> / <param> tags in vk.xml, 294# using makeVulkanTypeFromXMLTag 295# 2. User-defined instances with makeVulkanTypeSimple. 296class VulkanType(object): 297 298 def __init__(self): 299 self.parent: Optional[VulkanType] = None 300 self.typeName: str = "" 301 302 self.isTransformed = False 303 304 self.paramName: Optional[str] = None 305 306 self.lenExpr: Optional[str] = None # Value of the `len` attribute in the spec 307 self.isOptional: bool = False 308 self.optionalStr: Optional[str] = None # Value of the `optional` attribute in the spec 309 310 self.isConst = False 311 312 # "" means it's not a static array, otherwise this is the total size of 313 # all elements. e.g. staticArrExpr of "x[3][2][8]" will be "((3)*(2)*(8))". 314 self.staticArrExpr = "" 315 # "" means it's not a static array, otherwise it's the raw expression 316 # of static array size, which can be one-dimensional or multi-dimensional. 317 self.rawStaticArrExpr = "" 318 319 self.pointerIndirectionLevels = 0 # 0 means not pointer 320 self.isPointerToConstPointer = False 321 322 self.primitiveEncodingSize = None 323 324 self.deviceMemoryInfoParameterIndices = None 325 326 # Annotations 327 # Environment annotation for binding current 328 # variables to sub-structures 329 self.binds = {} 330 331 # Device memory annotations 332 333 # self.deviceMemoryAttrib/Val stores 334 # device memory info attributes 335 self.deviceMemoryAttrib = None 336 self.deviceMemoryVal = None 337 338 # Filter annotations 339 self.filterVar = None 340 self.filterVals = None 341 self.filterFunc = None 342 self.filterOtherwise = None 343 344 # Stream feature 345 self.streamFeature = None 346 347 # All other annotations 348 self.attribs = {} 349 350 self.nonDispatchableHandleCreate = False 351 self.nonDispatchableHandleDestroy = False 352 self.dispatchHandle = False 353 self.dispatchableHandleCreate = False 354 self.dispatchableHandleDestroy = False 355 356 357 def __str__(self,): 358 return ("(vulkantype %s %s paramName %s len %s optional? %s " 359 "staticArrExpr %s)") % ( 360 self.typeName + ("*" * self.pointerIndirectionLevels) + 361 ("ptr2constptr" if self.isPointerToConstPointer else ""), "const" 362 if self.isConst else "nonconst", self.paramName, self.lenExpr, 363 self.isOptional, self.staticArrExpr) 364 365 def isString(self): 366 return self.pointerIndirectionLevels == 1 and (self.typeName == "char") 367 368 def isArrayOfStrings(self): 369 return self.isPointerToConstPointer and (self.typeName == "char") 370 371 def primEncodingSize(self): 372 return self.primitiveEncodingSize 373 374 # Utility functions to make codegen life easier. 375 # This method derives the correct "count" expression if possible. 376 # Otherwise, returns None or "null-terminated" if a string. 377 def getLengthExpression(self): 378 if self.staticArrExpr != "": 379 return self.staticArrExpr 380 if self.lenExpr: 381 # Use a simple lookup table for latexmath. 382 known_expressions = { 383 r"latexmath:[\lceil{\mathit{samples} \over 32}\rceil]": 384 "int(samples / 32)", 385 r"latexmath:[2 \times \mathtt{VK\_UUID\_SIZE}]": "2 * VK_UUID_SIZE", 386 } 387 if self.lenExpr in known_expressions: 388 return known_expressions[self.lenExpr] 389 return self.lenExpr 390 return None 391 392 # Can we just pass this to functions expecting T* 393 def accessibleAsPointer(self): 394 if self.staticArrExpr != "": 395 return True 396 if self.pointerIndirectionLevels > 0: 397 return True 398 return False 399 400 # Rough attempt to infer where a type could be an output. 401 # Good for inferring which things need to be marshaled in 402 # versus marshaled out for Vulkan API calls 403 def possiblyOutput(self,): 404 return self.pointerIndirectionLevels > 0 and (not self.isConst) 405 406 def isVoidWithNoSize(self,): 407 return self.typeName == "void" and self.pointerIndirectionLevels == 0 408 409 def getCopy(self,): 410 return copy(self) 411 412 def getTransformed(self, isConstChoice=None, ptrIndirectionChoice=None): 413 res = self.getCopy() 414 415 if isConstChoice is not None: 416 res.isConst = isConstChoice 417 if ptrIndirectionChoice is not None: 418 res.pointerIndirectionLevels = ptrIndirectionChoice 419 420 return res 421 422 def getWithCustomName(self): 423 return self.getTransformed( 424 ptrIndirectionChoice=self.pointerIndirectionLevels + 1) 425 426 def getForAddressAccess(self): 427 return self.getTransformed( 428 ptrIndirectionChoice=self.pointerIndirectionLevels + 1) 429 430 def getForValueAccess(self): 431 if self.typeName == "void" and self.pointerIndirectionLevels == 1: 432 asUint8Type = self.getCopy() 433 asUint8Type.typeName = "uint8_t" 434 return asUint8Type.getForValueAccess() 435 return self.getTransformed( 436 ptrIndirectionChoice=self.pointerIndirectionLevels - 1) 437 438 def getForNonConstAccess(self): 439 return self.getTransformed(isConstChoice=False) 440 441 def withModifiedName(self, newName): 442 res = self.getCopy() 443 res.paramName = newName 444 return res 445 446 def isNextPointer(self): 447 return self.paramName == "pNext" 448 449 def isSigned(self): 450 return self.typeName in ["int", "int8_t", "int16_t", "int32_t", "int64_t"] 451 452 def isEnum(self, typeInfo): 453 return typeInfo.categoryOf(self.typeName) == "enum" 454 455 def isBitmask(self, typeInfo): 456 return typeInfo.categoryOf(self.typeName) == "enum" 457 458 # Only deals with 'core' handle types here. 459 def isDispatchableHandleType(self): 460 return self.typeName in DISPATCHABLE_HANDLE_TYPES 461 462 def isNonDispatchableHandleType(self): 463 return self.typeName in NON_DISPATCHABLE_HANDLE_TYPES 464 465 def isHandleType(self): 466 return self.isDispatchableHandleType() or \ 467 self.isNonDispatchableHandleType() 468 469 def isCreatedBy(self, api): 470 if self.shouldSkip(): 471 return False 472 if self.typeName in HANDLE_INFO.keys(): 473 nonKhrRes = HANDLE_INFO[self.typeName].isCreateApi(api.name) 474 if nonKhrRes: 475 return True 476 if len(api.name) > 3 and "KHR" == api.name[-3:]: 477 return HANDLE_INFO[self.typeName].isCreateApi(api.name[:-3]) 478 479 if self.typeName == "VkImage" and api.name == "vkCreateImageWithRequirementsGOOGLE": 480 return True 481 482 if self.typeName == "VkBuffer" and api.name == "vkCreateBufferWithRequirementsGOOGLE": 483 return True 484 485 return False 486 487 def isDestroyedBy(self, api): 488 if self.shouldSkip(): 489 return False 490 if self.typeName in HANDLE_INFO.keys(): 491 nonKhrRes = HANDLE_INFO[self.typeName].isDestroyApi(api.name) 492 if nonKhrRes: 493 return True 494 if len(api.name) > 3 and "KHR" == api.name[-3:]: 495 return HANDLE_INFO[self.typeName].isDestroyApi(api.name[:-3]) 496 497 return False 498 499 def isSimpleValueType(self, typeInfo): 500 if typeInfo.isCompoundType(self.typeName): 501 return False 502 if self.isString() or self.isArrayOfStrings(): 503 return False 504 if self.staticArrExpr or self.pointerIndirectionLevels > 0: 505 return False 506 return True 507 508 def getStructEnumExpr(self,): 509 return None 510 511 def getPrintFormatSpecifier(self): 512 kKnownTypePrintFormatSpecifiers = { 513 'float': '%f', 514 'int': '%d', 515 'int32_t': '%d', 516 'size_t': '%ld', 517 'uint16_t': '%d', 518 'uint32_t': '%d', 519 'uint64_t': '%ld', 520 'VkBool32': '%d', 521 'VkDeviceSize': '%ld', 522 'VkFormat': '%d', 523 'VkImageLayout': '%d', 524 } 525 526 if self.pointerIndirectionLevels > 0 or self.isHandleType(): 527 return '%p' 528 529 if self.typeName in kKnownTypePrintFormatSpecifiers: 530 return kKnownTypePrintFormatSpecifiers[self.typeName] 531 532 if self.typeName.endswith('Flags'): 533 # Based on `typedef uint32_t VkFlags;` 534 return '%d' 535 536 return None 537 def isOptionalPointer(self) -> bool: 538 return self.isOptional and \ 539 (not self.isForceOptional()) and\ 540 self.pointerIndirectionLevels > 0 and \ 541 (not self.isNextPointer()) 542 543 def isForceOptional(self) -> bool: 544 """ 545 Returns true if we should generate a placeholder for null. 546 547 Vulkan updates change certain pointers from non-optional to 548 optional. We want to keep our encoder/decoder backward compatible. 549 Thus we should generate a placeholder for such APIs. 550 """ 551 return self.getFullName() in STRUCT_MEMBER_IGNORE_OPTIONAL 552 553 def getFullName(self) -> str: 554 if self.parent is None: 555 return self.paramName 556 return f"{self.parent.name}.{self.paramName}" 557 558 def getProtectStreamFeature(self) -> Optional[str]: 559 key = self.getFullName() 560 if key in STRUCT_MEMBER_STREAM_FEATURE.keys(): 561 return STRUCT_MEMBER_STREAM_FEATURE[key] 562 return None 563 564 def shouldSkip(self) -> bool: 565 return ("api" in self.attribs.keys() 566 and not "vulkan" == self.attribs["api"]) 567 568# Is an S-expression w/ the following spec: 569# From https://gist.github.com/pib/240957 570class Atom(object): 571 def __init__(self, name): 572 self.name = name 573 def __repr__(self,): 574 return self.name 575 576def parse_sexp(sexp): 577 atom_end = set('()"\'') | set(whitespace) 578 stack, i, length = [[]], 0, len(sexp) 579 while i < length: 580 c = sexp[i] 581 582 reading = type(stack[-1]) 583 if reading == list: 584 if c == '(': stack.append([]) 585 elif c == ')': 586 stack[-2].append(stack.pop()) 587 if stack[-1][0] == ('quote',): stack[-2].append(stack.pop()) 588 elif c == '"': stack.append('') 589 elif c == "'": stack.append([('quote',)]) 590 elif c in whitespace: pass 591 else: stack.append(Atom(c)) 592 elif reading == str: 593 if c == '"': 594 stack[-2].append(stack.pop()) 595 if stack[-1][0] == ('quote',): stack[-2].append(stack.pop()) 596 elif c == '\\': 597 i += 1 598 stack[-1] += sexp[i] 599 else: stack[-1] += c 600 elif reading == Atom: 601 if c in atom_end: 602 atom = stack.pop() 603 if atom.name[0].isdigit(): stack[-1].append(eval(atom.name)) 604 else: stack[-1].append(atom) 605 if stack[-1][0] == ('quote',): stack[-2].append(stack.pop()) 606 continue 607 else: stack[-1] = Atom(stack[-1].name + c) 608 i += 1 609 610 return stack.pop() 611 612class FuncExprVal(object): 613 def __init__(self, val): 614 self.val = val 615 def __repr__(self,): 616 return self.val.__repr__() 617 618class FuncExpr(object): 619 def __init__(self, name, args): 620 self.name = name 621 self.args = args 622 def __repr__(self,): 623 if len(self.args) == 0: 624 return "(%s)" % (self.name.__repr__()) 625 else: 626 return "(%s %s)" % (self.name.__repr__(), " ".join(map(lambda x: x.__repr__(), self.args))) 627 628class FuncLambda(object): 629 def __init__(self, vs, body): 630 self.vs = vs 631 self.body = body 632 def __repr__(self,): 633 return "(L (%s) %s)" % (" ".join(map(lambda x: x.__repr__(), self.vs)), self.body.__repr__()) 634 635class FuncLambdaParam(object): 636 def __init__(self, name, typ): 637 self.name = name 638 self.typ = typ 639 def __repr__(self,): 640 return "%s : %s" % (self.name, self.typ) 641 642def parse_func_expr(parsed_sexp): 643 if len(parsed_sexp) != 1: 644 print("Error: parsed # expressions != 1: %d" % (len(parsed_sexp))) 645 raise 646 647 e = parsed_sexp[0] 648 649 def parse_lambda_param(e): 650 return FuncLambdaParam(e[0].name, e[1].name) 651 652 def parse_one(exp): 653 if list == type(exp): 654 if "lambda" == exp[0].__repr__(): 655 return FuncLambda(list(map(parse_lambda_param, exp[1])), parse_one(exp[2])) 656 else: 657 return FuncExpr(exp[0], list(map(parse_one, exp[1:]))) 658 else: 659 return FuncExprVal(exp) 660 661 return parse_one(e) 662 663def parseFilterFuncExpr(expr): 664 res = parse_func_expr(parse_sexp(expr)) 665 return res 666 667def parseLetBodyExpr(expr): 668 res = parse_func_expr(parse_sexp(expr)) 669 return res 670 671def makeVulkanTypeFromXMLTag(typeInfo, parentName: str, tag: Element) -> VulkanType: 672 res = VulkanType() 673 674 # Process the length expression 675 676 if tag.attrib.get("len") is not None: 677 lengths = tag.attrib.get("len").split(",") 678 res.lenExpr = lengths[0] 679 680 # Calculate static array expression 681 682 nametag = tag.find("name") 683 enumtag = tag.find("enum") 684 685 if enumtag is not None: 686 res.staticArrExpr = enumtag.text 687 elif nametag is not None: 688 res.rawStaticArrExpr = noneStr(nametag.tail) 689 690 dimensions = res.rawStaticArrExpr.count('[') 691 if dimensions == 1: 692 res.staticArrExpr = res.rawStaticArrExpr[1:-1] 693 elif dimensions > 1: 694 arraySizes = res.rawStaticArrExpr[1:-1].split('][') 695 res.staticArrExpr = '(' + \ 696 '*'.join(f'({size})' for size in arraySizes) + ')' 697 698 # Determine const 699 700 beforeTypePart = noneStr(tag.text) 701 702 if "const" in beforeTypePart: 703 res.isConst = True 704 705 # Calculate type and pointer info 706 for elem in tag: 707 if elem.tag == "name": 708 res.paramName = elem.text 709 if elem.tag == "type": 710 duringTypePart = noneStr(elem.text) 711 afterTypePart = noneStr(elem.tail) 712 # Now we know enough to fill some stuff in 713 res.typeName = duringTypePart 714 715 if res.typeName in TRANSFORMED_TYPES: 716 res.isTransformed = True 717 718 # This only handles pointerIndirectionLevels == 2 719 # along with optional constant pointer for the inner part. 720 for c in afterTypePart: 721 if c == "*": 722 res.pointerIndirectionLevels += 1 723 if "const" in afterTypePart and res.pointerIndirectionLevels == 2: 724 res.isPointerToConstPointer = True 725 726 # If void*, treat like it's not a pointer 727 # if duringTypePart == "void": 728 # res.pointerIndirectionLevels -= 1 729 730 # Calculate optionality (based on validitygenerator.py) 731 if tag.attrib.get("optional") is not None: 732 res.isOptional = True 733 res.optionalStr = tag.attrib.get("optional") 734 735 # If no validity is being generated, it usually means that 736 # validity is complex and not absolute, so let's say yes. 737 if tag.attrib.get("noautovalidity") is not None: 738 res.isOptional = True 739 740 # If this is a structure extension, it is optional. 741 if tag.attrib.get("structextends") is not None: 742 res.isOptional = True 743 744 # If this is a pNext pointer, it is optional. 745 if res.paramName == "pNext": 746 res.isOptional = True 747 748 res.primitiveEncodingSize = typeInfo.getPrimitiveEncodingSize(res.typeName) 749 750 # Annotations: Environment binds 751 if tag.attrib.get("binds") is not None: 752 bindPairs = map(lambda x: x.strip(), tag.attrib.get("binds").split(",")) 753 bindPairsSplit = map(lambda p: p.split(":"), bindPairs) 754 res.binds = dict(map(lambda sp: (sp[0].strip(), sp[1].strip()), bindPairsSplit)) 755 756 # Annotations: Filters 757 structMemberName = f"{parentName}.{res.paramName}" 758 if structMemberName in STRUCT_MEMBER_FILTER_VAR.keys(): 759 res.filterVar = STRUCT_MEMBER_FILTER_VAR[structMemberName] 760 761 if structMemberName in STRUCT_MEMBER_FILTER_VALS.keys(): 762 res.filterVals = STRUCT_MEMBER_FILTER_VALS[structMemberName] 763 764 if structMemberName in STRUCT_MEMBER_FILTER_FUNC.keys(): 765 res.filterFunc = parseFilterFuncExpr(STRUCT_MEMBER_FILTER_FUNC[structMemberName]) 766 767 if tag.attrib.get("filterOtherwise") is not None: 768 res.Otherwise = tag.attrib.get("filterOtherwise") 769 770 # store all other attribs here 771 res.attribs = dict(tag.attrib) 772 773 return res 774 775 776def makeVulkanTypeSimple(isConst, 777 typeName, 778 ptrIndirectionLevels, 779 paramName=None): 780 res = VulkanType() 781 782 res.typeName = typeName 783 res.isConst = isConst 784 res.pointerIndirectionLevels = ptrIndirectionLevels 785 res.isPointerToConstPointer = False 786 res.paramName = paramName 787 res.primitiveEncodingSize = None 788 789 return res 790 791 792# Classes for describing aggregate types (unions, structs) and API calls. 793class VulkanCompoundType(object): 794 795 def __init__(self, name: str, members: List[VulkanType], isUnion=False, structEnumExpr=None, structExtendsExpr=None, feature=None, initialEnv={}, optional=None): 796 self.name: str = name 797 self.typeName: str = name 798 self.members: List[VulkanType] = members 799 self.environment = initialEnv 800 self.isUnion = isUnion 801 self.structEnumExpr = structEnumExpr 802 self.structExtendsExpr = structExtendsExpr 803 self.feature = feature 804 if name in DEVICE_MEMORY_STRUCTS: 805 self.deviceMemoryInfoParameterIndices = DEVICE_MEMORY_STRUCTS[name] 806 else: 807 self.deviceMemoryInfoParameterIndices = None 808 self.isTransformed = name in TRANSFORMED_TYPES 809 self.copy = None 810 self.optionalStr = optional 811 812 def initCopies(self): 813 self.copy = self 814 815 for m in self.members: 816 m.parent = self.copy 817 818 def getMember(self, memberName) -> Optional[VulkanType]: 819 for m in self.members: 820 if m.paramName == memberName: 821 return m 822 return None 823 824 def getStructEnumExpr(self,): 825 return self.structEnumExpr 826 827 def getProtectStreamFeature(self) -> Optional[str]: 828 if not self.name in STRUCT_STREAM_FEATURE.keys(): 829 return None 830 return STRUCT_STREAM_FEATURE[self.name] 831 832 833class VulkanAPI(object): 834 835 def __init__(self, name: str, retType: VulkanType, parameters, origName=None): 836 self.name: str = name 837 self.origName = name 838 self.retType: VulkanType = retType 839 self.parameters: List[VulkanType] = list(filter(lambda param: not param.shouldSkip(), parameters)) 840 841 if name in DEVICE_MEMORY_COMMANDS.keys(): 842 self.deviceMemoryInfoParameterIndices = DEVICE_MEMORY_COMMANDS[name] 843 else: 844 self.deviceMemoryInfoParameterIndices = None 845 846 self.copy = None 847 848 self.isTransformed = name in TRANSFORMED_TYPES 849 850 if origName: 851 self.origName = origName 852 853 def initCopies(self): 854 self.copy = self 855 856 for m in self.parameters: 857 m.parent = self.copy 858 859 def getCopy(self,): 860 return copy(self) 861 862 def getParameter(self, parameterName): 863 for p in self.parameters: 864 if p.paramName == parameterName: 865 return p 866 return None 867 868 def withModifiedName(self, newName): 869 res = VulkanAPI(newName, self.retType, self.parameters) 870 return res 871 872 def getRetVarExpr(self): 873 if self.retType.typeName == "void": 874 return None 875 return "%s_%s_return" % (self.name, self.retType.typeName) 876 877 def getRetTypeExpr(self): 878 return self.retType.typeName 879 880 def withCustomParameters(self, customParams): 881 res = self.getCopy() 882 res.parameters = customParams 883 return res 884 885 def withCustomReturnType(self, retType): 886 res = self.getCopy() 887 res.retType = retType 888 return res 889 890# Whether or not special handling of virtual elements 891# such as VkDeviceMemory is needed. 892def vulkanTypeNeedsTransform(structOrApi): 893 return structOrApi.deviceMemoryInfoParameterIndices != None 894 895def vulkanTypeGetNeededTransformTypes(structOrApi): 896 res = [] 897 if structOrApi.deviceMemoryInfoParameterIndices != None: 898 res.append("devicememory") 899 return res 900 901def vulkanTypeforEachSubType(structOrApi, f): 902 toLoop = None 903 if type(structOrApi) == VulkanCompoundType: 904 toLoop = structOrApi.members 905 if type(structOrApi) == VulkanAPI: 906 toLoop = structOrApi.parameters 907 908 for (i, x) in enumerate(toLoop): 909 f(i, x) 910 911# Parses everything about Vulkan types into a Python readable format. 912class VulkanTypeInfo(object): 913 914 def __init__(self, generator): 915 self.generator = generator 916 self.categories: Set[str] = set([]) 917 918 # Tracks what Vulkan type is part of what category. 919 self.typeCategories: Dict[str, str] = {} 920 921 # Tracks the primitive encoding size for each type, if applicable. 922 self.encodingSizes: Dict[str, Optional[int]] = {} 923 924 self.structs: Dict[str, VulkanCompoundType] = {} 925 self.apis: Dict[str, VulkanAPI] = {} 926 927 # Maps bitmask types to the enum type used for the flags 928 # E.g. "VkImageAspectFlags" -> "VkImageAspectFlagBits" 929 self.bitmasks: Dict[str, str] = {} 930 931 # Maps all enum names to their values. 932 # For aliases, the value is the name of the canonical enum 933 self.enumValues: Dict[str, Union[int, str]] = {} 934 935 # Maps enum to their xml element 936 self.enumElem = {} 937 938 self.feature = None 939 940 def initType(self, name: str, category: str): 941 self.categories.add(category) 942 self.typeCategories[name] = category 943 self.encodingSizes[name] = self.setPrimitiveEncodingSize(name) 944 945 def categoryOf(self, name): 946 return self.typeCategories[name] 947 948 def getPrimitiveEncodingSize(self, name): 949 return self.encodingSizes[name] 950 951 # Queries relating to categories of Vulkan types. 952 def isHandleType(self, name): 953 return self.typeCategories.get(name) == "handle" 954 955 def isCompoundType(self, name: str): 956 return self.typeCategories.get(name) in ["struct", "union"] 957 958 # Gets the best size in bytes 959 # for encoding/decoding a particular Vulkan type. 960 # If not applicable, returns None. 961 def setPrimitiveEncodingSize(self, name: str) -> Optional[int]: 962 baseEncodingSizes = { 963 "void": 8, 964 "char": 1, 965 "float": 4, 966 "uint8_t": 1, 967 "uint16_t": 2, 968 "uint32_t": 4, 969 "uint64_t": 8, 970 "int": 4, 971 "int8_t": 1, 972 "int16_t": 2, 973 "int32_t": 4, 974 "int64_t": 8, 975 "size_t": 8, 976 "ssize_t": 8, 977 "VkBool32": 4, 978 "zx_handle_t": 4, 979 } 980 981 if name in baseEncodingSizes: 982 return baseEncodingSizes[name] 983 984 category = self.typeCategories[name] 985 986 if category in [None, "api", "include", "define", "struct", "union"]: 987 return None 988 989 # Handles are pointers so they must be 8 bytes. Basetype includes VkDeviceSize which is 8 bytes. 990 if category in ["handle", "basetype", "funcpointer"]: 991 return 8 992 993 if category in ["enum", "bitmask"]: 994 return 4 995 996 def isNonAbiPortableType(self, typeName): 997 if typeName in EXPLICITLY_ABI_PORTABLE_TYPES: 998 return False 999 1000 if typeName in EXPLICITLY_ABI_NON_PORTABLE_TYPES: 1001 return True 1002 1003 category = self.typeCategories[typeName] 1004 return category in NON_ABI_PORTABLE_TYPE_CATEGORIES 1005 1006 def onBeginFeature(self, featureName, featureType): 1007 self.feature = featureName 1008 1009 def onEndFeature(self): 1010 self.feature = None 1011 1012 def onGenType(self, typeinfo, name, alias): 1013 category = typeinfo.elem.get("category") 1014 self.initType(name, category) 1015 1016 if category in ["struct", "union"]: 1017 self.onGenStruct(typeinfo, name, alias) 1018 1019 if category == "bitmask": 1020 self.bitmasks[name] = typeinfo.elem.get("requires") 1021 1022 def onGenStruct(self, typeinfo, typeName, alias): 1023 if not alias: 1024 members: List[VulkanType] = [] 1025 1026 structExtendsExpr = typeinfo.elem.get("structextends") 1027 1028 structEnumExpr = None 1029 1030 initialEnv = {} 1031 envStr = typeinfo.elem.get("exists") 1032 if envStr != None: 1033 comma_separated = envStr.split(",") 1034 name_type_pairs = map(lambda cs: tuple(map(lambda t: t.strip(), cs.split(":"))), comma_separated) 1035 for (name, typ) in name_type_pairs: 1036 initialEnv[name] = { 1037 "type" : typ, 1038 "binding" : None, 1039 "structmember" : False, 1040 "body" : None, 1041 } 1042 1043 if typeName in STRUCT_ENV_STR.keys(): 1044 name_body_pairs = STRUCT_ENV_STR[typeName] 1045 for (name, body) in name_body_pairs.items(): 1046 initialEnv[name] = { 1047 "type" : "uint32_t", 1048 "binding" : name, 1049 "structmember" : False, 1050 "body" : parseLetBodyExpr(body) 1051 } 1052 1053 for member in typeinfo.elem.findall(".//member"): 1054 if "api" in member.attrib.keys() and not "vulkan" == member.attrib["api"]: 1055 continue 1056 vulkanType = makeVulkanTypeFromXMLTag(self, typeName, member) 1057 initialEnv[vulkanType.paramName] = { 1058 "type": vulkanType.typeName, 1059 "binding": vulkanType.paramName, 1060 "structmember": True, 1061 "body": None, 1062 } 1063 members.append(vulkanType) 1064 if vulkanType.typeName == "VkStructureType" and \ 1065 member.get("values"): 1066 structEnumExpr = member.get("values") 1067 1068 self.structs[typeName] = \ 1069 VulkanCompoundType( 1070 typeName, 1071 members, 1072 isUnion = self.categoryOf(typeName) == "union", 1073 structEnumExpr = structEnumExpr, 1074 structExtendsExpr = structExtendsExpr, 1075 feature = self.feature, 1076 initialEnv = initialEnv, 1077 optional = typeinfo.elem.get("optional", None)) 1078 self.structs[typeName].initCopies() 1079 1080 def onGenGroup(self, groupinfo, groupName, _alias=None): 1081 self.initType(groupName, "enum") 1082 enums = groupinfo.elem.findall("enum") 1083 for enum in enums: 1084 intVal, strVal = self.generator.enumToValue(enum, True) 1085 self.enumValues[enum.get('name')] = intVal if intVal is not None else strVal 1086 self.enumElem[enum.get('name')] = enum 1087 1088 1089 def onGenEnum(self, enuminfo, name: str, alias): 1090 self.initType(name, "enum") 1091 value: str = enuminfo.elem.get("value") 1092 self.enumElem[name] = enuminfo.elem 1093 if value and value.isdigit(): 1094 self.enumValues[name] = int(value) 1095 elif value and value[0] == '"' and value[-1] == '"': 1096 self.enumValues[name] = value[1:-1] 1097 elif alias is not None: 1098 self.enumValues[name] = alias 1099 else: 1100 # There's about a dozen cases of using the bitwise NOT operator (e.g.: `(~0U)`, `(~0ULL)`) 1101 # to concisely represent large values. Just ignore them for now. 1102 # In the future, we can add a lookup table to convert these to int 1103 return 1104 1105 def onGenCmd(self, cmdinfo, name, _alias): 1106 self.initType(name, "api") 1107 1108 proto = cmdinfo.elem.find("proto") 1109 params = cmdinfo.elem.findall("param") 1110 1111 self.apis[name] = \ 1112 VulkanAPI( 1113 name, 1114 makeVulkanTypeFromXMLTag(self, name, proto), 1115 list(map(lambda p: makeVulkanTypeFromXMLTag(self, name, p), 1116 params))) 1117 self.apis[name].initCopies() 1118 1119 def onEnd(self): 1120 pass 1121 1122def hasNullOptionalStringFeature(forEachType): 1123 return (hasattr(forEachType, "onCheckWithNullOptionalStringFeature")) and \ 1124 (hasattr(forEachType, "endCheckWithNullOptionalStringFeature")) and \ 1125 (hasattr(forEachType, "finalCheckWithNullOptionalStringFeature")) 1126 1127 1128# General function to iterate over a vulkan type and call code that processes 1129# each of its sub-components, if any. 1130def iterateVulkanType(typeInfo: VulkanTypeInfo, vulkanType: VulkanType, forEachType): 1131 if not vulkanType.isArrayOfStrings(): 1132 if vulkanType.isPointerToConstPointer: 1133 return False 1134 1135 if vulkanType.shouldSkip(): 1136 return False 1137 1138 forEachType.registerTypeInfo(typeInfo) 1139 1140 needCheck = vulkanType.isOptionalPointer() 1141 1142 if typeInfo.isCompoundType(vulkanType.typeName) and not vulkanType.isNextPointer(): 1143 1144 if needCheck: 1145 forEachType.onCheck(vulkanType) 1146 1147 forEachType.onCompoundType(vulkanType) 1148 1149 if needCheck: 1150 forEachType.endCheck(vulkanType) 1151 1152 else: 1153 if vulkanType.isString(): 1154 if needCheck and hasNullOptionalStringFeature(forEachType): 1155 forEachType.onCheckWithNullOptionalStringFeature(vulkanType) 1156 forEachType.onString(vulkanType) 1157 forEachType.endCheckWithNullOptionalStringFeature(vulkanType) 1158 forEachType.onString(vulkanType) 1159 forEachType.finalCheckWithNullOptionalStringFeature(vulkanType) 1160 elif needCheck: 1161 forEachType.onCheck(vulkanType) 1162 forEachType.onString(vulkanType) 1163 forEachType.endCheck(vulkanType) 1164 else: 1165 forEachType.onString(vulkanType) 1166 1167 elif vulkanType.isArrayOfStrings(): 1168 forEachType.onStringArray(vulkanType) 1169 1170 elif vulkanType.staticArrExpr: 1171 forEachType.onStaticArr(vulkanType) 1172 1173 elif vulkanType.isNextPointer(): 1174 if needCheck: 1175 forEachType.onCheck(vulkanType) 1176 forEachType.onStructExtension(vulkanType) 1177 if needCheck: 1178 forEachType.endCheck(vulkanType) 1179 1180 elif vulkanType.pointerIndirectionLevels > 0: 1181 if needCheck: 1182 forEachType.onCheck(vulkanType) 1183 forEachType.onPointer(vulkanType) 1184 if needCheck: 1185 forEachType.endCheck(vulkanType) 1186 1187 else: 1188 forEachType.onValue(vulkanType) 1189 1190 return True 1191 1192class VulkanTypeIterator(object): 1193 def __init__(self,): 1194 self.typeInfo = None 1195 1196 def registerTypeInfo(self, typeInfo): 1197 self.typeInfo = typeInfo 1198 1199def vulkanTypeGetStructFieldLengthInfo(structInfo, vulkanType): 1200 def getSpecialCaseVulkanStructFieldLength(structInfo, vulkanType): 1201 cases = [ 1202 { 1203 "structName": "VkShaderModuleCreateInfo", 1204 "field": "pCode", 1205 "lenExpr": "codeSize", 1206 "postprocess": lambda expr: "(%s / 4)" % expr 1207 }, 1208 { 1209 "structName": "VkPipelineMultisampleStateCreateInfo", 1210 "field": "pSampleMask", 1211 "lenExpr": "rasterizationSamples", 1212 "postprocess": lambda expr: "(((%s) + 31) / 32)" % expr 1213 }, 1214 ] 1215 1216 for c in cases: 1217 if (structInfo.name, vulkanType.paramName) == (c["structName"], c["field"]): 1218 return c 1219 1220 return None 1221 1222 specialCaseAccess = getSpecialCaseVulkanStructFieldLength(structInfo, vulkanType) 1223 1224 if specialCaseAccess is not None: 1225 return specialCaseAccess 1226 1227 lenExpr = vulkanType.getLengthExpression() 1228 1229 if lenExpr is None: 1230 return None 1231 1232 return { 1233 "structName": structInfo.name, 1234 "field": vulkanType.typeName, 1235 "lenExpr": lenExpr, 1236 "postprocess": lambda expr: expr} 1237 1238 1239class VulkanTypeProtobufInfo(object): 1240 def __init__(self, typeInfo, structInfo, vulkanType): 1241 self.needsMessage = typeInfo.isCompoundType(vulkanType.typeName) 1242 self.isRepeatedString = vulkanType.isArrayOfStrings() 1243 self.isString = vulkanType.isString() or ( 1244 vulkanType.typeName == "char" and (vulkanType.staticArrExpr != "")) 1245 1246 if structInfo is not None: 1247 self.lengthInfo = vulkanTypeGetStructFieldLengthInfo( 1248 structInfo, vulkanType) 1249 else: 1250 self.lengthInfo = vulkanType.getLengthExpression() 1251 1252 self.protobufType = None 1253 self.origTypeCategory = typeInfo.categoryOf(vulkanType.typeName) 1254 1255 self.isExtensionStruct = \ 1256 vulkanType.typeName == "void" and \ 1257 vulkanType.pointerIndirectionLevels > 0 and \ 1258 vulkanType.paramName == "pNext" 1259 1260 if self.needsMessage: 1261 return 1262 1263 if typeInfo.categoryOf(vulkanType.typeName) in ["enum", "bitmask"]: 1264 self.protobufType = "uint32" 1265 1266 if typeInfo.categoryOf(vulkanType.typeName) in ["funcpointer", "handle", "define"]: 1267 self.protobufType = "uint64" 1268 1269 if typeInfo.categoryOf(vulkanType.typeName) in ["basetype"]: 1270 baseTypeMapping = { 1271 "VkFlags" : "uint32", 1272 "VkBool32" : "uint32", 1273 "VkDeviceSize" : "uint64", 1274 "VkSampleMask" : "uint32", 1275 } 1276 self.protobufType = baseTypeMapping[vulkanType.typeName] 1277 1278 if typeInfo.categoryOf(vulkanType.typeName) == None: 1279 1280 otherTypeMapping = { 1281 "void" : "uint64", 1282 "char" : "uint8", 1283 "size_t" : "uint64", 1284 "float" : "float", 1285 "uint8_t" : "uint32", 1286 "uint16_t" : "uint32", 1287 "int32_t" : "int32", 1288 "uint32_t" : "uint32", 1289 "uint64_t" : "uint64", 1290 "VkDeviceSize" : "uint64", 1291 "VkSampleMask" : "uint32", 1292 } 1293 1294 if vulkanType.typeName in otherTypeMapping: 1295 self.protobufType = otherTypeMapping[vulkanType.typeName] 1296 else: 1297 self.protobufType = "uint64" 1298 1299 1300 protobufCTypeMapping = { 1301 "uint8" : "uint8_t", 1302 "uint32" : "uint32_t", 1303 "int32" : "int32_t", 1304 "uint64" : "uint64_t", 1305 "float" : "float", 1306 "string" : "const char*", 1307 } 1308 1309 self.protobufCType = protobufCTypeMapping[self.protobufType] 1310 1311