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