• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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