Merge vk-gl-cts/vulkan-cts-1.2.7 into vk-gl-cts/vulkan-cts-1.2.8
[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 from itertools import chain
30 from collections import OrderedDict
31
32 sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts"))
33
34 from build.common import DEQP_DIR, execute
35 from khr_util.format import indentLines, writeInlFile
36
37 VULKAN_HEADERS_INCLUDE_DIR      = os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "include")
38 VULKAN_SRC_DIR                          = os.path.join(os.path.dirname(__file__), "src")
39
40 INL_HEADER = """\
41 /* WARNING: This is auto-generated file. Do not modify, since changes will
42  * be lost! Modify the generating script instead.
43  * This file was generated by /scripts/gen_framework.py
44  */\
45 """
46
47 DEFINITIONS                     = [
48         ("VK_MAX_PHYSICAL_DEVICE_NAME_SIZE",    "size_t"),
49         ("VK_MAX_EXTENSION_NAME_SIZE",                  "size_t"),
50         ("VK_MAX_DRIVER_NAME_SIZE",                             "size_t"),
51         ("VK_MAX_DRIVER_INFO_SIZE",                             "size_t"),
52         ("VK_UUID_SIZE",                                                "size_t"),
53         ("VK_LUID_SIZE",                                                "size_t"),
54         ("VK_MAX_MEMORY_TYPES",                                 "size_t"),
55         ("VK_MAX_MEMORY_HEAPS",                                 "size_t"),
56         ("VK_MAX_DESCRIPTION_SIZE",                             "size_t"),
57         ("VK_MAX_DEVICE_GROUP_SIZE",                    "size_t"),
58         ("VK_ATTACHMENT_UNUSED",                                "uint32_t"),
59         ("VK_SUBPASS_EXTERNAL",                                 "uint32_t"),
60         ("VK_QUEUE_FAMILY_IGNORED",                             "uint32_t"),
61         ("VK_QUEUE_FAMILY_EXTERNAL",                    "uint32_t"),
62         ("VK_REMAINING_MIP_LEVELS",                             "uint32_t"),
63         ("VK_REMAINING_ARRAY_LAYERS",                   "uint32_t"),
64         ("VK_WHOLE_SIZE",                                               "vk::VkDeviceSize"),
65         ("VK_TRUE",                                                             "vk::VkBool32"),
66         ("VK_FALSE",                                                    "vk::VkBool32"),
67 ]
68
69 PLATFORM_TYPES          = [
70         # VK_KHR_xlib_surface
71         (["Display","*"],                                               ["XlibDisplayPtr"],                             "void*"),
72         (["Window"],                                                    ["XlibWindow"],                                 "uintptr_t",),
73         (["VisualID"],                                                  ["XlibVisualID"],                               "uint32_t"),
74
75         # VK_KHR_xcb_surface
76         (["xcb_connection_t", "*"],                             ["XcbConnectionPtr"],                   "void*"),
77         (["xcb_window_t"],                                              ["XcbWindow"],                                  "uintptr_t"),
78         (["xcb_visualid_t"],                                    ["XcbVisualid"],                                "uint32_t"),
79
80         # VK_KHR_wayland_surface
81         (["struct", "wl_display","*"],                  ["WaylandDisplayPtr"],                  "void*"),
82         (["struct", "wl_surface", "*"],                 ["WaylandSurfacePtr"],                  "void*"),
83
84         # VK_KHR_mir_surface
85         (["MirConnection", "*"],                                ["MirConnectionPtr"],                   "void*"),
86         (["MirSurface", "*"],                                   ["MirSurfacePtr"],                              "void*"),
87
88         # VK_KHR_android_surface
89         (["ANativeWindow", "*"],                                ["AndroidNativeWindowPtr"],             "void*"),
90
91         # VK_KHR_win32_surface
92         (["HINSTANCE"],                                                 ["Win32InstanceHandle"],                "void*"),
93         (["HWND"],                                                              ["Win32WindowHandle"],                  "void*"),
94         (["HANDLE"],                                                    ["Win32Handle"],                                "void*"),
95         (["const", "SECURITY_ATTRIBUTES", "*"], ["Win32SecurityAttributesPtr"], "const void*"),
96         (["AHardwareBuffer", "*"],                              ["AndroidHardwareBufferPtr"],   "void*"),
97         (["HMONITOR"],                                                  ["Win32MonitorHandle"],                 "void*"),
98         (["LPCWSTR"],                                                   ["Win32LPCWSTR"],                               "const void*"),
99
100         # VK_EXT_acquire_xlib_display
101         (["RROutput"],                                                  ["RROutput"],                                   "void*"),
102
103         (["zx_handle_t"],                                               ["zx_handle_t"],                                "uint32_t"),
104         (["GgpFrameToken"],                                             ["GgpFrameToken"],                              "int32_t"),
105         (["GgpStreamDescriptor"],                               ["GgpStreamDescriptor"],                "int32_t"),
106         (["CAMetalLayer"],                                              ["CAMetalLayer"],                               "void*"),
107 ]
108
109 PLATFORM_TYPE_NAMESPACE = "pt"
110
111 TYPE_SUBSTITUTIONS              = [
112         # Platform-specific
113         ("DWORD",               "uint32_t"),
114         ("HANDLE*",             PLATFORM_TYPE_NAMESPACE + "::" + "Win32Handle*"),
115 ]
116
117 EXTENSION_POSTFIXES                             = ["KHR", "EXT", "NV", "NVX", "KHX", "NN", "MVK", "FUCHSIA", "GGP", "AMD", "QNX"]
118 EXTENSION_POSTFIXES_STANDARD    = ["KHR", "EXT"]
119
120 def prefixName (prefix, name):
121         name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name[2:])
122         name = re.sub(r'([a-zA-Z])([0-9])', r'\1_\2', name)
123         name = name.upper()
124
125         name = name.replace("YCB_CR_", "YCBCR_")
126         name = name.replace("WIN_32_", "WIN32_")
127         name = name.replace("8_BIT_", "8BIT_")
128         name = name.replace("16_BIT_", "16BIT_")
129         name = name.replace("INT_64_", "INT64_")
130         name = name.replace("D_3_D_12_", "D3D12_")
131         name = name.replace("IOSSURFACE_", "IOS_SURFACE_")
132         name = name.replace("MAC_OS", "MACOS_")
133         name = name.replace("TEXTURE_LOD", "TEXTURE_LOD_")
134         name = name.replace("VIEWPORT_W", "VIEWPORT_W_")
135         name = name.replace("_IDPROPERTIES", "_ID_PROPERTIES")
136         name = name.replace("PHYSICAL_DEVICE_SHADER_FLOAT_16_INT_8_FEATURES", "PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES")
137         name = name.replace("PHYSICAL_DEVICE_RGBA_10_X_6_FORMATS_FEATURES_EXT", "PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT")
138         name = name.replace("_PCIBUS_", "_PCI_BUS_")
139         name = name.replace("ASTCD", "ASTC_D")
140         name = name.replace("AABBNV", "AABB_NV")
141         name = name.replace("IMAGE_PIPE", "IMAGEPIPE")
142         name = name.replace("SMBUILTINS", "SM_BUILTINS")
143         name = name.replace("ASTCHDRFEATURES", "ASTC_HDR_FEATURES")
144         name = name.replace("UINT_8", "UINT8")
145         name = name.replace("VULKAN_11_FEATURES", "VULKAN_1_1_FEATURES")
146         name = name.replace("VULKAN_11_PROPERTIES", "VULKAN_1_1_PROPERTIES")
147         name = name.replace("VULKAN_12_FEATURES", "VULKAN_1_2_FEATURES")
148         name = name.replace("VULKAN_12_PROPERTIES", "VULKAN_1_2_PROPERTIES")
149         name = name.replace("INT_8_", "INT8_")
150         name = name.replace("AABBNV", "AABB_NV")
151         name = name.replace("_H_264_", "_H264_")
152         name = name.replace("_H_265_", "_H265_")
153         name = name.replace("RDMAFEATURES", "RDMA_FEATURES")
154         name = name.replace("RGBA_10_X_6", "RGBA10X6")
155
156
157         return prefix + name
158
159 class Version:
160         def __init__ (self, versionTuple):
161                 self.major = versionTuple[0]
162                 self.minor = versionTuple[1]
163                 self.patch = versionTuple[2]
164
165         def getInHex (self):
166                 if self.patch == 0:
167                         return "VK_API_VERSION_%d_%d" % (self.major, self.minor)
168                 return '0x%Xu' % (hash(self))
169
170         def isStandardVersion (self):
171                 if self.patch != 0:
172                         return False
173                 if self.major != 1:
174                         return False
175                 return True
176
177         def getBestRepresentation (self):
178                 if self.isStandardVersion():
179                         return self.getInHex()
180                 return self.getDefineName()
181
182         def getDefineName (self):
183                 return 'VERSION_%d_%d_%d' % (self.major, self.minor, self.patch)
184
185         def __hash__ (self):
186                 return (self.major << 22) | (self.minor << 12) | self.patch
187
188         def __eq__ (self, other):
189                 return self.major == other.major and self.minor == other.minor and self.patch == other.patch
190
191         def __str__ (self):
192                 return self.getBestRepresentation()
193
194
195 class Handle:
196         TYPE_DISP               = 0
197         TYPE_NONDISP    = 1
198
199         def __init__ (self, type, name):
200                 self.type               = type
201                 self.name               = name
202                 self.alias              = None
203                 self.isAlias    = False
204
205         def getHandleType (self):
206                 return prefixName("HANDLE_TYPE_", self.name)
207
208         def checkAliasValidity (self):
209                 pass
210
211         def __repr__ (self):
212                 return '%s (%s, %s)' % (self.name, self.alias, self.isAlias)
213
214 class Definition:
215         def __init__ (self, type, name, value):
216                 self.type       = type
217                 self.name       = name
218                 self.value      = value
219                 self.alias      = None
220                 self.isAlias    = False
221
222         def __repr__ (self):
223                 return '%s = %s (%s)' % (self.name, self.value, self.type)
224
225 class Enum:
226         def __init__ (self, name, values):
227                 self.name               = name
228                 self.values             = values
229                 self.alias              = None
230                 self.isAlias    = False
231
232         def checkAliasValidity (self):
233                 if self.alias != None:
234                         if len(self.values) != len(self.alias.values):
235                                 raise Exception("%s has different number of flags than its alias %s." % (self.name, self.alias.name))
236                         for index, value in enumerate(self.values):
237                                 aliasVal = self.alias.values[index]
238                                 if value[1] != aliasVal[1] or not (value[0].startswith(aliasVal[0]) or aliasVal[0].startswith(value[0])):
239                                         raise Exception("Flag %s of %s has different value than %s of %s." % (self.alias.values[index], self.alias.name, value, self.name))
240
241         def __repr__ (self):
242                 return '%s (%s) %s' % (self.name, self.alias, self.values)
243
244 class Bitfield:
245         def __init__ (self, name, values):
246                 self.name               = name
247                 self.values             = values
248                 self.alias              = None
249                 self.isAlias    = False
250
251         def checkAliasValidity (self):
252                 if self.alias != None:
253                         if len(self.values) != len(self.alias.values):
254                                 raise Exception("%s has different number of flags than its alias %s." % (self.name, self.alias.name))
255                         for index, value in enumerate(self.values):
256                                 aliasVal = self.alias.values[index]
257                                 if value[1] != aliasVal[1] or not (value[0].startswith(aliasVal[0]) or aliasVal[0].startswith(value[0])):
258                                         raise Exception("Flag %s of %s has different value than %s of %s." % (self.alias.values[index], self.alias.name, value, self.name))
259
260         def __repr__ (self):
261                 return '%s (%s)' % (self.name, self.alias)
262
263 class Variable:
264         def __init__ (self, type, name, arraySizeOrFieldWidth):
265                 type            = type.replace('*',' *').replace('&',' &')
266                 for src, dst in TYPE_SUBSTITUTIONS:
267                         type = type.replace(src, dst)
268                 self.type       = type.split(' ')
269                 for platformType, substitute, compat in PLATFORM_TYPES:
270                         range = self.contains(self.type, platformType)
271                         if range != None:
272                                 self.type = self.type[:range[0]]+[PLATFORM_TYPE_NAMESPACE + '::' + substitute[0]] + substitute[1:] + self.type[range[1]:]
273                                 break
274                 self.name               = name
275                 if len(arraySizeOrFieldWidth) > 0 and arraySizeOrFieldWidth[0] == ':':
276                         self.arraySize  = ''
277                         self.fieldWidth = arraySizeOrFieldWidth
278                 else:
279                         self.arraySize  = arraySizeOrFieldWidth
280                         self.fieldWidth = ''
281
282         def contains(self, big, small):
283                 for i in range(len(big)-len(small)+1):
284                         for j in range(len(small)):
285                                 if big[i+j] != small[j]:
286                                         break
287                         else:
288                                 return i, i+len(small)
289                 return None
290
291         def getType (self):
292                 return ' '.join(self.type).replace(' *','*').replace(' &','&')
293
294         def getAsString (self, separator):
295                 return '%s%s%s%s%s' % (self.getType(), separator, self.name, self.arraySize, self.fieldWidth)
296
297         def getAsStringForArgumentList (self, separator):
298                 return '%s%s%s%s' % (self.getType(), separator, self.name, self.arraySize)
299
300         def __repr__ (self):
301                 return '<%s> <%s> <%s>' % (self.type, self.name, self.arraySize)
302
303         def __eq__ (self, other):
304                 if len(self.type) != len(other.type):
305                         return False
306                 for index, type in enumerate(self.type):
307                         if "*" == type or "&" == type or "const" == type or "volatile" == type:
308                                 if type != other.type[index]:
309                                         return False
310                         elif type != other.type[index] and \
311                                 type not in map(lambda ext: other.type[index] + ext, EXTENSION_POSTFIXES_STANDARD) and \
312                                 other.type[index] not in map(lambda ext: type + ext, EXTENSION_POSTFIXES_STANDARD):
313                                 return False
314                 return self.arraySize == other.arraySize
315
316         def __ne__ (self, other):
317                 return not self == other
318
319 class CompositeType:
320         CLASS_STRUCT    = 0
321         CLASS_UNION             = 1
322
323         def __init__ (self, typeClass, name, members, apiVersion = None):
324                 self.typeClass  = typeClass
325                 self.name               = name
326                 self.members    = members
327                 self.alias              = None
328                 self.isAlias    = False
329                 self.apiVersion = apiVersion
330
331         def getClassName (self):
332                 names = {CompositeType.CLASS_STRUCT: 'struct', CompositeType.CLASS_UNION: 'union'}
333                 return names[self.typeClass]
334
335         def checkAliasValidity (self):
336                 if self.alias != None:
337                         if len(self.members) != len(self.alias.members):
338                                 raise Exception("%s has different number of members than its alias %s." % (self.name, self.alias.name))
339                         for index, member in enumerate(self.members ):
340                                 break
341                                 #if member != self.alias.members[index]:
342                                         #raise Exception("Member %s of %s is different than core member %s in %s." % (self.alias.members[index], self.alias.name, member, self.name))
343                                         #raise Exception("Member ",str(self.alias.members[index])," of ", str(self.alias.name)," is different than core member ", str(member)," in ", str(self.name),".")
344         def __repr__ (self):
345                 return '%s (%s)' % (self.name, self.alias)
346
347 class Function:
348         TYPE_PLATFORM           = 0 # Not bound to anything
349         TYPE_INSTANCE           = 1 # Bound to VkInstance
350         TYPE_DEVICE                     = 2 # Bound to VkDevice
351
352         def __init__ (self, name, returnType, arguments, apiVersion = None):
353                 self.name               = name
354                 self.returnType = returnType
355                 self.arguments  = arguments
356                 self.alias              = None
357                 self.isAlias    = False
358                 self.apiVersion = apiVersion
359
360         def getType (self):
361                 # Special functions
362                 if self.name == "vkGetInstanceProcAddr":
363                         return Function.TYPE_PLATFORM
364                 assert len(self.arguments) > 0
365                 firstArgType = self.arguments[0].getType()
366                 if firstArgType in ["VkInstance", "VkPhysicalDevice"]:
367                         return Function.TYPE_INSTANCE
368                 elif firstArgType in ["VkDevice", "VkCommandBuffer", "VkQueue"]:
369                         return Function.TYPE_DEVICE
370                 else:
371                         return Function.TYPE_PLATFORM
372
373         def checkAliasValidity (self):
374                 if self.alias != None:
375                         if len(self.arguments) != len(self.alias.arguments):
376                                 raise Exception("%s has different number of arguments than its alias %s." % (self.name, self.alias.name))
377                         if self.returnType != self.alias.returnType or not (self.returnType.startswith(self.alias.returnType) or self.alias.returnType.startswith(self.returnType)):
378                                 raise Exception("%s has different return value's type than its alias %s." % (self.name, self.alias.name))
379                         for index, argument in enumerate(self.arguments):
380                                 if argument != self.alias.arguments[index]:
381                                         raise Exception("argument %s: \"%s\" of %s is different than \"%s\" of %s." % (index, self.alias.arguments[index].getAsString(' '), self.alias.name, argument.getAsString(' '), self.name))
382
383         def __repr__ (self):
384                 return '%s (%s)' % (self.name, self.alias)
385
386 class Extension:
387         def __init__ (self, name, handles, enums, bitfields, compositeTypes, functions, definitions, additionalDefinitions, typedefs, versionInCore):
388                 self.name                       = name
389                 self.definitions        = definitions
390                 self.additionalDefs = additionalDefinitions
391                 self.handles            = handles
392                 self.enums                      = enums
393                 self.bitfields          = bitfields
394                 self.compositeTypes     = compositeTypes
395                 self.functions          = functions
396                 self.typedefs           = typedefs
397                 self.versionInCore      = versionInCore
398
399         def __repr__ (self):
400                 return 'EXT:\n%s ->\nENUMS:\n%s\nCOMPOS:\n%s\nFUNCS:\n%s\nBITF:\n%s\nHAND:\n%s\nDEFS:\n%s\n' % (self.name, self.enums, self.compositeTypes, self.functions, self.bitfields, self.handles, self.definitions, self.versionInCore)
401
402 class API:
403         def __init__ (self, versions, definitions, handles, enums, bitfields, bitfields64, compositeTypes, functions, extensions, additionalExtensionData):
404                 self.versions                                   = versions
405                 self.definitions                                = definitions
406                 self.handles                                    = handles
407                 self.enums                                              = enums
408                 self.bitfields                                  = bitfields
409                 self.bitfields64                                = bitfields64
410                 self.compositeTypes                             = compositeTypes
411                 self.functions                                  = functions                                     # \note contains extension functions as well
412                 self.extensions                                 = extensions
413                 self.additionalExtensionData    = additionalExtensionData       # \note contains mandatory features and information about promotion
414
415 def readFile (filename):
416         with open(filename, 'rt') as f:
417                 return f.read()
418
419 IDENT_PTRN      = r'[a-zA-Z_][a-zA-Z0-9_]*'
420 WIDTH_PTRN      = r'[:0-9]*'
421 TYPE_PTRN       = r'[a-zA-Z_][a-zA-Z0-9_ \t*&]*'
422
423 def getInterfaceName (function):
424         assert function.name[:2] == "vk"
425         return function.name[2].lower() + function.name[3:]
426
427 def getFunctionTypeName (function):
428         assert function.name[:2] == "vk"
429         return function.name[2:] + "Func"
430
431 def endsWith (str, postfix):
432         return str[-len(postfix):] == postfix
433
434 def splitNameExtPostfix (name):
435         knownExtPostfixes = EXTENSION_POSTFIXES
436         for postfix in knownExtPostfixes:
437                 if endsWith(name, postfix):
438                         return (name[:-len(postfix)], postfix)
439         return (name, "")
440
441 def getBitEnumNameForBitfield (bitfieldName):
442         bitfieldName, postfix = splitNameExtPostfix(bitfieldName)
443         assert bitfieldName[-1] == "s"
444         return bitfieldName[:-1] + "Bits" + postfix
445
446 def getBitfieldNameForBitEnum (bitEnumName):
447         bitEnumName, postfix = splitNameExtPostfix(bitEnumName)
448         assert bitEnumName[-4:] == "Bits"
449         return bitEnumName[:-4] + "s" + postfix
450
451 def parsePreprocDefinedValue (src, name):
452         value = parsePreprocDefinedValueOptional(src, name)
453         if value is None:
454                 raise Exception("No such definition: %s" % name)
455         return value
456
457 def parsePreprocDefinedValueOptional (src, name):
458         definition = re.search(r'#\s*define\s+' + name + r'\s+([^\n]+)\n', src)
459         if definition is None:
460                 return None
461         value = definition.group(1).strip()
462         if value == "UINT32_MAX":
463                 value = "(~0u)"
464         return value
465
466 def parseEnum (name, src):
467         keyValuePtrn = '(' + IDENT_PTRN + r')\s*=\s*([^\s,\n}]+)\s*[,\n}]'
468         return Enum(name, re.findall(keyValuePtrn, src))
469
470 # \note Parses raw enums, some are mapped to bitfields later
471 def parseEnums (src):
472         matches = re.findall(r'typedef enum(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
473         enums   = []
474         for enumname, contents, typename in matches:
475                 enums.append(parseEnum(typename, contents))
476         return enums
477
478 def parseCompositeType (type, name, src):
479         typeNamePtrn    = r'(' + TYPE_PTRN + r')(\s+' + IDENT_PTRN + r')((\[[^\]]+\]|\s*:\s*[0-9]+)*)\s*;'
480         matches                 = re.findall(typeNamePtrn, src)
481         members                 = [Variable(t.strip(), n.strip(), a.replace(' ', '')) for t, n, a, _ in matches]
482         return CompositeType(type, name, members)
483
484 def parseCompositeTypes (src):
485         typeMap = { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION }
486         matches = re.findall(r'typedef (struct|union)(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
487         types   = []
488         for type, structname, contents, typename in matches:
489                 types.append(parseCompositeType(typeMap[type], typename, contents))
490         return types
491
492 def parseCompositeTypesByVersion (src, versionsData):
493
494         # find occurence of extension is a place where
495         # we cant assign apiVersion to found structures
496         extPtrn         = r'#define\s+[A-Z0-9_]+_EXTENSION_NAME\s+"([^"]+)"'
497         versionEnd      = re.search(extPtrn, src)
498         versions        = [Version((v[2], v[3], 0)) for v in versionsData]
499         versions.append(None)
500
501         # construct list of locations where version definitions start, and add the end of the file to it
502         sectionLocations = [versionDef[1] for versionDef in versionsData]
503         sectionLocations.append(versionEnd.start())
504         sectionLocations.append(len(src))
505
506         # construct function declaration pattern
507         ptrn            = r'typedef (struct|union)(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;'
508         regPtrn         = re.compile(ptrn)
509         types           = []
510         typeMap         = { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION }
511
512         # iterate over all versions and find all structure definitions
513         for index, v in enumerate(versions):
514                 matches = regPtrn.findall(src, sectionLocations[index], sectionLocations[index+1])
515                 for type, structname, contents, typename in matches:
516                         compositeType = parseCompositeType(typeMap[type], typename, contents)
517                         compositeType.apiVersion = v
518                         types.append(compositeType)
519         return types
520
521 def parseVersions (src):
522         # returns list of tuples each with four items:
523         # 1. string with version token (without ' 1' at the end)
524         # 2. starting point off version specific definitions in vulkan.h.in
525         # 3. major version number
526         # 4. minor version number
527         return [(m.group()[:-2], m.start(), int(m.group(1)), int(m.group(2))) for m in re.finditer('VK_VERSION_([1-9])_([0-9]) 1', src)]
528
529 def parseHandles (src):
530         matches = re.findall(r'VK_DEFINE(_NON_DISPATCHABLE|)_HANDLE\((' + IDENT_PTRN + r')\)[ \t]*[\n\r]', src)
531         handles = []
532         typeMap = {'': Handle.TYPE_DISP, '_NON_DISPATCHABLE': Handle.TYPE_NONDISP}
533         for type, name in matches:
534                 handle = Handle(typeMap[type], name)
535                 handles.append(handle)
536         return handles
537
538 def parseArgList (src):
539         typeNamePtrn    = r'(' + TYPE_PTRN + r')(\s+' + IDENT_PTRN + r')((\[[^\]]+\])*)\s*'
540         args                    = []
541         for rawArg in src.split(','):
542                 m = re.search(typeNamePtrn, rawArg)
543                 args.append(Variable(m.group(1).strip(), m.group(2).strip(), m.group(3)))
544         return args
545
546 def removeTypeExtPostfix (name):
547         for extPostfix in EXTENSION_POSTFIXES_STANDARD:
548                 if endsWith(name, extPostfix):
549                         return name[0:-len(extPostfix)]
550         return None
551
552 def populateExtensionAliases(allObjects, extensionObjects):
553         for object in extensionObjects:
554                 withoutPostfix = removeTypeExtPostfix(object.name)
555                 if withoutPostfix != None and withoutPostfix in allObjects:
556                         # max 1 alias is assumed by functions in this file
557                         assert allObjects[withoutPostfix].alias == None
558                         allObjects[withoutPostfix].alias = object
559                         object.isAlias = True
560         for object in extensionObjects:
561                 object.checkAliasValidity()
562
563 def populateAliasesWithTypedefs (objects, src):
564         objectsByName = {}
565         for object in objects:
566                 objectsByName[object.name] = object
567                 ptrn    = r'\s*typedef\s+' + object.name + r'\s+([^;]+)'
568                 stash = re.findall(ptrn, src)
569                 if len(stash) == 1:
570                         objExt = copy.deepcopy(object)
571                         objExt.name = stash[0]
572                         object.alias = objExt
573                         objExt.isAlias = True
574                         objects.append(objExt)
575
576 def removeAliasedValues (enum):
577         valueByName = {}
578         for name, value in enum.values:
579                 valueByName[name] = value
580
581         def removeDefExtPostfix (name):
582                 for extPostfix in EXTENSION_POSTFIXES:
583                         if endsWith(name, "_" + extPostfix):
584                                 return name[0:-(len(extPostfix)+1)]
585                 return None
586
587         newValues = []
588         for name, value in enum.values:
589                 withoutPostfix = removeDefExtPostfix(name)
590                 if withoutPostfix != None and withoutPostfix in valueByName and valueByName[withoutPostfix] == value:
591                         continue
592                 newValues.append((name, value))
593         enum.values = newValues
594
595 def parseFunctions (src):
596         ptrn            = r'VKAPI_ATTR\s+(' + TYPE_PTRN + ')\s+VKAPI_CALL\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;'
597         matches         = re.findall(ptrn, src)
598         functions       = []
599         for returnType, name, argList in matches:
600                 functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList)))
601         return functions
602
603 def parseFunctionsByVersion (src, versions):
604         # construct list of locations where version definitions start, and add the end of the file to it
605         sectionLocations = [versionDef[1] for versionDef in versions]
606         sectionLocations.append(len(src))
607
608         # construct function declaration pattern
609         ptrn            = r'VKAPI_ATTR\s+(' + TYPE_PTRN + ')\s+VKAPI_CALL\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;'
610         regPtrn         = re.compile(ptrn)
611         functions       = []
612
613         # iterate over all versions and find all function definitions
614         for index, v in enumerate(versions):
615                 matches = regPtrn.findall(src, sectionLocations[index], sectionLocations[index+1])
616                 for returnType, name, argList in matches:
617                         functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList), v[0]))
618         return functions
619
620 def splitByExtension (src):
621         ptrn            = r'#define\s+[A-Z0-9_]+_EXTENSION_NAME\s+"([^"]+)"'
622         # Construct long pattern that will be used to split whole source by extensions
623         match           = "#define\s+("
624         for part in re.finditer(ptrn, src):
625                  match += part.group(1)+"|"
626         match = match[:-1] + ")\s+1"
627         parts = re.split(match, src)
628
629         # First part is core, following tuples contain extension name and all its definitions
630         byExtension     = [(None, parts[0])]
631         for ndx in range(1, len(parts), 2):
632                 byExtension.append((parts[ndx], parts[ndx+1]))
633         return byExtension
634
635 def parseDefinitions (extensionName, src):
636
637         def skipDefinition (extensionName, definition):
638                 if extensionName == None:
639                         return True
640                 extNameUpper = extensionName.upper()
641                 extNameUpper = extNameUpper.replace("VK_KHR_SYNCHRONIZATION2", "VK_KHR_SYNCHRONIZATION_2")
642                 extNameUpper = extNameUpper.replace("VK_INTEL_SHADER_INTEGER_FUNCTIONS2", "VK_INTEL_SHADER_INTEGER_FUNCTIONS_2")
643                 extNameUpper = extNameUpper.replace("VK_EXT_ROBUSTNESS2", "VK_EXT_ROBUSTNESS_2")
644                 extNameUpper = extNameUpper.replace("VK_EXT_FRAGMENT_DENSITY_MAP2", "VK_EXT_FRAGMENT_DENSITY_MAP_2")
645                 extNameUpper = extNameUpper.replace("VK_EXT_SHADER_ATOMIC_FLOAT2", "VK_EXT_SHADER_ATOMIC_FLOAT_2")
646                 extNameUpper = extNameUpper.replace("VK_AMD_SHADER_CORE_PROPERTIES2", "VK_AMD_SHADER_CORE_PROPERTIES_2")
647                 extNameUpper = extNameUpper.replace("VK_EXT_EXTENDED_DYNAMIC_STATE2", "VK_EXT_EXTENDED_DYNAMIC_STATE_2")
648                 # SPEC_VERSION enums
649                 if definition[0].startswith(extNameUpper) and definition[1].isdigit():
650                         return False
651                 if definition[0].startswith(extNameUpper):
652                         return True
653                 if definition[0].endswith("_H_"):
654                         return True
655                 return False
656
657         ptrn            = r'#define\s+([^\s]+)\s+([^\r\n]+)'
658         matches         = re.findall(ptrn, src)
659
660         return [Definition(None, match[0], match[1]) for match in matches if not skipDefinition(extensionName, match)]
661
662 def parseTypedefs (src):
663
664         ptrn            = r'typedef\s+([^\s]+)\s+([^\r\n]+);'
665         matches         = re.findall(ptrn, src)
666
667         return [Definition(None, match[0], match[1]) for match in matches]
668
669 def parseExtensions (src, versions, allFunctions, allCompositeTypes, allEnums, allBitfields, allHandles, allDefinitions, additionalExtensionData):
670
671         # note promotedExtensionDict is also executed for vulkan 1.0 source for which extension name is None
672         promotedExtensionDict = {None: None}
673         for extensionName, data in additionalExtensionData:
674                 # make sure that this extension was registered
675                 if 'register_extension' not in data.keys():
676                         continue
677                 match = re.match("(\d).(\d).(\d)", data['register_extension']['core'])
678                 if match == None:
679                         continue
680                 # save array containing 'device' or 'instance' string followed by the vulkan version in which this extension is core
681                 promotedExtensionDict[extensionName] = [data['register_extension']['type'], int(match.group(1)), int(match.group(2)), int(match.group(3))]
682
683         splitSrc                                = splitByExtension(src)
684         extensions                              = []
685         functionsByName                 = {function.name: function for function in allFunctions}
686         compositeTypesByName    = {compType.name: compType for compType in allCompositeTypes}
687         enumsByName                             = {enum.name: enum for enum in allEnums}
688         bitfieldsByName                 = {bitfield.name: bitfield for bitfield in allBitfields}
689         handlesByName                   = {handle.name: handle for handle in allHandles}
690         definitionsByName               = {definition.name: definition for definition in allDefinitions}
691
692         for extensionName, extensionSrc in splitSrc:
693                 definitions                     = [Definition("uint32_t", v.getInHex(), parsePreprocDefinedValueOptional(extensionSrc, v.getInHex())) for v in versions]
694                 definitions.extend([Definition(type, name, parsePreprocDefinedValueOptional(extensionSrc, name)) for name, type in DEFINITIONS])
695                 definitions                     = [definition for definition in definitions if definition.value != None]
696                 additionalDefinitions = parseDefinitions(extensionName, extensionSrc)
697                 handles                         = parseHandles(extensionSrc)
698                 functions                       = parseFunctions(extensionSrc)
699                 compositeTypes          = parseCompositeTypes(extensionSrc)
700                 rawEnums                        = parseEnums(extensionSrc)
701                 bitfieldNames           = parseBitfieldNames(extensionSrc)
702                 typedefs                        = parseTypedefs(extensionSrc)
703                 enumBitfieldNames       = [getBitEnumNameForBitfield(name) for name in bitfieldNames]
704                 enums                           = [enum for enum in rawEnums if enum.name not in enumBitfieldNames]
705
706                 extCoreVersion          = promotedExtensionDict.get(extensionName, None)
707                 extFunctions            = [functionsByName[function.name] for function in functions]
708                 extCompositeTypes       = [compositeTypesByName[compositeType.name] for compositeType in compositeTypes]
709                 extEnums                        = [enumsByName[enum.name] for enum in enums]
710                 extBitfields            = [bitfieldsByName[bitfieldName] for bitfieldName in bitfieldNames]
711                 extHandles                      = [handlesByName[handle.name] for handle in handles]
712                 extDefinitions          = [definitionsByName[definition.name] for definition in definitions]
713
714                 if extCoreVersion != None:
715                         populateExtensionAliases(functionsByName, extFunctions)
716                         populateExtensionAliases(handlesByName, extHandles)
717                         populateExtensionAliases(enumsByName, extEnums)
718                         populateExtensionAliases(bitfieldsByName, extBitfields)
719                         populateExtensionAliases(compositeTypesByName, extCompositeTypes)
720                 extensions.append(Extension(extensionName, extHandles, extEnums, extBitfields, extCompositeTypes, extFunctions, extDefinitions, additionalDefinitions, typedefs, extCoreVersion))
721         return extensions
722
723 def parseBitfieldNames (src):
724         ptrn            = r'typedef\s+VkFlags\s(' + IDENT_PTRN + r')\s*;'
725         matches         = re.findall(ptrn, src)
726
727         return matches
728
729 def parse64bitBitfieldNames (src):
730         ptrn            = r'typedef\s+VkFlags64\s(' + IDENT_PTRN + r')\s*;'
731         matches         = re.findall(ptrn, src)
732
733         return matches
734
735 def parse64bitBitfieldValues (src, bitfieldNamesList):
736
737         bitfields64 = []
738         for bitfieldName in bitfieldNamesList:
739                 ptrn            = r'static const ' + bitfieldName + r'\s*(' + IDENT_PTRN + r')\s*=\s*([a-zA-Z0-9_]+)\s*;'
740                 matches         = re.findall(ptrn, src)
741                 bitfields64.append(Bitfield(bitfieldName, matches))
742
743         return bitfields64
744
745 def parseAPI (src):
746         versionsData    = parseVersions(src)
747         versions                = [Version((v[2], v[3], 0)) for v in versionsData]
748         definitions             = [Definition("uint32_t", v.getInHex(), parsePreprocDefinedValue(src, v.getInHex())) for v in versions] +\
749                                           [Definition(type, name, parsePreprocDefinedValue(src, name)) for name, type in DEFINITIONS]
750
751         handles                                         = parseHandles(src)
752         rawEnums                                        = parseEnums(src)
753         bitfieldNames                           = parseBitfieldNames(src)
754         bitfieldEnums                           = set([getBitEnumNameForBitfield(n) for n in bitfieldNames if getBitEnumNameForBitfield(n) in [enum.name for enum in rawEnums]])
755         bitfield64Names                         = parse64bitBitfieldNames(src)
756         bitfields64                                     = parse64bitBitfieldValues(src, bitfield64Names)
757         enums                                           = []
758         bitfields                                       = []
759         compositeTypes                          = parseCompositeTypesByVersion(src, versionsData)
760         allFunctions                            = parseFunctionsByVersion(src, versionsData)
761         additionalExtensionData         = {}
762
763         # read all files from extensions directory
764         for fileName in glob.glob(os.path.join(VULKAN_SRC_DIR, "extensions", "*.json")):
765                 extensionName   = os.path.basename(fileName)[:-5]
766                 fileContent             = readFile(fileName)
767                 try:
768                         additionalExtensionData[extensionName] = json.loads(fileContent)
769                 except ValueError as err:
770                         print("Error in %s: %s" % (os.path.basename(fileName), str(err)))
771                         sys.exit(-1)
772         additionalExtensionData = sorted(additionalExtensionData.items(), key=lambda e: e[0])
773
774         for enum in rawEnums:
775                 if enum.name in bitfieldEnums:
776                         bitfields.append(Bitfield(getBitfieldNameForBitEnum(enum.name), enum.values))
777                 else:
778                         enums.append(enum)
779
780         for bitfieldName in bitfieldNames:
781                 if not bitfieldName in [bitfield.name for bitfield in bitfields]:
782                         # Add empty bitfield
783                         bitfields.append(Bitfield(bitfieldName, []))
784
785         extensions = parseExtensions(src, versions, allFunctions, compositeTypes, enums, bitfields, handles, definitions, additionalExtensionData)
786
787         # Populate alias fields
788         populateAliasesWithTypedefs(compositeTypes, src)
789         populateAliasesWithTypedefs(enums, src)
790         populateAliasesWithTypedefs(bitfields, src)
791         populateAliasesWithTypedefs(handles, src)
792
793         for enum in enums:
794                 removeAliasedValues(enum)
795
796         # Make generator to create Deleter<VkAccelerationStructureNV>
797         for f in allFunctions:
798                 if (f.name == 'vkDestroyAccelerationStructureNV'):
799                         f.arguments[1].type[0] = 'VkAccelerationStructureNV'
800
801         # Dealias handles VkAccelerationStructureNV and VkAccelerationStructureKHR
802         for handle in handles:
803                 if handle.name == 'VkAccelerationStructureKHR':
804                         handle.alias = None
805                 if handle.name == 'VkAccelerationStructureNV':
806                         handle.isAlias = False
807
808         return API(
809                 versions                                = versions,
810                 definitions                             = definitions,
811                 handles                                 = handles,
812                 enums                                   = enums,
813                 bitfields                               = bitfields,
814                 bitfields64                             = bitfields64,
815                 compositeTypes                  = compositeTypes,
816                 functions                               = allFunctions,
817                 extensions                              = extensions,
818                 additionalExtensionData = additionalExtensionData)
819
820 def splitUniqueAndDuplicatedEntries (handles):
821         listOfUniqueHandles = []
822         duplicates                      = OrderedDict()
823         for handle in handles:
824                 if handle.alias != None:
825                         duplicates[handle.alias] = handle
826                 if not handle.isAlias:
827                         listOfUniqueHandles.append(handle)
828         return listOfUniqueHandles, duplicates
829
830 def writeHandleType (api, filename):
831         uniqeHandles, duplicatedHandles = splitUniqueAndDuplicatedEntries(api.handles)
832
833         def genHandles ():
834                 yield "\t%s\t= 0," % uniqeHandles[0].getHandleType()
835                 for handle in uniqeHandles[1:]:
836                         yield "\t%s," % handle.getHandleType()
837                 for duplicate in duplicatedHandles:
838                         yield "\t%s\t= %s," % (duplicate.getHandleType(), duplicatedHandles[duplicate].getHandleType())
839                 yield "\tHANDLE_TYPE_LAST\t= %s + 1" % (uniqeHandles[-1].getHandleType())
840
841         def genHandlesBlock ():
842                 yield "enum HandleType"
843                 yield "{"
844
845                 for line in indentLines(genHandles()):
846                         yield line
847
848                 yield "};"
849                 yield ""
850
851         writeInlFile(filename, INL_HEADER, genHandlesBlock())
852
853 def getEnumValuePrefix (enum):
854         prefix = enum.name[0]
855         for i in range(1, len(enum.name)):
856                 if enum.name[i].isupper() and not enum.name[i-1].isupper():
857                         prefix += "_"
858                 prefix += enum.name[i].upper()
859         return prefix
860
861 def parseInt (value):
862         if value[:2] == "0x":
863                 return int(value, 16)
864         else:
865                 return int(value, 10)
866
867 def areEnumValuesLinear (enum):
868         curIndex = 0
869         for name, value in enum.values:
870                 if value[:2] != "VK":
871                         intValue = parseInt(value)
872                         if intValue != curIndex:
873                                 # consider enums containing *_MAX_ENUM = 0x7FFFFFFF as linear
874                                 if intValue == 0x7FFFFFFF:
875                                         return True
876                                 return False
877                         curIndex += 1
878         return True
879
880 def genEnumSrc (enum):
881         yield "enum %s" % enum.name
882         yield "{"
883
884         lines = []
885         if areEnumValuesLinear(enum):
886                 hasMaxItem      = parseInt(enum.values[-1][1]) == 0x7FFFFFFF
887
888                 values          = enum.values[:-1] if hasMaxItem else enum.values
889                 lastItem        = "\t%s_LAST," % getEnumValuePrefix(enum)
890
891                 # linear values first, followed by *_LAST
892                 lines           += ["\t%s\t= %s," % v for v in values if v[1][:2] != "VK"]
893                 lines.append(lastItem)
894
895                 # equivalence enums and *_MAX_ENUM
896                 lines           += ["\t%s\t= %s," % v for v in values if v[1][:2] == "VK"]
897                 if hasMaxItem:
898                         lines.append("\t%s\t= %s," % enum.values[-1])
899         else:
900                 lines           += ["\t%s\t= %s," % v for v in enum.values]
901
902         for line in indentLines(lines):
903                 yield line
904
905         yield "};"
906
907 def genBitfieldSrc (bitfield):
908         if len(bitfield.values) > 0:
909                 yield "enum %s" % getBitEnumNameForBitfield(bitfield.name)
910                 yield "{"
911                 for line in indentLines(["\t%s\t= %s," % v for v in bitfield.values]):
912                         yield line
913                 yield "};"
914         yield "typedef uint32_t %s;" % bitfield.name
915
916 def genBitfield64Src (bitfield64):
917         yield "typedef uint64_t %s;" % bitfield64.name
918         if len(bitfield64.values) > 0:
919                 ptrn = "static const " + bitfield64.name + " %s\t= %s;"
920                 for line in indentLines([ptrn % v for v in bitfield64.values]):
921                         yield line
922                 yield ""
923
924 def genCompositeTypeSrc (type):
925         yield "%s %s" % (type.getClassName(), type.name)
926         yield "{"
927         for line in indentLines(['\t'+m.getAsString('\t')+';' for m in type.members]):
928                 yield line
929         yield "};"
930
931 def genHandlesSrc (handles):
932         uniqeHandles, duplicatedHandles = splitUniqueAndDuplicatedEntries(handles)
933
934         def genLines (handles):
935                 for handle in uniqeHandles:
936                         if handle.type == Handle.TYPE_DISP:
937                                 yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType())
938                         elif handle.type == Handle.TYPE_NONDISP:
939                                 yield "VK_DEFINE_NON_DISPATCHABLE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType())
940
941                 for duplicate in duplicatedHandles:
942                         if duplicate.type == Handle.TYPE_DISP:
943                                 yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (duplicate.name, duplicatedHandles[duplicate].getHandleType())
944                         elif duplicate.type == Handle.TYPE_NONDISP:
945                                 yield "VK_DEFINE_NON_DISPATCHABLE_HANDLE\t(%s,\t%s);" % (duplicate.name, duplicatedHandles[duplicate].getHandleType())
946
947         for line in indentLines(genLines(handles)):
948                 yield line
949
950 def stripTrailingComment(str):
951         index = str.find("//")
952         if index == -1:
953                 return str
954         return str[:index]
955
956 def genDefinitionsSrc (definitions):
957         for line in ["#define %s\t(static_cast<%s>\t(%s))" % (definition.name, definition.type, stripTrailingComment(definition.value)) for definition in definitions]:
958                 yield line
959
960 def genDefinitionsAliasSrc (definitions):
961         for line in ["#define %s\t%s" % (definition.name, definitions[definition].name) for definition in definitions]:
962                 if definition.value != definitions[definition].value and definition.value != definitions[definition].name:
963                         raise Exception("Value of %s (%s) is different than core definition value %s (%s)." % (definition.name, definition.value, definitions[definition].name, definitions[definition].value))
964                 yield line
965
966 def genMaxFrameworkVersion (definitions):
967         maxApiVersionMajor = 1
968         maxApiVersionMinor = 0
969         for definition in definitions:
970                 match = re.match("VK_API_VERSION_(\d+)_(\d+)", definition.name)
971                 if match:
972                         apiVersionMajor = int(match.group(1))
973                         apiVersionMinor = int(match.group(2))
974                         if apiVersionMajor > maxApiVersionMajor:
975                                 maxApiVersionMajor = apiVersionMajor
976                                 maxApiVersionMinor = apiVersionMinor
977                         elif apiVersionMajor == maxApiVersionMajor and apiVersionMinor > maxApiVersionMinor:
978                                 maxApiVersionMinor = apiVersionMinor
979         yield "#define VK_API_MAX_FRAMEWORK_VERSION\tVK_API_VERSION_%d_%d" % (maxApiVersionMajor, maxApiVersionMinor)
980
981 def writeBasicTypes (api, filename):
982
983         def gen ():
984                 definitionsCore, definitionDuplicates = splitUniqueAndDuplicatedEntries(api.definitions)
985
986                 for line in indentLines(chain(genDefinitionsSrc(definitionsCore), genMaxFrameworkVersion(definitionsCore), genDefinitionsAliasSrc(definitionDuplicates))):
987                         yield line
988                 yield ""
989
990                 for line in genHandlesSrc(api.handles):
991                         yield line
992                 yield ""
993
994                 for enum in api.enums:
995                         if not enum.isAlias:
996                                 for line in genEnumSrc(enum):
997                                         yield line
998                         else:
999                                 for enum2 in api.enums:
1000                                         if enum2.alias == enum:
1001                                                 yield "typedef %s %s;" % (enum2.name, enum.name)
1002                         yield ""
1003
1004                 for bitfield in api.bitfields:
1005                         if not bitfield.isAlias:
1006                                 for line in genBitfieldSrc(bitfield):
1007                                         yield line
1008                         else:
1009                                 for bitfield2 in api.bitfields:
1010                                         if bitfield2.alias == bitfield:
1011                                                 yield "typedef %s %s;" % (bitfield2.name, bitfield.name)
1012                         yield ""
1013
1014                 for bitfield64 in api.bitfields64:
1015                         for line in genBitfield64Src(bitfield64):
1016                                 yield line
1017
1018                 for line in indentLines(["VK_DEFINE_PLATFORM_TYPE(%s,\t%s)" % (s[0], c) for n, s, c in PLATFORM_TYPES]):
1019                         yield line
1020
1021                 for ext in api.extensions:
1022                         if ext.additionalDefs != None:
1023                                 for definition in ext.additionalDefs:
1024                                         yield "#define " + definition.name + " " + definition.value
1025
1026         writeInlFile(filename, INL_HEADER, gen())
1027
1028 def writeCompositeTypes (api, filename):
1029         def gen ():
1030                 for type in api.compositeTypes:
1031                         type.checkAliasValidity()
1032
1033                         if not type.isAlias:
1034                                 for line in genCompositeTypeSrc(type):
1035                                         yield line
1036                         else:
1037                                 for type2 in api.compositeTypes:
1038                                         if type2.alias == type:
1039                                                 yield "typedef %s %s;" % (type2.name, type.name)
1040                         yield ""
1041
1042         writeInlFile(filename, INL_HEADER, gen())
1043
1044 def argListToStr (args):
1045         return ", ".join(v.getAsStringForArgumentList(' ') for v in args)
1046
1047 def writeInterfaceDecl (api, filename, functionTypes, concrete):
1048         def genProtos ():
1049                 postfix = "" if concrete else " = 0"
1050                 for function in api.functions:
1051                         if not function.getType() in functionTypes:
1052                                 continue
1053                         if not function.isAlias:
1054                                 yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments), postfix)
1055
1056         writeInlFile(filename, INL_HEADER, indentLines(genProtos()))
1057
1058 def writeFunctionPtrTypes (api, filename):
1059         def genTypes ():
1060                 for function in api.functions:
1061                         yield "typedef VKAPI_ATTR %s\t(VKAPI_CALL* %s)\t(%s);" % (function.returnType, getFunctionTypeName(function), argListToStr(function.arguments))
1062
1063         writeInlFile(filename, INL_HEADER, indentLines(genTypes()))
1064
1065 def writeFunctionPointers (api, filename, functionTypes):
1066         def FunctionsYielder ():
1067                 for function in api.functions:
1068                         if function.getType() in functionTypes:
1069                                 if function.isAlias:
1070                                         if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice":
1071                                                 yield "%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function))
1072                                 else:
1073                                         yield "%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function))
1074
1075         writeInlFile(filename, INL_HEADER, indentLines(FunctionsYielder()))
1076
1077 def writeInitFunctionPointers (api, filename, functionTypes, cond = None):
1078         def makeInitFunctionPointers ():
1079                 for function in api.functions:
1080                         if function.getType() in functionTypes and (cond == None or cond(function)):
1081                                 interfaceName = getInterfaceName(function)
1082                                 if function.isAlias:
1083                                         if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice":
1084                                                 yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name)
1085                                 else:
1086                                         yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name)
1087                                         if function.alias != None:
1088                                                 yield "if (!m_vk.%s)" % (getInterfaceName(function))
1089                                                 yield "    m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.alias.name)
1090         lines = [line.replace('    ', '\t') for line in indentLines(makeInitFunctionPointers())]
1091         writeInlFile(filename, INL_HEADER, lines)
1092
1093 def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className):
1094         def makeFuncPtrInterfaceImpl ():
1095                 for function in api.functions:
1096                         if function.getType() in functionTypes and not function.isAlias:
1097                                 yield ""
1098                                 yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), argListToStr(function.arguments))
1099                                 yield "{"
1100                                 if function.name == "vkEnumerateInstanceVersion":
1101                                         yield " if (m_vk.enumerateInstanceVersion)"
1102                                         yield "         return m_vk.enumerateInstanceVersion(pApiVersion);"
1103                                         yield ""
1104                                         yield " *pApiVersion = VK_API_VERSION_1_0;"
1105                                         yield " return VK_SUCCESS;"
1106                                 elif function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice" and function.alias != None:
1107                                         yield " vk::VkPhysicalDeviceProperties props;"
1108                                         yield " m_vk.getPhysicalDeviceProperties(physicalDevice, &props);"
1109                                         yield " if (props.apiVersion >= VK_API_VERSION_1_1)"
1110                                         yield "         %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
1111                                         yield " else"
1112                                         yield "         %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.alias), ", ".join(a.name for a in function.arguments))
1113                                 else:
1114                                         yield " %sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
1115                                 yield "}"
1116
1117         writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl())
1118
1119 def writeStrUtilProto (api, filename):
1120         def makeStrUtilProto ():
1121                 for line in indentLines(["const char*\tget%sName\t(%s value);" % (enum.name[2:], enum.name) for enum in api.enums if not enum.isAlias]):
1122                         yield line
1123                 yield ""
1124                 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 not e.isAlias]):
1125                         yield line
1126                 yield ""
1127                 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 not e.isAlias]):
1128                         yield line
1129                 yield ""
1130                 for line in indentLines(["tcu::Format::Bitfield<32>\tget%sStr\t(%s value);" % (bitfield.name[2:], bitfield.name) for bitfield in api.bitfields if not bitfield.isAlias or bitfield.name=='VkBuildAccelerationStructureFlagsNV']):
1131                         yield line
1132                 yield ""
1133                 for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.compositeTypes if not s.isAlias]):
1134                         yield line
1135
1136         writeInlFile(filename, INL_HEADER, makeStrUtilProto())
1137
1138 def writeStrUtilImpl (api, filename):
1139         def makeStrUtilImpl ():
1140                 for line in indentLines(["template<> const char*\tgetTypeName<%s>\t(void) { return \"%s\";\t}" % (handle.name, handle.name) for handle in api.handles if not handle.isAlias]):
1141                         yield line
1142
1143                 yield ""
1144                 yield "namespace %s" % PLATFORM_TYPE_NAMESPACE
1145                 yield "{"
1146
1147                 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):
1148                         yield line
1149
1150                 yield "}"
1151
1152                 for enum in api.enums:
1153                         if enum.isAlias:
1154                                 continue
1155                         yield ""
1156                         yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name)
1157                         yield "{"
1158                         yield "\tswitch (value)"
1159                         yield "\t{"
1160                         for line in indentLines(["\t\tcase %s:\treturn \"%s\";" % (n, n) for n, v in enum.values if v[:2] != "VK"] + ["\t\tdefault:\treturn DE_NULL;"]):
1161                                 yield line
1162                         yield "\t}"
1163                         yield "}"
1164
1165                 for bitfield in api.bitfields:
1166                         if bitfield.isAlias:
1167                                 if bitfield.name != 'VkBuildAccelerationStructureFlagsNV':
1168                                         continue
1169                         yield ""
1170                         yield "tcu::Format::Bitfield<32> get%sStr (%s value)" % (bitfield.name[2:], bitfield.name)
1171                         yield "{"
1172
1173                         if len(bitfield.values) > 0:
1174                                 yield "\tstatic const tcu::Format::BitDesc s_desc[] ="
1175                                 yield "\t{"
1176                                 for line in indentLines(["\t\ttcu::Format::BitDesc(%s,\t\"%s\")," % (n, n) for n, v in bitfield.values]):
1177                                         yield line
1178                                 yield "\t};"
1179                                 yield "\treturn tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));"
1180                         else:
1181                                 yield "\treturn tcu::Format::Bitfield<32>(value, DE_NULL, DE_NULL);"
1182                         yield "}"
1183
1184                 bitfieldTypeNames = set([bitfield.name for bitfield in api.bitfields])
1185
1186                 for type in api.compositeTypes:
1187                         if not type.isAlias:
1188                                 yield ""
1189                                 yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % type.name
1190                                 yield "{"
1191                                 yield "\ts << \"%s = {\\n\";" % type.name
1192                                 for member in type.members:
1193                                         memberName      = member.name
1194                                         valFmt          = None
1195                                         newLine         = ""
1196                                         if member.getType() in bitfieldTypeNames:
1197                                                 valFmt = "get%sStr(value.%s)" % (member.getType()[2:], member.name)
1198                                         elif member.getType() == "const char*" or member.getType() == "char*":
1199                                                 valFmt = "getCharPtrStr(value.%s)" % member.name
1200                                         elif member.getType() == PLATFORM_TYPE_NAMESPACE + "::Win32LPCWSTR":
1201                                                 valFmt = "getWStr(value.%s)" % member.name
1202                                         elif member.arraySize != '':
1203                                                 singleDimensional = not '][' in member.arraySize
1204                                                 if member.name in ["extensionName", "deviceName", "layerName", "description"]:
1205                                                         valFmt = "(const char*)value.%s" % member.name
1206                                                 elif singleDimensional and (member.getType() == 'char' or member.getType() == 'uint8_t'):
1207                                                         newLine = "'\\n' << "
1208                                                         valFmt  = "tcu::formatArray(tcu::Format::HexIterator<%s>(DE_ARRAY_BEGIN(value.%s)), tcu::Format::HexIterator<%s>(DE_ARRAY_END(value.%s)))" % (member.getType(), member.name, member.getType(), member.name)
1209                                                 else:
1210                                                         if member.name == "memoryTypes" or member.name == "memoryHeaps":
1211                                                                 endIter = "DE_ARRAY_BEGIN(value.%s) + value.%sCount" % (member.name, member.name[:-1])
1212                                                         else:
1213                                                                 endIter = "DE_ARRAY_END(value.%s)" % member.name
1214                                                         newLine = "'\\n' << "
1215                                                         valFmt  = "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), %s)" % (member.name, endIter)
1216                                                 memberName = member.name
1217                                         else:
1218                                                 valFmt = "value.%s" % member.name
1219                                         yield ("\ts << \"\\t%s = \" << " % memberName) + newLine + valFmt + " << '\\n';"
1220                                 yield "\ts << '}';"
1221                                 yield "\treturn s;"
1222                                 yield "}"
1223         writeInlFile(filename, INL_HEADER, makeStrUtilImpl())
1224
1225
1226 def writeObjTypeImpl (api, filename):
1227         def makeObjTypeImpl ():
1228
1229                 yield "namespace vk"
1230                 yield "{"
1231
1232                 yield "template<typename T> VkObjectType getObjectType  (void);"
1233
1234                 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 if not handle.isAlias]):
1235                         yield line
1236
1237                 yield "}"
1238
1239         writeInlFile(filename, INL_HEADER, makeObjTypeImpl())
1240
1241 class ConstructorFunction:
1242         def __init__ (self, type, name, objectType, ifaceArgs, arguments):
1243                 self.type               = type
1244                 self.name               = name
1245                 self.objectType = objectType
1246                 self.ifaceArgs  = ifaceArgs
1247                 self.arguments  = arguments
1248
1249 def getConstructorFunctions (api):
1250         funcs = []
1251         ifacesDict = {
1252                 Function.TYPE_PLATFORM: [Variable("const PlatformInterface&", "vk", "")],
1253                 Function.TYPE_INSTANCE: [Variable("const InstanceInterface&", "vk", "")],
1254                 Function.TYPE_DEVICE: [Variable("const DeviceInterface&", "vk", "")]
1255         }
1256         for function in api.functions:
1257                 if function.isAlias:
1258                         continue
1259                 if (function.name[:8] == "vkCreate" or function.name == "vkAllocateMemory") and not "createInfoCount" in [a.name for a in function.arguments]:
1260                         if function.name == "vkCreateDisplayModeKHR":
1261                                 continue # No way to delete display modes (bug?)
1262
1263                         # \todo [pyry] Rather hacky
1264                         ifaceArgs = ifacesDict[function.getType()]
1265                         if function.name == "vkCreateDevice":
1266                                 ifaceArgs = [Variable("const PlatformInterface&", "vkp", ""), Variable("VkInstance", "instance", "")] + ifaceArgs
1267
1268                         assert (function.arguments[-2].type == ["const", "VkAllocationCallbacks", "*"])
1269
1270                         objectType      = function.arguments[-1].type[0] #not getType() but type[0] on purpose
1271                         arguments       = function.arguments[:-1]
1272                         funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function), objectType, ifaceArgs, arguments))
1273         return funcs
1274
1275 def addVersionDefines(versionSpectrum):
1276         output = ["#define " + ver.getDefineName() + " " + ver.getInHex() for ver in versionSpectrum if not ver.isStandardVersion()]
1277         return output
1278
1279 def removeVersionDefines(versionSpectrum):
1280         output = ["#undef " + ver.getDefineName() for ver in versionSpectrum if not ver.isStandardVersion()]
1281         return output
1282
1283 def writeRefUtilProto (api, filename):
1284         functions = getConstructorFunctions(api)
1285
1286         def makeRefUtilProto ():
1287                 unindented = []
1288                 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]):
1289                         yield line
1290
1291         writeInlFile(filename, INL_HEADER, makeRefUtilProto())
1292
1293 def writeRefUtilImpl (api, filename):
1294         functions = getConstructorFunctions(api)
1295
1296         def makeRefUtilImpl ():
1297                 yield "namespace refdetails"
1298                 yield "{"
1299                 yield ""
1300
1301                 for function in api.functions:
1302                         if function.getType() == Function.TYPE_DEVICE \
1303                         and (function.name[:9] == "vkDestroy" or function.name == "vkFreeMemory") \
1304                         and not function.name == "vkDestroyDevice" \
1305                         and not function.isAlias:
1306                                 objectType = function.arguments[-2].getType()
1307                                 yield "template<>"
1308                                 yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType)
1309                                 yield "{"
1310                                 yield "\tm_deviceIface->%s(m_device, obj, m_allocator);" % (getInterfaceName(function))
1311                                 yield "}"
1312                                 yield ""
1313
1314                 yield "} // refdetails"
1315                 yield ""
1316
1317                 dtorDict = {
1318                         Function.TYPE_PLATFORM: "object",
1319                         Function.TYPE_INSTANCE: "instance",
1320                         Function.TYPE_DEVICE: "device"
1321                 }
1322
1323                 for function in functions:
1324                         deleterArgsString = ''
1325                         if function.name == "createDevice":
1326                                 # createDevice requires two additional parameters to setup VkDevice deleter
1327                                 deleterArgsString = "vkp, instance, object, " +  function.arguments[-1].name
1328                         else:
1329                                 deleterArgsString = "vk, %s, %s" % (dtorDict[function.type], function.arguments[-1].name)
1330
1331                         yield "Move<%s> %s (%s)" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments))
1332                         yield "{"
1333                         yield "\t%s object = 0;" % function.objectType
1334                         yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"]))
1335                         yield "\treturn Move<%s>(check<%s>(object), Deleter<%s>(%s));" % (function.objectType, function.objectType, function.objectType, deleterArgsString)
1336                         yield "}"
1337                         yield ""
1338
1339         writeInlFile(filename, INL_HEADER, makeRefUtilImpl())
1340
1341 def writeStructTraitsImpl (api, filename):
1342         def gen ():
1343                 for type in api.compositeTypes:
1344                         if type.getClassName() == "struct" and type.members[0].name == "sType" and not type.isAlias and type.name != "VkBaseOutStructure" and type.name != "VkBaseInStructure":
1345                                 yield "template<> VkStructureType getStructureType<%s> (void)" % type.name
1346                                 yield "{"
1347                                 yield "\treturn %s;" % prefixName("VK_STRUCTURE_TYPE_", type.name)
1348                                 yield "}"
1349                                 yield ""
1350
1351         writeInlFile(filename, INL_HEADER, gen())
1352
1353 def writeNullDriverImpl (api, filename):
1354         def genNullDriverImpl ():
1355                 specialFuncNames        = [
1356                                 "vkCreateGraphicsPipelines",
1357                                 "vkCreateComputePipelines",
1358                                 "vkCreateRayTracingPipelinesNV",
1359                                 "vkCreateRayTracingPipelinesKHR",
1360                                 "vkGetInstanceProcAddr",
1361                                 "vkGetDeviceProcAddr",
1362                                 "vkEnumeratePhysicalDevices",
1363                                 "vkEnumerateInstanceExtensionProperties",
1364                                 "vkEnumerateDeviceExtensionProperties",
1365                                 "vkGetPhysicalDeviceFeatures",
1366                                 "vkGetPhysicalDeviceFeatures2KHR",
1367                                 "vkGetPhysicalDeviceProperties",
1368                                 "vkGetPhysicalDeviceProperties2KHR",
1369                                 "vkGetPhysicalDeviceQueueFamilyProperties",
1370                                 "vkGetPhysicalDeviceMemoryProperties",
1371                                 "vkGetPhysicalDeviceFormatProperties",
1372                                 "vkGetPhysicalDeviceImageFormatProperties",
1373                                 "vkGetDeviceQueue",
1374                                 "vkGetBufferMemoryRequirements",
1375                                 "vkGetBufferMemoryRequirements2KHR",
1376                                 "vkGetImageMemoryRequirements",
1377                                 "vkGetImageMemoryRequirements2KHR",
1378                                 "vkAllocateMemory",
1379                                 "vkMapMemory",
1380                                 "vkUnmapMemory",
1381                                 "vkAllocateDescriptorSets",
1382                                 "vkFreeDescriptorSets",
1383                                 "vkResetDescriptorPool",
1384                                 "vkAllocateCommandBuffers",
1385                                 "vkFreeCommandBuffers",
1386                                 "vkCreateDisplayModeKHR",
1387                                 "vkCreateSharedSwapchainsKHR",
1388                                 "vkGetPhysicalDeviceExternalBufferPropertiesKHR",
1389                                 "vkGetPhysicalDeviceImageFormatProperties2KHR",
1390                                 "vkGetMemoryAndroidHardwareBufferANDROID",
1391                         ]
1392
1393                 coreFunctions           = [f for f in api.functions if not f.isAlias]
1394                 specialFuncs            = [f for f in coreFunctions if f.name in specialFuncNames]
1395                 createFuncs                     = [f for f in coreFunctions if (f.name[:8] == "vkCreate" or f.name == "vkAllocateMemory") and not f in specialFuncs]
1396                 destroyFuncs            = [f for f in coreFunctions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs]
1397                 dummyFuncs                      = [f for f in coreFunctions if f not in specialFuncs + createFuncs + destroyFuncs]
1398
1399                 def getHandle (name):
1400                         for handle in api.handles:
1401                                 if handle.name == name[0]:
1402                                         return handle
1403                         raise Exception("No such handle: %s" % name)
1404
1405                 for function in createFuncs:
1406                         objectType      = function.arguments[-1].type[:-1]
1407                         argsStr         = ", ".join([a.name for a in function.arguments[:-1]])
1408
1409                         yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
1410                         yield "{"
1411                         yield "\tDE_UNREF(%s);" % function.arguments[-2].name
1412
1413                         if getHandle(objectType).type == Handle.TYPE_NONDISP:
1414                                 yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[0][2:], objectType[0], argsStr)
1415                         else:
1416                                 yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[0][2:], objectType[0], argsStr)
1417                         yield "}"
1418                         yield ""
1419
1420                 for function in destroyFuncs:
1421                         objectArg       = function.arguments[-2]
1422
1423                         yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
1424                         yield "{"
1425                         for arg in function.arguments[:-2]:
1426                                 yield "\tDE_UNREF(%s);" % arg.name
1427
1428                         if getHandle(objectArg.type).type == Handle.TYPE_NONDISP:
1429                                 yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.getType()[2:], objectArg.getType(), objectArg.name, function.arguments[-1].name)
1430                         else:
1431                                 yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.getType()[2:], objectArg.getType(), objectArg.name, function.arguments[-1].name)
1432
1433                         yield "}"
1434                         yield ""
1435
1436                 for function in dummyFuncs:
1437                         yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
1438                         yield "{"
1439                         for arg in function.arguments:
1440                                 yield "\tDE_UNREF(%s);" % arg.name
1441                         if function.returnType != "void":
1442                                 yield "\treturn VK_SUCCESS;"
1443                         yield "}"
1444                         yield ""
1445
1446                 def genFuncEntryTable (type, name):
1447                         funcs = [f for f in api.functions if f.getType() == type]
1448                         refFuncs = {}
1449                         for f in api.functions:
1450                                 if f.alias != None:
1451                                         refFuncs[f.alias] = f
1452
1453                         yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name
1454                         yield "{"
1455                         for line in indentLines(["\tVK_NULL_FUNC_ENTRY(%s,\t%s)," % (function.name, getInterfaceName(function if not function.isAlias else refFuncs[function])) for function in funcs]):
1456                                 yield line
1457                         yield "};"
1458                         yield ""
1459
1460                 # Func tables
1461                 for line in genFuncEntryTable(Function.TYPE_PLATFORM, "s_platformFunctions"):
1462                         yield line
1463
1464                 for line in genFuncEntryTable(Function.TYPE_INSTANCE, "s_instanceFunctions"):
1465                         yield line
1466
1467                 for line in genFuncEntryTable(Function.TYPE_DEVICE, "s_deviceFunctions"):
1468                         yield line
1469
1470         writeInlFile(filename, INL_HEADER, genNullDriverImpl())
1471
1472 def writeTypeUtil (api, filename):
1473         # Structs filled by API queries are not often used in test code
1474         QUERY_RESULT_TYPES = set([
1475                         "VkPhysicalDeviceFeatures",
1476                         "VkPhysicalDeviceLimits",
1477                         "VkFormatProperties",
1478                         "VkImageFormatProperties",
1479                         "VkPhysicalDeviceSparseProperties",
1480                         "VkQueueFamilyProperties",
1481                         "VkMemoryType",
1482                         "VkMemoryHeap",
1483                         "StdVideoH264SpsVuiFlags",
1484                         "StdVideoH264SpsFlags",
1485                         "StdVideoH264PpsFlags",
1486                         "StdVideoDecodeH264PictureInfoFlags",
1487                         "StdVideoDecodeH264ReferenceInfoFlags",
1488                         "StdVideoDecodeH264MvcElementFlags",
1489                         "StdVideoEncodeH264SliceHeaderFlags",
1490                         "StdVideoEncodeH264PictureInfoFlags",
1491                         "StdVideoEncodeH264RefMgmtFlags",
1492                         "StdVideoH265HrdFlags",
1493                         "StdVideoH265VpsFlags",
1494                         "StdVideoH265SpsVuiFlags",
1495                         "StdVideoH265SpsFlags",
1496                         "StdVideoH265PpsFlags",
1497                         "StdVideoDecodeH265PictureInfoFlags",
1498                         "StdVideoDecodeH265ReferenceInfoFlags",
1499                         "StdVideoEncodeH265PictureInfoFlags",
1500                         "StdVideoEncodeH265SliceHeaderFlags",
1501                         "StdVideoEncodeH265ReferenceModificationFlags",
1502                         "StdVideoEncodeH265ReferenceInfoFlags",
1503                 ])
1504         COMPOSITE_TYPES = set([t.name for t in api.compositeTypes if not t.isAlias])
1505
1506         def isSimpleStruct (type):
1507                 def hasArrayMember (type):
1508                         for member in type.members:
1509                                 if member.arraySize != '':
1510                                         return True
1511                         return False
1512
1513                 def hasCompositeMember (type):
1514                         for member in type.members:
1515                                 if member.getType() in COMPOSITE_TYPES:
1516                                         return True
1517                         return False
1518
1519                 return type.typeClass == CompositeType.CLASS_STRUCT and \
1520                 type.members[0].getType() != "VkStructureType" and \
1521                 not type.name in QUERY_RESULT_TYPES and \
1522                 not hasArrayMember(type) and \
1523                 not hasCompositeMember(type)
1524
1525         def gen ():
1526                 for type in api.compositeTypes:
1527                         if not isSimpleStruct(type) or type.isAlias:
1528                                 continue
1529
1530                         name = type.name[2:] if type.name[:2].lower() == "vk" else type.name
1531
1532                         yield ""
1533                         yield "inline %s make%s (%s)" % (type.name, name, argListToStr(type.members))
1534                         yield "{"
1535                         yield "\t%s res;" % type.name
1536                         for line in indentLines(["\tres.%s\t= %s;" % (m.name, m.name) for m in type.members]):
1537                                 yield line
1538                         yield "\treturn res;"
1539                         yield "}"
1540
1541         writeInlFile(filename, INL_HEADER, gen())
1542
1543 def writeDriverIds(filename):
1544
1545         driverIdsString = []
1546         driverIdsString.append("static const struct\n"
1547                                          "{\n"
1548                                          "\tstd::string driver;\n"
1549                                          "\tuint32_t id;\n"
1550                                          "} driverIds [] =\n"
1551                                          "{")
1552
1553         vulkanCore = readFile(os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "vulkan", "vulkan_core.h"))
1554
1555         items = re.search(r'(?:typedef\s+enum\s+VkDriverId\s*{)((.*\n)*)(?:}\s*VkDriverId\s*;)', vulkanCore).group(1).split(',')
1556         driverItems = dict()
1557         for item in items:
1558                 item.strip()
1559                 splitted = item.split('=')
1560                 key = splitted[0].strip()
1561                 value_str = splitted[1].strip()
1562                 try: # is this previously defined value?
1563                         value = driverItems[value_str]
1564                 except:
1565                         value = value_str
1566                         value_str = ""
1567                 if value_str:
1568                         value_str = "\t// " + value_str
1569                 driverItems[key] = value
1570                 if not item == items[-1]:
1571                         driverIdsString.append("\t{\"" + key + "\"" + ", " + value + "}," + value_str)
1572                 else:
1573                         driverIdsString.append("\t{\"" + key + "\"" + ", " + value + "}" + value_str)
1574                 driverItems[key] = value
1575
1576         driverIdsString.append("};")
1577
1578         writeInlFile(filename, INL_HEADER, driverIdsString)
1579
1580
1581 def writeSupportedExtenions(api, filename):
1582
1583         def writeExtensionsForVersions(map):
1584                 result = []
1585                 for version in map:
1586                         result.append(" if (coreVersion >= " + str(version) + ")")
1587                         result.append(" {")
1588                         for extension in map[version]:
1589                                 result.append('         dst.push_back("' + extension.name + '");')
1590                         result.append(" }")
1591
1592                 return result
1593
1594         instanceMap             = {}
1595         deviceMap               = {}
1596         versionSet              = set()
1597
1598         for ext in api.extensions:
1599                 if ext.versionInCore != None:
1600                         if ext.versionInCore[0] == 'instance':
1601                                 list = instanceMap.get(Version(ext.versionInCore[1:]))
1602                                 instanceMap[Version(ext.versionInCore[1:])] = list + [ext] if list else [ext]
1603                         else:
1604                                 list = deviceMap.get(Version(ext.versionInCore[1:]))
1605                                 deviceMap[Version(ext.versionInCore[1:])] = list + [ext] if list else [ext]
1606                         versionSet.add(Version(ext.versionInCore[1:]))
1607
1608         lines = addVersionDefines(versionSet) + [
1609         "",
1610         "void getCoreDeviceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(deviceMap) != 0 else ""),
1611         "{"] + writeExtensionsForVersions(deviceMap) + [
1612         "}",
1613         "",
1614         "void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(instanceMap) != 0 else ""),
1615         "{"] + writeExtensionsForVersions(instanceMap) + [
1616         "}",
1617         ""] + removeVersionDefines(versionSet)
1618         writeInlFile(filename, INL_HEADER, lines)
1619
1620 def writeExtensionFunctions (api, filename):
1621
1622         def isInstanceExtension (ext):
1623                 if ext.name and ext.functions:
1624                         if ext.functions[0].getType() == Function.TYPE_INSTANCE:
1625                                 return True
1626                         else:
1627                                 return False
1628
1629         def isDeviceExtension (ext):
1630                 if ext.name and ext.functions:
1631                         if ext.functions[0].getType() == Function.TYPE_DEVICE:
1632                                 return True
1633                         else:
1634                                 return False
1635
1636         def writeExtensionNameArrays ():
1637                 instanceExtensionNames = []
1638                 deviceExtensionNames = []
1639                 for ext in api.extensions:
1640                         if ext.name and isInstanceExtension(ext):
1641                                 instanceExtensionNames += [ext.name]
1642                         elif ext.name and isDeviceExtension(ext):
1643                                 deviceExtensionNames += [ext.name]
1644                 yield '::std::string instanceExtensionNames[] =\n{'
1645                 for instanceExtName in instanceExtensionNames:
1646                         if (instanceExtName == instanceExtensionNames[len(instanceExtensionNames) - 1]):
1647                                 yield '\t"%s"' % instanceExtName
1648                         else:
1649                                 yield '\t"%s",' % instanceExtName
1650                 yield '};\n'
1651                 yield '::std::string deviceExtensionNames[] =\n{'
1652                 for deviceExtName in deviceExtensionNames:
1653                         if (deviceExtName == deviceExtensionNames[len(deviceExtensionNames) - 1]):
1654                                 yield '\t"%s"' % deviceExtName
1655                         else:
1656                                 yield '\t"%s",' % deviceExtName
1657                 yield '};'
1658
1659         def writeExtensionFunctions (functionType):
1660                 isFirstWrite = True
1661                 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
1662                 if functionType == Function.TYPE_INSTANCE:
1663                         yield 'void getInstanceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{'
1664                         dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"]
1665                 elif functionType == Function.TYPE_DEVICE:
1666                         yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{'
1667                         dg_list = ["vkGetDeviceGroupPresentCapabilitiesKHR", "vkGetDeviceGroupSurfacePresentModesKHR", "vkAcquireNextImage2KHR"]
1668                 for ext in api.extensions:
1669                         funcNames = []
1670                         if ext.name:
1671                                 for func in ext.functions:
1672                                         if func.getType() == functionType:
1673                                                 # only add functions with same vendor as extension
1674                                                 # this is a workaroudn for entrypoints requiring more
1675                                                 # than one excetions and lack of the dependency in vulkan_core.h
1676                                                 vendor = ext.name.split('_')[1]
1677                                                 if func.name.endswith(vendor):
1678                                                         funcNames.append(func.name)
1679                         if ext.name:
1680                                 yield '\tif (extName == "%s")' % ext.name
1681                                 yield '\t{'
1682                                 for funcName in funcNames:
1683                                         if funcName in dg_list:
1684                                                 yield '\t\tif(apiVersion >= VK_API_VERSION_1_1) functions.push_back("%s");' % funcName
1685                                         else:
1686                                                 yield '\t\tfunctions.push_back("%s");' % funcName
1687                                 if ext.name == "VK_KHR_device_group":
1688                                         for dg_func in dg_list:
1689                                                 yield '\t\tif(apiVersion < VK_API_VERSION_1_1) functions.push_back("%s");' % dg_func
1690                                 yield '\t\treturn;'
1691                                 yield '\t}'
1692                                 isFirstWrite = False
1693                 if not isFirstWrite:
1694                         yield '\tDE_FATAL("Extension name not found");'
1695                         yield '}'
1696
1697         lines = ['']
1698         for line in writeExtensionFunctions(Function.TYPE_INSTANCE):
1699                 lines += [line]
1700         lines += ['']
1701         for line in writeExtensionFunctions(Function.TYPE_DEVICE):
1702                 lines += [line]
1703         lines += ['']
1704         for line in writeExtensionNameArrays():
1705                 lines += [line]
1706
1707         writeInlFile(filename, INL_HEADER, lines)
1708
1709 def writeCoreFunctionalities(api, filename):
1710         functionOriginValues    = ["FUNCTIONORIGIN_PLATFORM", "FUNCTIONORIGIN_INSTANCE", "FUNCTIONORIGIN_DEVICE"]
1711         lines                                   = addVersionDefines(api.versions) + [
1712         "",
1713         'enum FunctionOrigin', '{'] + [line for line in indentLines([
1714         '\t' + functionOriginValues[0] + '\t= 0,',
1715         '\t' + functionOriginValues[1] + ',',
1716         '\t' + functionOriginValues[2]])] + [
1717         "};",
1718         "",
1719         "typedef ::std::pair<const char*, FunctionOrigin> FunctionInfo;",
1720         "typedef ::std::vector<FunctionInfo> FunctionInfosList;",
1721         "typedef ::std::map<uint32_t, FunctionInfosList> ApisMap;",
1722         "",
1723         "void initApisMap (ApisMap& apis)",
1724         "{",
1725         "       apis.clear();"] + [
1726         "       apis.insert(::std::pair<uint32_t, FunctionInfosList>(" + str(v) + ", FunctionInfosList()));" for v in api.versions] + [
1727         ""]
1728
1729         apiVersions = []
1730         for index, v in enumerate(api.versions):
1731                 funcs = []
1732                 apiVersions.append("VK_VERSION_{0}_{1}".format(v.major, v.minor))
1733                 # iterate over all functions that are core in latest vulkan version
1734                 # note that first item in api.extension array are actually all definitions that are in vulkan.h.in before section with extensions
1735                 for fun in api.extensions[0].functions:
1736                         if fun.apiVersion in apiVersions:
1737                                 funcs.append('  apis[' + str(v) + '].push_back(FunctionInfo("' + fun.name + '",\t' + functionOriginValues[fun.getType()] + '));')
1738                 lines = lines + [line for line in indentLines(funcs)] + [""]
1739
1740         lines = lines + ["}", ""] + removeVersionDefines(api.versions)
1741         writeInlFile(filename, INL_HEADER, lines)
1742
1743 def writeDeviceFeatures2(api, filename):
1744         # list of structures that should be tested with getPhysicalDeviceFeatures2
1745         # this is not posible to determine from vulkan_core.h, if new feature structures
1746         # are added they should be manualy added to this list
1747         testedStructures = [
1748                 'VkPhysicalDeviceConditionalRenderingFeaturesEXT',
1749                 'VkPhysicalDeviceScalarBlockLayoutFeatures',
1750                 'VkPhysicalDevicePerformanceQueryFeaturesKHR',
1751                 'VkPhysicalDevice16BitStorageFeatures',
1752                 'VkPhysicalDeviceMultiviewFeatures',
1753                 'VkPhysicalDeviceProtectedMemoryFeatures',
1754                 'VkPhysicalDeviceSamplerYcbcrConversionFeatures',
1755                 'VkPhysicalDeviceVariablePointersFeatures',
1756                 'VkPhysicalDevice8BitStorageFeatures',
1757                 'VkPhysicalDeviceShaderAtomicInt64Features',
1758                 'VkPhysicalDeviceShaderFloat16Int8Features',
1759                 'VkPhysicalDeviceBufferDeviceAddressFeaturesEXT',
1760                 'VkPhysicalDeviceBufferDeviceAddressFeatures',
1761                 'VkPhysicalDeviceDescriptorIndexingFeatures',
1762                 'VkPhysicalDeviceTimelineSemaphoreFeatures',
1763                 'VkPhysicalDeviceFragmentDensityMapFeaturesEXT',
1764                 'VkPhysicalDeviceFragmentDensityMap2FeaturesEXT',
1765                 'VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR',
1766         ]
1767         # helper class used to encapsulate all data needed during generation
1768         class StructureDetail:
1769                 def __init__ (self, name):
1770                         nameResult                      = re.search('(.*)Features(.*)', name[len('VkPhysicalDevice'):])
1771                         nameSplitUp                     = ''
1772                         # generate structure type name from structure name
1773                         # note that sometimes digits are separated with '_':
1774                         # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT
1775                         # but mostly they are not:
1776                         # VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES
1777                         if (nameResult.group(1) == 'FragmentDensityMap2'):
1778                                 nameSplitUp             = ['FRAGMENT', 'DENSITY', 'MAP', '2', 'FEATURES']
1779                         else:
1780                                 nameSplit               = re.findall(r'[1-9A-Z]+(?:[a-z1-9]+|[A-Z]*(?=[A-Z]|$))', nameResult.group(1))
1781                                 nameSplitUp             = map(str.upper, nameSplit)
1782                                 nameSplitUp             = list(nameSplitUp) + ['FEATURES']
1783                         # check if there is extension suffix
1784                         if (len(nameResult.group(2)) != 0):
1785                                 nameSplitUp.append(nameResult.group(2))
1786                         self.name                       = name
1787                         self.sType                      = 'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_' + '_'.join(nameSplitUp)
1788                         self.instanceName       = 'd' + name[11:]
1789                         self.flagName           = 'is' + name[16:]
1790                         self.extension          = None
1791                         self.major                      = None
1792                         self.minor                      = None
1793                         self.members            = []
1794         # helper extension class used in algorith below
1795         class StructureFoundContinueToNextOne(Exception):
1796                 pass
1797         testedStructureDetail = [StructureDetail(struct) for struct in testedStructures]
1798         # iterate over all searched structures and find extensions that enable them
1799         for structureDetail in testedStructureDetail:
1800                 try:
1801                         # iterate over all extensions
1802                         for extension in api.extensions[1:]:
1803                                 # check composite types and typedefs in case extension is part of core
1804                                 for structureList in [extension.compositeTypes, extension.typedefs]:
1805                                         # iterate over all structures added by extension
1806                                         for extensionStructure in structureList:
1807                                                 # compare checked structure name to name of structure from extension
1808                                                 if structureDetail.name == extensionStructure.name:
1809                                                         structureDetail.extension = extension.name
1810                                                         if extension.versionInCore is not None:
1811                                                                 structureDetail.major = extension.versionInCore[1]
1812                                                                 structureDetail.minor = extension.versionInCore[2]
1813                                                         raise StructureFoundContinueToNextOne
1814                 except StructureFoundContinueToNextOne:
1815                         continue
1816         for structureDetail in testedStructureDetail:
1817                 for compositeType in api.compositeTypes:
1818                         if structureDetail.name != compositeType.name:
1819                                 continue
1820                         structureMembers = compositeType.members[2:]
1821                         structureDetail.members = [m.name for m in structureMembers]
1822                         if structureDetail.major is not None:
1823                                 break
1824                         # if structure was not added with extension then check if
1825                         # it was added directly with one of vulkan versions
1826                         apiVersion = compositeType.apiVersion
1827                         if apiVersion is None:
1828                                 continue
1829                         structureDetail.major = apiVersion.major
1830                         structureDetail.minor = apiVersion.minor
1831                         break
1832         # generate file content
1833         structureDefinitions = []
1834         featureEnabledFlags = []
1835         clearStructures = []
1836         structureChain = []
1837         logStructures = []
1838         verifyStructures = []
1839         for index, structureDetail in enumerate(testedStructureDetail):
1840                 # create two instances of each structure
1841                 nameSpacing = '\t' * int((55 - len(structureDetail.name)) / 4)
1842                 structureDefinitions.append(structureDetail.name + nameSpacing + structureDetail.instanceName + '[count];')
1843                 # create flags that check if proper extension or vulkan version is available
1844                 condition       = ''
1845                 extension       = structureDetail.extension
1846                 major           = structureDetail.major
1847                 if extension is not None:
1848                         condition = ' checkExtension(properties, "' + extension + '")'
1849                 if major is not None:
1850                         if condition != '':
1851                                 condition += '\t' * int((39 - len(extension)) / 4) + '|| '
1852                         else:
1853                                 condition += '\t' * 17 + '   '
1854                         condition += 'context.contextSupports(vk::ApiVersion(' + str(major) + ', ' + str(structureDetail.minor) + ', 0))'
1855                 condition += ';'
1856                 nameSpacing = '\t' * int((40 - len(structureDetail.flagName)) / 4)
1857                 featureEnabledFlags.append('const bool ' + structureDetail.flagName + nameSpacing + '=' + condition)
1858                 # clear memory of each structure
1859                 nameSpacing = '\t' * int((43 - len(structureDetail.instanceName)) / 4)
1860                 clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx],' + nameSpacing + '0xFF * ndx, sizeof(' + structureDetail.name + '));')
1861                 # construct structure chain
1862                 nextInstanceName = 'DE_NULL';
1863                 if index < len(testedStructureDetail)-1:
1864                         nextInstanceName = '&' + testedStructureDetail[index+1].instanceName + '[ndx]'
1865                 structureChain.append('\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.flagName + ' ? ' + structureDetail.sType + ' : VK_STRUCTURE_TYPE_MAX_ENUM;')
1866                 structureChain.append('\t' + structureDetail.instanceName + '[ndx].pNext = ' + nextInstanceName + ';\n')
1867                 # construct log section
1868                 logStructures.append('if (' + structureDetail.flagName + ')')
1869                 logStructures.append('\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;')
1870                 #construct verification section
1871                 verifyStructures.append('if (' + structureDetail.flagName + ' &&')
1872                 for index, m in enumerate(structureDetail.members):
1873                         prefix = '\t(' if index == 0 else '\t '
1874                         postfix = '))' if index == len(structureDetail.members)-1 else ' ||'
1875                         verifyStructures.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix)
1876                 verifyStructures.append('{\n\t\tTCU_FAIL("Mismatch between ' + structureDetail.name + '");\n}')
1877         # construct file content
1878         stream = []
1879         stream.extend(structureDefinitions)
1880         stream.append('')
1881         stream.extend(featureEnabledFlags)
1882         stream.append('\nfor (int ndx = 0; ndx < count; ++ndx)\n{')
1883         stream.extend(clearStructures)
1884         stream.append('')
1885         stream.extend(structureChain)
1886         stream.append('\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n'
1887                                   '\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n'
1888                                   '\textFeatures.pNext = &' + testedStructureDetail[0].instanceName + '[ndx];\n'
1889                                   '\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);\n}\n')
1890         stream.extend(logStructures)
1891         stream.append('')
1892         stream.extend(verifyStructures)
1893         writeInlFile(filename, INL_HEADER, stream)
1894
1895 def generateDeviceFeaturesDefs(src):
1896         # look for definitions
1897         ptrnSType       = r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_FEATURES(\w*)\s*='
1898         matches         = re.findall(ptrnSType, src, re.M)
1899         matches         = sorted(matches, key=lambda m: m[0])
1900         # construct final list
1901         defs = []
1902         for sType, sSuffix in matches:
1903                 structName                      = re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '')
1904                 ptrnStructName          = r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Features' + sSuffix.replace('_', '') + ')'
1905                 matchStructName         = re.search(ptrnStructName, src, re.IGNORECASE)
1906                 if matchStructName:
1907                         # handle special cases
1908                         if sType == "EXCLUSIVE_SCISSOR":
1909                                 sType = "SCISSOR_EXCLUSIVE"
1910                         elif sType == "ASTC_DECODE":
1911                                 sType = "ASTC_DECODE_MODE"
1912                         if sType in {'VULKAN_1_1', 'VULKAN_1_2'}:
1913                                 continue
1914                         # skip cases that have const pNext pointer
1915                         if sType == 'RASTERIZATION_ORDER_ATTACHMENT_ACCESS':
1916                                 continue
1917                         # end handling special cases
1918                         ptrnExtensionName       = r'^\s*#define\s+(\w+' + sSuffix + '_' + sType + '_EXTENSION_NAME).+$'
1919                         matchExtensionName      = re.search(ptrnExtensionName, src, re.M)
1920                         ptrnSpecVersion         = r'^\s*#define\s+(\w+' + sSuffix + '_' + sType + '_SPEC_VERSION).+$'
1921                         matchSpecVersion        = re.search(ptrnSpecVersion, src, re.M)
1922                         defs.append( (sType, '', sSuffix, matchStructName.group(1), \
1923                                                         matchExtensionName.group(0)     if matchExtensionName   else None,
1924                                                         matchExtensionName.group(1)     if matchExtensionName   else None,
1925                                                         matchSpecVersion.group(1)       if matchSpecVersion             else '0') )
1926         return defs
1927
1928 def generateDevicePropertiesDefs(src):
1929         # look for definitions
1930         ptrnSType       = r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_PROPERTIES(\w*)\s*='
1931         matches         = re.findall(ptrnSType, src, re.M)
1932         matches         = sorted(matches, key=lambda m: m[0])
1933         # construct final list
1934         defs = []
1935         for sType, sSuffix in matches:
1936                 # handle special cases
1937                 if sType in {'VULKAN_1_1', 'VULKAN_1_2', 'GROUP', 'MEMORY_BUDGET', 'MEMORY', 'TOOL'}:
1938                         continue
1939                 # there are cases like VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD
1940                 # where 2 is after PROPERTIES - to handle this we need to split suffix to two parts
1941                 sVerSuffix = ''
1942                 sExtSuffix = sSuffix
1943                 suffixStart = sSuffix.rfind('_')
1944                 if suffixStart > 0:
1945                         sVerSuffix = sSuffix[:suffixStart]
1946                         sExtSuffix = sSuffix[suffixStart:]
1947                 # handle special case
1948                 if sType == "ID":
1949                         structName      = sType
1950                 else:
1951                         structName      = re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '')
1952                 ptrnStructName          = r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Properties' + sSuffix.replace('_', '') + ')'
1953                 matchStructName         = re.search(ptrnStructName, src, re.M)
1954                 if matchStructName:
1955                         extType = sType
1956                         if extType == "DISCARD_RECTANGLE":
1957                                 extType = "DISCARD_RECTANGLES"
1958                         elif extType == "DRIVER":
1959                                 extType = "DRIVER_PROPERTIES"
1960                         elif extType == "POINT_CLIPPING":
1961                                 extType = "MAINTENANCE_2"
1962                         elif extType == "SHADER_CORE":
1963                                 extType = "SHADER_CORE_PROPERTIES"
1964                         elif extType == "DRM":
1965                                 extType = "PHYSICAL_DEVICE_DRM"
1966                         # end handling special cases
1967                         ptrnExtensionName       = r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix +'[_0-9]*_EXTENSION_NAME).+$'
1968                         matchExtensionName      = re.search(ptrnExtensionName, src, re.M)
1969                         ptrnSpecVersion         = r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix + '[_0-9]*_SPEC_VERSION).+$'
1970                         matchSpecVersion        = re.search(ptrnSpecVersion, src, re.M)
1971                         defs.append( (sType, sVerSuffix, sExtSuffix, matchStructName.group(1), \
1972                                                         matchExtensionName.group(0)     if matchExtensionName   else None,
1973                                                         matchExtensionName.group(1)     if matchExtensionName   else None,
1974                                                         matchSpecVersion.group  (1)     if matchSpecVersion             else '0') )
1975         return defs
1976
1977 def writeDeviceFeatures(api, dfDefs, filename):
1978         # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs
1979         # and construct dictionary with all of their attributes
1980         blobMembers = {}
1981         blobStructs = {}
1982         blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$")
1983         for structureType in api.compositeTypes:
1984                 match = blobPattern.match(structureType.name)
1985                 if match:
1986                         allMembers = [member.name for member in structureType.members]
1987                         vkVersion = match.group(1)
1988                         blobMembers[vkVersion] = allMembers[2:]
1989                         blobStructs[vkVersion] = set()
1990         initFromBlobDefinitions = []
1991         emptyInitDefinitions = []
1992         # iterate over all feature structures
1993         allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*")
1994         nonExtFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*$")
1995         for structureType in api.compositeTypes:
1996                 # skip structures that are not feature structures
1997                 if not allFeaturesPattern.match(structureType.name):
1998                         continue
1999                 # skip structures that were previously identified as blobs
2000                 if blobPattern.match(structureType.name):
2001                         continue
2002                 if structureType.isAlias:
2003                         continue
2004                 # skip sType and pNext and just grab third and next attributes
2005                 structureMembers = structureType.members[2:]
2006                 notPartOfBlob = True
2007                 if nonExtFeaturesPattern.match(structureType.name):
2008                         # check if this member is part of any of the blobs
2009                         for blobName, blobMemberList in blobMembers.items():
2010                                 # if just one member is not part of this blob go to the next blob
2011                                 # (we asume that all members are part of blob - no need to check all)
2012                                 if structureMembers[0].name not in blobMemberList:
2013                                         continue
2014                                 # add another feature structure name to this blob
2015                                 blobStructs[blobName].add(structureType)
2016                                 # add specialization for this feature structure
2017                                 memberCopying = ""
2018                                 for member in structureMembers:
2019                                         memberCopying += "\tfeatureType.{0} = allFeaturesBlobs.vk{1}.{0};\n".format(member.name, blobName)
2020                                 wholeFunction = \
2021                                         "template<> void initFeatureFromBlob<{0}>({0}& featureType, const AllFeaturesBlobs& allFeaturesBlobs)\n" \
2022                                         "{{\n" \
2023                                         "{1}" \
2024                                         "}}".format(structureType.name, memberCopying)
2025                                 initFromBlobDefinitions.append(wholeFunction)
2026                                 notPartOfBlob = False
2027                                 # assuming that all members are part of blob, goto next
2028                                 break
2029                 # add empty template definition as on Fedora there are issue with
2030                 # linking using just generic template - all specializations are needed
2031                 if notPartOfBlob:
2032                         emptyFunction = "template<> void initFeatureFromBlob<{0}>({0}&, const AllFeaturesBlobs&) {{}}"
2033                         emptyInitDefinitions.append(emptyFunction.format(structureType.name))
2034         extensionDefines = []
2035         makeFeatureDescDefinitions = []
2036         featureStructWrappers = []
2037         for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extLine, extName, specVer) in enumerate(dfDefs):
2038                 extensionNameDefinition = extName
2039                 if not extensionNameDefinition:
2040                         extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType)
2041                 # construct defines with names
2042                 if extLine:
2043                         extensionDefines.append(extLine)
2044                 else:
2045                         extensionDefines.append('#define {0} "not_existent_feature"'.format(extensionNameDefinition))
2046                 # handle special cases
2047                 if sType == "SCISSOR_EXCLUSIVE":
2048                         sType = "EXCLUSIVE_SCISSOR"
2049                 elif sType == "ASTC_DECODE_MODE":
2050                         sType = "ASTC_DECODE"
2051                 # end handling special cases
2052                 # construct makeFeatureDesc template function definitions
2053                 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sVerSuffix + sExtSuffix)
2054                 makeFeatureDescDefinitions.append("template<> FeatureDesc makeFeatureDesc<{0}>(void) " \
2055                         "{{ return FeatureDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVer, len(dfDefs)-idx))
2056                 # construct CreateFeatureStruct wrapper block
2057                 featureStructWrappers.append("\t{{ createFeatureStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVer))
2058         # construct method that will check if structure sType is part of blob
2059         blobChecker = "bool isPartOfBlobFeatures (VkStructureType sType)\n{\n" \
2060                                   "\tconst std::vector<VkStructureType> sTypeVect =" \
2061                                   "\t{\n"
2062         # iterate over blobs with list of structures
2063         for blobName in sorted(blobStructs.keys()):
2064                 blobChecker += "\t\t// Vulkan{0}\n".format(blobName)
2065                 # iterate over all feature structures in current blob
2066                 structuresList = list(blobStructs[blobName])
2067                 structuresList = sorted(structuresList, key=lambda s: s.name)
2068                 for structType in structuresList:
2069                         # find definition of this structure in dfDefs
2070                         structName = structType.name
2071                         # handle special cases
2072                         if structName == 'VkPhysicalDeviceShaderDrawParameterFeatures':
2073                                 structName = 'VkPhysicalDeviceShaderDrawParametersFeatures'
2074                         # end handling special cases
2075                         structDef = [s for s in dfDefs if s[3] == structName][0]
2076                         sType = structDef[0]
2077                         sSuffix = structDef[1] + structDef[2]
2078                         # handle special cases
2079                         if sType == "SCISSOR_EXCLUSIVE":
2080                                 sType = "EXCLUSIVE_SCISSOR"
2081                         # end handling special cases
2082                         sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix)
2083                         blobChecker += "\t\t{0},\n".format(sTypeName)
2084         blobChecker += "\t};\n" \
2085                                    "\treturn de::contains(sTypeVect.begin(), sTypeVect.end(), sType);\n" \
2086                                    "}\n"
2087         # combine all definition lists
2088         stream = [
2089         '#include "vkDeviceFeatures.hpp"\n',
2090         'namespace vk\n{']
2091         stream.extend(extensionDefines)
2092         stream.append('\n')
2093         stream.extend(initFromBlobDefinitions)
2094         stream.append('\n// generic template is not enough for some compilers')
2095         stream.extend(emptyInitDefinitions)
2096         stream.append('\n')
2097         stream.extend(makeFeatureDescDefinitions)
2098         stream.append('\n')
2099         stream.append('static const FeatureStructCreationData featureStructCreationArray[] =\n{')
2100         stream.extend(featureStructWrappers)
2101         stream.append('};\n')
2102         stream.append(blobChecker)
2103         stream.append('} // vk\n')
2104         writeInlFile(filename, INL_HEADER, stream)
2105
2106 def writeDeviceFeatureTest(api, filename):
2107
2108         coreFeaturesPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$")
2109         featureItems = []
2110         # iterate over all feature structures
2111         allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*")
2112         for structureType in api.compositeTypes:
2113                 # skip structures that are not feature structures
2114                 if not allFeaturesPattern.match(structureType.name):
2115                         continue
2116                 # skip alias structures
2117                 if structureType.isAlias:
2118                         continue
2119                 # skip sType and pNext and just grab third and next attributes
2120                 structureMembers = structureType.members[2:]
2121
2122                 items = []
2123                 for member in structureMembers:
2124                         items.append("          FEATURE_ITEM ({0}, {1}),".format(structureType.name, member.name))
2125
2126                 testBlock = \
2127                         "if (const void* featuresStruct = findStructureInChain(const_cast<const void*>(deviceFeatures2.pNext), getStructureType<{0}>()))\n" \
2128                         "{{\n" \
2129                         "       static const Feature features[] =\n" \
2130                         "       {{\n" \
2131                         "{1}\n" \
2132                         "       }};\n" \
2133                         "       auto* supportedFeatures = reinterpret_cast<const {0}*>(featuresStruct);\n" \
2134                         "       checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures);\n" \
2135                         "}}\n"
2136                 featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("DE_NULL" if coreFeaturesPattern.match(structureType.name) else "&extensionNames")))
2137
2138         stream = ['']
2139         stream.extend(featureItems)
2140         writeInlFile(filename, INL_HEADER, stream)
2141
2142 def writeDeviceProperties(api, dpDefs, filename):
2143         # find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs
2144         # and construct dictionary with all of their attributes
2145         blobMembers = {}
2146         blobStructs = {}
2147         blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Properties[0-9]*$")
2148         for structureType in api.compositeTypes:
2149                 match = blobPattern.match(structureType.name)
2150                 if match:
2151                         allMembers = [member.name for member in structureType.members]
2152                         vkVersion = match.group(1)
2153                         blobMembers[vkVersion] = allMembers[2:]
2154                         blobStructs[vkVersion] = set()
2155         initFromBlobDefinitions = []
2156         emptyInitDefinitions = []
2157         # iterate over all property structures
2158         allPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*")
2159         nonExtPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*$")
2160         for structureType in api.compositeTypes:
2161                 # skip structures that are not property structures
2162                 if not allPropertiesPattern.match(structureType.name):
2163                         continue
2164                 # skip structures that were previously identified as blobs
2165                 if blobPattern.match(structureType.name):
2166                         continue
2167                 if structureType.isAlias:
2168                         continue
2169                 # skip sType and pNext and just grab third and next attributes
2170                 structureMembers = structureType.members[2:]
2171                 notPartOfBlob = True
2172                 if nonExtPropertiesPattern.match(structureType.name):
2173                         # check if this member is part of any of the blobs
2174                         for blobName, blobMemberList in blobMembers.items():
2175                                 # if just one member is not part of this blob go to the next blob
2176                                 # (we asume that all members are part of blob - no need to check all)
2177                                 if structureMembers[0].name not in blobMemberList:
2178                                         continue
2179                                 # add another property structure name to this blob
2180                                 blobStructs[blobName].add(structureType)
2181                                 # add specialization for this property structure
2182                                 memberCopying = ""
2183                                 for member in structureMembers:
2184                                         if not member.arraySize:
2185                                                 # handle special case
2186                                                 if structureType.name == "VkPhysicalDeviceSubgroupProperties" and "subgroup" not in member.name :
2187                                                         blobMemberName = "subgroup" + member.name[0].capitalize() + member.name[1:]
2188                                                         memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{2};\n".format(member.name, blobName, blobMemberName)
2189                                                 # end handling special case
2190                                                 else:
2191                                                         memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{0};\n".format(member.name, blobName)
2192                                         else:
2193                                                 memberCopying += "\tmemcpy(propertyType.{0}, allPropertiesBlobs.vk{1}.{0}, sizeof({2}) * {3});\n".format(member.name, blobName, member.type[0], member.arraySize[1:-1])
2194                                 wholeFunction = \
2195                                         "template<> void initPropertyFromBlob<{0}>({0}& propertyType, const AllPropertiesBlobs& allPropertiesBlobs)\n" \
2196                                         "{{\n" \
2197                                         "{1}" \
2198                                         "}}".format(structureType.name, memberCopying)
2199                                 initFromBlobDefinitions.append(wholeFunction)
2200                                 notPartOfBlob = False
2201                                 # assuming that all members are part of blob, goto next
2202                                 break
2203                 # add empty template definition as on Fedora there are issue with
2204                 # linking using just generic template - all specializations are needed
2205                 if notPartOfBlob:
2206                         emptyFunction = "template<> void initPropertyFromBlob<{0}>({0}&, const AllPropertiesBlobs&) {{}}"
2207                         emptyInitDefinitions.append(emptyFunction.format(structureType.name))
2208         extensionDefines = []
2209         makePropertyDescDefinitions = []
2210         propertyStructWrappers = []
2211         for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extLine, extName, specVer) in enumerate(dpDefs):
2212                 extensionNameDefinition = extName
2213                 if not extensionNameDefinition:
2214                         extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType)
2215                 # construct defines with names
2216                 if extLine:
2217                         extensionDefines.append(extLine)
2218                 else:
2219                         extensionDefines.append('#define {0} "core_property"'.format(extensionNameDefinition))
2220                 # construct makePropertyDesc template function definitions
2221                 sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sVerSuffix + sExtSuffix)
2222                 makePropertyDescDefinitions.append("template<> PropertyDesc makePropertyDesc<{0}>(void) " \
2223                         "{{ return PropertyDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVer, len(dpDefs)-idx))
2224                 # construct CreateProperty struct wrapper block
2225                 propertyStructWrappers.append("\t{{ createPropertyStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVer))
2226                         # construct method that will check if structure sType is part of blob
2227         blobChecker = "bool isPartOfBlobProperties (VkStructureType sType)\n{\n" \
2228                                   "\tconst std::vector<VkStructureType> sTypeVect =" \
2229                                   "\t{\n"
2230         # iterate over blobs with list of structures
2231         for blobName in sorted(blobStructs.keys()):
2232                 blobChecker += "\t\t// Vulkan{0}\n".format(blobName)
2233                 # iterate over all feature structures in current blob
2234                 structuresList = list(blobStructs[blobName])
2235                 structuresList = sorted(structuresList, key=lambda s: s.name)
2236                 for structType in structuresList:
2237                         # find definition of this structure in dpDefs
2238                         structName = structType.name
2239                         structDef = [s for s in dpDefs if s[3] == structName][0]
2240                         sType = structDef[0]
2241                         sSuffix = structDef[1] + structDef[2]
2242                         sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sSuffix)
2243                         blobChecker += "\t\t{0},\n".format(sTypeName)
2244         blobChecker += "\t};\n" \
2245                                    "\treturn de::contains(sTypeVect.begin(), sTypeVect.end(), sType);\n" \
2246                                    "}\n"
2247         # combine all definition lists
2248         stream = [
2249         '#include "vkDeviceProperties.hpp"\n',
2250         'namespace vk\n{']
2251         stream.extend(extensionDefines)
2252         stream.append('\n')
2253         stream.extend(initFromBlobDefinitions)
2254         stream.append('\n// generic template is not enough for some compilers')
2255         stream.extend(emptyInitDefinitions)
2256         stream.append('\n')
2257         stream.extend(makePropertyDescDefinitions)
2258         stream.append('\n')
2259         stream.append('static const PropertyStructCreationData propertyStructCreationArray[] =\n{')
2260         stream.extend(propertyStructWrappers)
2261         stream.append('};\n')
2262         stream.append(blobChecker)
2263         stream.append('} // vk\n')
2264         writeInlFile(filename, INL_HEADER, stream)
2265
2266 def genericDeviceFeaturesWriter(dfDefs, pattern, filename):
2267         stream = []
2268         for _, _, _, extStruct, _, _, _ in dfDefs:
2269                 nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "")
2270                 stream.append(pattern.format(extStruct, nameSubStr))
2271         writeInlFile(filename, INL_HEADER, indentLines(stream))
2272
2273 def writeDeviceFeaturesDefaultDeviceDefs(dfDefs, filename):
2274         pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceFeatures.getFeatureType<{0}>();\t}}"
2275         genericDeviceFeaturesWriter(dfDefs, pattern, filename)
2276
2277 def writeDeviceFeaturesContextDecl(dfDefs, filename):
2278         pattern = "const vk::{0}&\tget{1}\t(void) const;"
2279         genericDeviceFeaturesWriter(dfDefs, pattern, filename)
2280
2281 def writeDeviceFeaturesContextDefs(dfDefs, filename):
2282         pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}"
2283         genericDeviceFeaturesWriter(dfDefs, pattern, filename)
2284
2285 def genericDevicePropertiesWriter(dfDefs, pattern, filename):
2286         stream = []
2287         for _, _, _, extStruct, _, _, _ in dfDefs:
2288                 nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "")
2289                 if extStruct == "VkPhysicalDeviceRayTracingPropertiesNV":
2290                         nameSubStr += "NV"
2291                 stream.append(pattern.format(extStruct, nameSubStr))
2292         writeInlFile(filename, INL_HEADER, indentLines(stream))
2293
2294 def writeDevicePropertiesDefaultDeviceDefs(dfDefs, filename):
2295         pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceProperties.getPropertyType<{0}>();\t}}"
2296         genericDevicePropertiesWriter(dfDefs, pattern, filename)
2297
2298 def writeDevicePropertiesContextDecl(dfDefs, filename):
2299         pattern = "const vk::{0}&\tget{1}\t(void) const;"
2300         genericDevicePropertiesWriter(dfDefs, pattern, filename)
2301
2302 def writeDevicePropertiesContextDefs(dfDefs, filename):
2303         pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}"
2304         genericDevicePropertiesWriter(dfDefs, pattern, filename)
2305
2306 def writeMandatoryFeatures(api, filename):
2307         stream = []
2308
2309         dictStructs = {}
2310         dictData = []
2311         for _, data in api.additionalExtensionData:
2312                 if 'mandatory_features' not in data.keys():
2313                         continue
2314                 # sort to have same results for py2 and py3
2315                 listStructFeatures = sorted(data['mandatory_features'].items(), key=lambda tup: tup[0])
2316                 for structure, featuresList in listStructFeatures:
2317                         for featureData in featuresList:
2318                                 assert('features' in featureData.keys())
2319                                 assert('requirements' in featureData.keys())
2320                                 requirements = featureData['requirements']
2321                                 dictData.append( [ structure, featureData['features'], requirements ])
2322                                 if structure == 'VkPhysicalDeviceFeatures':
2323                                         continue
2324                                 # if structure is not in dict construct name of variable and add is as a first item
2325                                 if (structure not in dictStructs):
2326                                         dictStructs[structure] = [structure[2:3].lower() + structure[3:]]
2327                                 # add first requirement if it is unique
2328                                 if requirements and (requirements[0] not in dictStructs[structure]):
2329                                         dictStructs[structure].append(requirements[0])
2330
2331         stream.extend(['bool checkMandatoryFeatures(const vkt::Context& context)\n{',
2332                                    '\tif (!context.isInstanceFunctionalitySupported("VK_KHR_get_physical_device_properties2"))',
2333                                    '\t\tTCU_THROW(NotSupportedError, "Extension VK_KHR_get_physical_device_properties2 is not present");',
2334                                    '',
2335                                    '\tVkPhysicalDevice\t\t\t\t\tphysicalDevice\t\t= context.getPhysicalDevice();',
2336                                    '\tconst InstanceInterface&\t\t\tvki\t\t\t\t\t= context.getInstanceInterface();',
2337                                    '\tconst vector<VkExtensionProperties>\tdeviceExtensions\t= enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL);',
2338                                    '',
2339                                    '\ttcu::TestLog& log = context.getTestContext().getLog();',
2340                                    '\tvk::VkPhysicalDeviceFeatures2 coreFeatures;',
2341                                    '\tdeMemset(&coreFeatures, 0, sizeof(coreFeatures));',
2342                                    '\tcoreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;',
2343                                    '\tvoid** nextPtr = &coreFeatures.pNext;',
2344                                    ''])
2345
2346         listStruct = sorted(dictStructs.items(), key=lambda tup: tup[0]) # sort to have same results for py2 and py3
2347         for k, v in listStruct:
2348                 if (v[1].startswith("ApiVersion")):
2349                         cond = '\tif (context.contextSupports(vk::' + v[1] + '))'
2350                 else:
2351                         cond = '\tif (vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "' + v[1] + '"))'
2352                 stream.extend(['\tvk::' + k + ' ' + v[0]+ ';',
2353                                         '\tdeMemset(&' + v[0] + ', 0, sizeof(' + v[0] + '));',
2354                                         ''])
2355                 reqs = v[1:]
2356                 if len(reqs) > 0 :
2357                         cond = 'if ( '
2358                         for i, req in enumerate(reqs) :
2359                                 if (req.startswith("ApiVersion")):
2360                                         cond = cond + 'context.contextSupports(vk::' + req + ')'
2361                                 else:
2362                                         cond = cond + 'isExtensionSupported(deviceExtensions, RequiredExtension("' + req + '"))'
2363                                 if i+1 < len(reqs) :
2364                                         cond = cond + ' || '
2365                         cond = cond + ' )'
2366                         stream.append('\t' + cond)
2367                 stream.extend(['\t{',
2368                                            '\t\t' + v[0] + '.sType = getStructureType<' + k + '>();',
2369                                            '\t\t*nextPtr = &' + v[0] + ';',
2370                                            '\t\tnextPtr  = &' + v[0] + '.pNext;',
2371                                            '\t}',
2372                                            ''])
2373         stream.extend(['\tcontext.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &coreFeatures);',
2374                                    '\tbool result = true;',
2375                                    ''])
2376
2377         for v in dictData:
2378                 structType = v[0];
2379                 structName = 'coreFeatures.features';
2380                 if v[0] != 'VkPhysicalDeviceFeatures' :
2381                         structName = dictStructs[v[0]][0]
2382                 if len(v[2]) > 0 :
2383                         condition = 'if ( '
2384                         for i, req in enumerate(v[2]) :
2385                                 if (req.startswith("ApiVersion")):
2386                                         condition = condition + 'context.contextSupports(vk::' + req + ')'
2387                                 elif '.' in req:
2388                                         condition = condition + req
2389                                 else:
2390                                         condition = condition + 'isExtensionSupported(deviceExtensions, RequiredExtension("' + req + '"))'
2391                                 if i+1 < len(v[2]) :
2392                                         condition = condition + ' && '
2393                         condition = condition + ' )'
2394                         stream.append('\t' + condition)
2395                 stream.append('\t{')
2396                 # Don't need to support an AND case since that would just be another line in the .txt
2397                 if len(v[1]) == 1:
2398                         stream.append('\t\tif ( ' + structName + '.' + v[1][0] + ' == VK_FALSE )')
2399                 else:
2400                         condition = 'if ( '
2401                         for i, feature in enumerate(v[1]):
2402                                 if i != 0:
2403                                         condition = condition + ' && '
2404                                 condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )'
2405                         condition = condition + ' )'
2406                         stream.append('\t\t' + condition)
2407                 featureSet = " or ".join(v[1])
2408                 stream.extend(['\t\t{',
2409                                            '\t\t\tlog << tcu::TestLog::Message << "Mandatory feature ' + featureSet + ' not supported" << tcu::TestLog::EndMessage;',
2410                                            '\t\t\tresult = false;',
2411                                            '\t\t}',
2412                                            '\t}',
2413                                            ''])
2414         stream.append('\treturn result;')
2415         stream.append('}\n')
2416         writeInlFile(filename, INL_HEADER, stream)
2417
2418 def writeExtensionList(api, filename, extensionType):
2419         extensionList = []
2420         for extensionName, data in api.additionalExtensionData:
2421                 # make sure extension name starts with VK_KHR
2422                 if not extensionName.startswith('VK_KHR'):
2423                         continue
2424                 # make sure that this extension was registered
2425                 if 'register_extension' not in data.keys():
2426                         continue
2427                 # make sure extension has proper type
2428                 if extensionType == data['register_extension']['type']:
2429                         extensionList.append(extensionName)
2430         extensionList.sort()
2431         # write list of all found extensions
2432         stream = []
2433         stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(extensionType.title()))
2434         for n in extensionList:
2435                 stream.append('\t"' + n + '",')
2436         stream.append('};\n')
2437         writeInlFile(filename, INL_HEADER, stream)
2438
2439 def preprocessTopInclude(src, dir):
2440         pattern = r'#include\s+"([^\n]+)"'
2441         while True:
2442                 inc = re.search(pattern, src)
2443                 if inc is None:
2444                         return src
2445                 incFileName = inc.string[inc.start(1):inc.end(1)]
2446                 patternIncNamed = r'#include\s+"' + incFileName + '"'
2447                 incBody = readFile(os.path.join(dir, incFileName)) if incFileName != 'vk_platform.h' else ''
2448                 incBodySanitized = re.sub(pattern, '', incBody)
2449                 bodyEndSanitized = re.sub(patternIncNamed, '', src[inc.end(0):])
2450                 src = src[0:inc.start(0)] + incBodySanitized + bodyEndSanitized
2451         return src
2452
2453 if __name__ == "__main__":
2454
2455         outputPath = os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan")
2456         # if argument was specified it is interpreted as a path to which .inl files will be written
2457         if len(sys.argv) > 1:
2458                 outputPath = str(sys.argv[1])
2459
2460         # Generate vulkan headers from vk.xml
2461         currentDir                      = os.getcwd()
2462         pythonExecutable        = sys.executable or "python"
2463         os.chdir(os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "..", "xml"))
2464         targets = [
2465                 "vulkan_android.h",
2466                 "vulkan_beta.h",
2467                 "vulkan_core.h",
2468                 "vulkan_fuchsia.h",
2469                 "vulkan_ggp.h",
2470                 "vulkan_ios.h",
2471                 "vulkan_macos.h",
2472                 "vulkan_metal.h",
2473                 "vulkan_vi.h",
2474                 "vulkan_wayland.h",
2475                 "vulkan_win32.h",
2476                 "vulkan_xcb.h",
2477                 "vulkan_xlib.h",
2478                 "vulkan_xlib_xrandr.h",
2479         ]
2480         for target in targets:
2481                 execute([pythonExecutable, "../scripts/genvk.py", "-o", "../include/vulkan", target])
2482         os.chdir(currentDir)
2483
2484         # Read all .h files and make sure vulkan_core.h is first out of vulkan files
2485         targets.remove("vulkan_core.h")
2486         targets.sort()
2487         vkFilesWithCatalog =  [os.path.join("vulkan", f) for f in targets]
2488         first = [os.path.join("vk_video", "vulkan_video_codecs_common.h"), os.path.join("vulkan", "vulkan_core.h")]
2489         allFilesWithCatalog = first + vkFilesWithCatalog
2490
2491         src = ""
2492         for file in allFilesWithCatalog:
2493                 src += preprocessTopInclude(readFile(os.path.join(VULKAN_HEADERS_INCLUDE_DIR,file)), VULKAN_HEADERS_INCLUDE_DIR)
2494
2495         src = re.sub('\s*//[^\n]*', '', src)
2496         src = re.sub('\n\n', '\n', src)
2497
2498         api                             = parseAPI(src)
2499
2500         platformFuncs   = [Function.TYPE_PLATFORM]
2501         instanceFuncs   = [Function.TYPE_INSTANCE]
2502         deviceFuncs             = [Function.TYPE_DEVICE]
2503
2504         dfd                                                                             = generateDeviceFeaturesDefs(src)
2505         writeDeviceFeatures                                             (api, dfd, os.path.join(outputPath, "vkDeviceFeatures.inl"))
2506         writeDeviceFeaturesDefaultDeviceDefs    (dfd, os.path.join(outputPath, "vkDeviceFeaturesForDefaultDeviceDefs.inl"))
2507         writeDeviceFeaturesContextDecl                  (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDecl.inl"))
2508         writeDeviceFeaturesContextDefs                  (dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDefs.inl"))
2509         writeDeviceFeatureTest                                  (api, os.path.join(outputPath, "vkDeviceFeatureTest.inl"))
2510
2511         dpd                                                                             = generateDevicePropertiesDefs(src)
2512         writeDeviceProperties                                   (api, dpd, os.path.join(outputPath, "vkDeviceProperties.inl"))
2513
2514         writeDevicePropertiesDefaultDeviceDefs  (dpd, os.path.join(outputPath, "vkDevicePropertiesForDefaultDeviceDefs.inl"))
2515         writeDevicePropertiesContextDecl                (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDecl.inl"))
2516         writeDevicePropertiesContextDefs                (dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDefs.inl"))
2517
2518         writeHandleType                                                 (api, os.path.join(outputPath, "vkHandleType.inl"))
2519         writeBasicTypes                                                 (api, os.path.join(outputPath, "vkBasicTypes.inl"))
2520         writeCompositeTypes                                             (api, os.path.join(outputPath, "vkStructTypes.inl"))
2521         writeInterfaceDecl                                              (api, os.path.join(outputPath, "vkVirtualPlatformInterface.inl"),               platformFuncs,  False)
2522         writeInterfaceDecl                                              (api, os.path.join(outputPath, "vkVirtualInstanceInterface.inl"),               instanceFuncs,  False)
2523         writeInterfaceDecl                                              (api, os.path.join(outputPath, "vkVirtualDeviceInterface.inl"),                 deviceFuncs,    False)
2524         writeInterfaceDecl                                              (api, os.path.join(outputPath, "vkConcretePlatformInterface.inl"),              platformFuncs,  True)
2525         writeInterfaceDecl                                              (api, os.path.join(outputPath, "vkConcreteInstanceInterface.inl"),              instanceFuncs,  True)
2526         writeInterfaceDecl                                              (api, os.path.join(outputPath, "vkConcreteDeviceInterface.inl"),                deviceFuncs,    True)
2527         writeFunctionPtrTypes                                   (api, os.path.join(outputPath, "vkFunctionPointerTypes.inl"))
2528         writeFunctionPointers                                   (api, os.path.join(outputPath, "vkPlatformFunctionPointers.inl"),               platformFuncs)
2529         writeFunctionPointers                                   (api, os.path.join(outputPath, "vkInstanceFunctionPointers.inl"),               instanceFuncs)
2530         writeFunctionPointers                                   (api, os.path.join(outputPath, "vkDeviceFunctionPointers.inl"),                 deviceFuncs)
2531         writeInitFunctionPointers                               (api, os.path.join(outputPath, "vkInitPlatformFunctionPointers.inl"),   platformFuncs,  lambda f: f.name != "vkGetInstanceProcAddr")
2532         writeInitFunctionPointers                               (api, os.path.join(outputPath, "vkInitInstanceFunctionPointers.inl"),   instanceFuncs)
2533         writeInitFunctionPointers                               (api, os.path.join(outputPath, "vkInitDeviceFunctionPointers.inl"),             deviceFuncs)
2534         writeFuncPtrInterfaceImpl                               (api, os.path.join(outputPath, "vkPlatformDriverImpl.inl"),                             platformFuncs,  "PlatformDriver")
2535         writeFuncPtrInterfaceImpl                               (api, os.path.join(outputPath, "vkInstanceDriverImpl.inl"),                             instanceFuncs,  "InstanceDriver")
2536         writeFuncPtrInterfaceImpl                               (api, os.path.join(outputPath, "vkDeviceDriverImpl.inl"),                               deviceFuncs,    "DeviceDriver")
2537         writeStrUtilProto                                               (api, os.path.join(outputPath, "vkStrUtil.inl"))
2538         writeStrUtilImpl                                                (api, os.path.join(outputPath, "vkStrUtilImpl.inl"))
2539         writeRefUtilProto                                               (api, os.path.join(outputPath, "vkRefUtil.inl"))
2540         writeRefUtilImpl                                                (api, os.path.join(outputPath, "vkRefUtilImpl.inl"))
2541         writeStructTraitsImpl                                   (api, os.path.join(outputPath, "vkGetStructureTypeImpl.inl"))
2542         writeNullDriverImpl                                             (api, os.path.join(outputPath, "vkNullDriverImpl.inl"))
2543         writeTypeUtil                                                   (api, os.path.join(outputPath, "vkTypeUtil.inl"))
2544         writeSupportedExtenions                                 (api, os.path.join(outputPath, "vkSupportedExtensions.inl"))
2545         writeCoreFunctionalities                                (api, os.path.join(outputPath, "vkCoreFunctionalities.inl"))
2546         writeExtensionFunctions                                 (api, os.path.join(outputPath, "vkExtensionFunctions.inl"))
2547         writeDeviceFeatures2                                    (api, os.path.join(outputPath, "vkDeviceFeatures2.inl"))
2548         writeMandatoryFeatures                                  (api, os.path.join(outputPath, "vkMandatoryFeatures.inl"))
2549         writeExtensionList                                              (api, os.path.join(outputPath, "vkInstanceExtensions.inl"),                             'instance')
2550         writeExtensionList                                              (api, os.path.join(outputPath, "vkDeviceExtensions.inl"),                               'device')
2551         writeDriverIds                                                  (     os.path.join(outputPath, "vkKnownDriverIds.inl"))
2552         writeObjTypeImpl                                                (api, os.path.join(outputPath, "vkObjTypeImpl.inl"))
2553         # NOTE: when new files are generated then they should also be added to the
2554         # vk-gl-cts\external\vulkancts\framework\vulkan\CMakeLists.txt outputs list