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