xref: /aosp_15_r20/external/mesa3d/src/gfxstream/codegen/scripts/cereal/common/vulkantypes.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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