• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
23import os
24import re
25import sys
26import copy
27import glob
28import json
29import argparse
30from itertools import chain
31from collections import OrderedDict
32
33scriptPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts")
34sys.path.insert(0, scriptPath)
35
36from ctsbuild.common import DEQP_DIR, execute
37from khr_util.format import indentLines, writeInlFile
38
39VULKAN_HEADERS_INCLUDE_DIR	= os.path.join(os.path.dirname(__file__), "..", "..", "vulkan-docs", "src", "include")
40SCRIPTS_SRC_DIR				= os.path.join(os.path.dirname(__file__), "src")
41DEFAULT_OUTPUT_DIR			= { "" :	os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkan"),
42								"SC" :	os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "generated", "vulkansc") }
43
44INL_HEADER = """\
45/* WARNING: This is auto-generated file. Do not modify, since changes will
46 * be lost! Modify the generating script instead.
47 * This file was generated by /scripts/gen_framework.py
48 */\
49
50"""
51
52DEFINITIONS			= [
53	("VK_MAX_PHYSICAL_DEVICE_NAME_SIZE",	"size_t"),
54	("VK_MAX_EXTENSION_NAME_SIZE",			"size_t"),
55	("VK_MAX_DRIVER_NAME_SIZE",				"size_t"),
56	("VK_MAX_DRIVER_INFO_SIZE",				"size_t"),
57	("VK_UUID_SIZE",						"size_t"),
58	("VK_LUID_SIZE",						"size_t"),
59	("VK_MAX_MEMORY_TYPES",					"size_t"),
60	("VK_MAX_MEMORY_HEAPS",					"size_t"),
61	("VK_MAX_DESCRIPTION_SIZE",				"size_t"),
62	("VK_MAX_DEVICE_GROUP_SIZE",			"size_t"),
63	("VK_ATTACHMENT_UNUSED",				"uint32_t"),
64	("VK_SUBPASS_EXTERNAL",					"uint32_t"),
65	("VK_QUEUE_FAMILY_IGNORED",				"uint32_t"),
66	("VK_QUEUE_FAMILY_EXTERNAL",			"uint32_t"),
67	("VK_REMAINING_MIP_LEVELS",				"uint32_t"),
68	("VK_REMAINING_ARRAY_LAYERS",			"uint32_t"),
69	("VK_WHOLE_SIZE",						"vk::VkDeviceSize"),
70	("VK_TRUE",								"vk::VkBool32"),
71	("VK_FALSE",							"vk::VkBool32"),
72]
73
74PLATFORM_TYPES		= [
75	# VK_KHR_xlib_surface
76	(["Display","*"],						["XlibDisplayPtr"],				"void*"),
77	(["Window"],							["XlibWindow"],					"uintptr_t",),
78	(["VisualID"],							["XlibVisualID"],				"uint32_t"),
79
80	# VK_KHR_xcb_surface
81	(["xcb_connection_t", "*"],				["XcbConnectionPtr"],			"void*"),
82	(["xcb_window_t"],						["XcbWindow"],					"uintptr_t"),
83	(["xcb_visualid_t"],					["XcbVisualid"],				"uint32_t"),
84
85	# VK_KHR_wayland_surface
86	(["struct", "wl_display","*"],			["WaylandDisplayPtr"],			"void*"),
87	(["struct", "wl_surface", "*"],			["WaylandSurfacePtr"],			"void*"),
88
89	# VK_KHR_mir_surface
90	(["MirConnection", "*"],				["MirConnectionPtr"],			"void*"),
91	(["MirSurface", "*"],					["MirSurfacePtr"],				"void*"),
92
93	# VK_KHR_android_surface
94	(["ANativeWindow", "*"],				["AndroidNativeWindowPtr"],		"void*"),
95
96	# VK_KHR_win32_surface
97	(["HINSTANCE"],							["Win32InstanceHandle"],		"void*"),
98	(["HWND"],								["Win32WindowHandle"],			"void*"),
99	(["HANDLE"],							["Win32Handle"],				"void*"),
100	(["const", "SECURITY_ATTRIBUTES", "*"],	["Win32SecurityAttributesPtr"],	"const void*"),
101	(["AHardwareBuffer", "*"],				["AndroidHardwareBufferPtr"],	"void*"),
102	(["HMONITOR"],							["Win32MonitorHandle"],			"void*"),
103	(["LPCWSTR"],							["Win32LPCWSTR"],				"const void*"),
104
105	# VK_EXT_acquire_xlib_display
106	(["RROutput"],							["RROutput"],					"void*"),
107
108	(["zx_handle_t"],						["zx_handle_t"],				"uint32_t"),
109	(["GgpFrameToken"],						["GgpFrameToken"],				"int32_t"),
110	(["GgpStreamDescriptor"],				["GgpStreamDescriptor"],		"int32_t"),
111	(["CAMetalLayer"],						["CAMetalLayer"],				"void*"),
112
113	# VK_EXT_metal_objects
114	(["MTLDevice_id"],						["MTLDevice_id"],				"void*"),
115	(["MTLCommandQueue_id"],				["MTLCommandQueue_id"],			"void*"),
116	(["MTLBuffer_id"],						["MTLBuffer_id"],				"void*"),
117	(["MTLTexture_id"],						["MTLTexture_id"],				"void*"),
118	(["IOSurfaceRef"],						["IOSurfaceRef"],				"void*"),
119	(["MTLSharedEvent_id"],					["MTLSharedEvent_id"],			"void*"),
120
121    # VK_NV_external_sci_sync / VK_NV_external_sci_sync2 / VK_NV_external_memory_sci_buf
122    (["NvSciSyncAttrList"],                 ["NvSciSyncAttrList"],          "int32_t"),
123    (["NvSciSyncObj"],                      ["NvSciSyncObj"],               "int32_t"),
124    (["NvSciSyncFence"],                    ["NvSciSyncFence"],             "int32_t"),
125    (["NvSciBufAttrList"],                  ["NvSciBufAttrList"],           "int32_t"),
126    (["NvSciBufObj"],                       ["NvSciBufObj"],                "int32_t"),
127]
128
129PLATFORM_TYPE_NAMESPACE	= "pt"
130
131TYPE_SUBSTITUTIONS		= [
132	# Platform-specific
133	("DWORD",		"uint32_t"),
134	("HANDLE*",		PLATFORM_TYPE_NAMESPACE + "::" + "Win32Handle*"),
135]
136
137EXTENSION_POSTFIXES				= ["KHR", "EXT", "NV", "NVX", "KHX", "NN", "MVK", "FUCHSIA", "GGP", "AMD", "QNX", "LUNARG"]
138EXTENSION_POSTFIXES_STANDARD	= ["KHR", "EXT"]
139
140def prefixName (prefix, name):
141	name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name[2:])
142	name = re.sub(r'([a-zA-Z])([0-9])', r'\1_\2', name)
143	name = name.upper()
144
145	name = name.replace("YCB_CR_", "YCBCR_")
146	name = name.replace("WIN_32_", "WIN32_")
147	name = name.replace("8_BIT_", "8BIT_")
148	name = name.replace("16_BIT_", "16BIT_")
149	name = name.replace("INT_64_", "INT64_")
150	name = name.replace("D_3_D_12_", "D3D12_")
151	name = name.replace("IOSSURFACE_", "IOS_SURFACE_")
152	name = name.replace("MAC_OS", "MACOS_")
153	name = name.replace("TEXTURE_LOD", "TEXTURE_LOD_")
154	name = name.replace("VIEWPORT_W", "VIEWPORT_W_")
155	name = name.replace("_IDPROPERTIES", "_ID_PROPERTIES")
156	name = name.replace("PHYSICAL_DEVICE_SHADER_FLOAT_16_INT_8_FEATURES", "PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES")
157	name = name.replace("PHYSICAL_DEVICE_RGBA_10_X_6_FORMATS_FEATURES_EXT", "PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT")
158	name = name.replace("_PCIBUS_", "_PCI_BUS_")
159	name = name.replace("ASTCD", "ASTC_D")
160	name = name.replace("AABBNV", "AABB_NV")
161	name = name.replace("IMAGE_PIPE", "IMAGEPIPE")
162	name = name.replace("SMBUILTINS", "SM_BUILTINS")
163	name = name.replace("ASTCHDRFEATURES", "ASTC_HDR_FEATURES")
164	name = name.replace("UINT_8", "UINT8")
165	name = name.replace("VULKAN_11_FEATURES", "VULKAN_1_1_FEATURES")
166	name = name.replace("VULKAN_11_PROPERTIES", "VULKAN_1_1_PROPERTIES")
167	name = name.replace("VULKAN_12_FEATURES", "VULKAN_1_2_FEATURES")
168	name = name.replace("VULKAN_12_PROPERTIES", "VULKAN_1_2_PROPERTIES")
169	name = name.replace("VULKAN_13_FEATURES", "VULKAN_1_3_FEATURES")
170	name = name.replace("VULKAN_13_PROPERTIES", "VULKAN_1_3_PROPERTIES")
171	name = name.replace("VULKAN_SC_10_FEATURES", "VULKAN_SC_1_0_FEATURES")
172	name = name.replace("VULKAN_SC_10_PROPERTIES", "VULKAN_SC_1_0_PROPERTIES")
173	name = name.replace("INT_8_", "INT8_")
174	name = name.replace("AABBNV", "AABB_NV")
175	name = name.replace("_H_264_", "_H264_")
176	name = name.replace("_H_265_", "_H265_")
177	name = name.replace("RDMAFEATURES", "RDMA_FEATURES")
178	name = name.replace("RGBA_10_X_6", "RGBA10X6")
179	name = name.replace("2_D", "2D_")
180	name = name.replace("3_D", "3D_")
181	name = name.replace("IOSURFACE", "IO_SURFACE")
182
183	return prefix + name
184
185def getApiVariantIndexByName(variantName):
186	apiVariant = {
187		None : 0,
188		''   : 0,
189		'SC' : 1
190	}
191	return apiVariant[variantName]
192
193def getApiVariantNameByIndex(variantIndex):
194	apiVariant = {
195		None : '',
196		0    : '',
197		1    : 'SC'
198	}
199	return apiVariant[variantIndex]
200
201class Version:
202	def __init__ (self, versionTuple):
203		self.api   = versionTuple[0]
204		self.major = versionTuple[1]
205		self.minor = versionTuple[2]
206		self.patch = versionTuple[3]
207
208	def getInHex (self):
209		if self.patch == 0:
210			return "VK%s_API_VERSION_%d_%d" % (getApiVariantNameByIndex(self.api), self.major, self.minor)
211		return '0x%Xu' % (hash(self))
212
213	def isStandardVersion (self):
214		if self.patch != 0:
215			return False
216		if self.major != 1:
217			return False
218		return True
219
220	def getBestRepresentation (self):
221		if self.isStandardVersion():
222			return self.getInHex()
223		return self.getDefineName()
224
225	def getDefineName (self):
226		return 'VERSION_%d_%d_%d' % (self.major, self.minor, self.patch)
227
228	def __hash__ (self):
229		return (self.api << 29) | (self.major << 22) | (self.minor << 12) | self.patch
230
231	def __eq__ (self, other):
232		return self.api == other.api and self.major == other.major and self.minor == other.minor and self.patch == other.patch
233
234	def __str__ (self):
235		return self.getBestRepresentation()
236
237class Handle:
238	TYPE_DISP		= 0
239	TYPE_NONDISP	= 1
240
241	def __init__ (self, type, name):
242		self.type		= type
243		self.name		= name
244		self.alias		= None
245		self.isAlias	= False
246
247	def getHandleType (self):
248		return prefixName("HANDLE_TYPE_", self.name)
249
250	def checkAliasValidity (self):
251		pass
252
253	def __repr__ (self):
254		return '%s (%s, %s)' % (self.name, self.alias, self.isAlias)
255
256class Definition:
257	def __init__ (self, type, name, value):
258		self.type	= type
259		self.name	= name
260		self.value	= value
261		self.alias	= None
262		self.isAlias	= False
263
264	def __repr__ (self):
265		return '%s = %s (%s)' % (self.name, self.value, self.type)
266
267class Enum:
268	def __init__ (self, name, values):
269		self.name		= name
270		self.values		= values
271		self.alias		= None
272		self.isAlias	= False
273
274	def checkAliasValidity (self):
275		if self.alias != None:
276			if len(self.values) != len(self.alias.values):
277				raise Exception("%s has different number of flags than its alias %s." % (self.name, self.alias.name))
278			for index, value in enumerate(self.values):
279				aliasVal = self.alias.values[index]
280				if value[1] != aliasVal[1] or not (value[0].startswith(aliasVal[0]) or aliasVal[0].startswith(value[0])):
281					raise Exception("Flag %s of %s has different value than %s of %s." % (self.alias.values[index], self.alias.name, value, self.name))
282
283	def __repr__ (self):
284		return '%s (%s) %s' % (self.name, self.alias, self.values)
285
286class Bitfield:
287	def __init__ (self, name, values):
288		self.name		= name
289		self.values		= values
290		self.alias		= None
291		self.isAlias	= False
292
293	def checkAliasValidity (self):
294		if self.alias != None:
295			if len(self.values) != len(self.alias.values):
296				raise Exception("%s has different number of flags than its alias %s." % (self.name, self.alias.name))
297			for index, value in enumerate(self.values):
298				aliasVal = self.alias.values[index]
299				if value[1] != aliasVal[1] or not (value[0].startswith(aliasVal[0]) or aliasVal[0].startswith(value[0])):
300					raise Exception("Flag %s of %s has different value than %s of %s." % (self.alias.values[index], self.alias.name, value, self.name))
301
302	def __repr__ (self):
303		return '%s (%s)' % (self.name, self.alias)
304
305class Variable:
306	def __init__ (self, type, name, arraySizeOrFieldWidth):
307		type		= type.replace('*',' *').replace('&',' &')
308		for src, dst in TYPE_SUBSTITUTIONS:
309			type = type.replace(src, dst)
310		self.type	= type.split(' ')
311		for platformType, substitute, compat in PLATFORM_TYPES:
312			range = self.contains(self.type, platformType)
313			if range != None:
314				self.type = self.type[:range[0]]+[PLATFORM_TYPE_NAMESPACE + '::' + substitute[0]] + substitute[1:] + self.type[range[1]:]
315				break
316		self.name		= name
317		if len(arraySizeOrFieldWidth) > 0 and arraySizeOrFieldWidth[0] == ':':
318			self.arraySize	= ''
319			self.fieldWidth = arraySizeOrFieldWidth
320		else:
321			self.arraySize	= arraySizeOrFieldWidth
322			self.fieldWidth = ''
323
324	def contains(self, big, small):
325		for i in range(len(big)-len(small)+1):
326			for j in range(len(small)):
327				if big[i+j] != small[j]:
328					break
329			else:
330				return i, i+len(small)
331		return None
332
333	def getType (self):
334		return ' '.join(self.type).replace(' *','*').replace(' &','&')
335
336	def getAsString (self, separator):
337		return '%s%s%s%s%s' % (self.getType(), separator, self.name, self.arraySize, self.fieldWidth)
338
339	def getAsStringForArgumentList (self, separator):
340		return '%s%s%s%s' % (self.getType(), separator, self.name, self.arraySize)
341
342	def __repr__ (self):
343		return '<%s> <%s> <%s>' % (self.type, self.name, self.arraySize)
344
345	def __eq__ (self, other):
346		if len(self.type) != len(other.type):
347			return False
348		for index, type in enumerate(self.type):
349			if "*" == type or "&" == type or "const" == type or "volatile" == type:
350				if type != other.type[index]:
351					return False
352			elif type != other.type[index] and \
353				type not in map(lambda ext: other.type[index] + ext, EXTENSION_POSTFIXES_STANDARD) and \
354				other.type[index] not in map(lambda ext: type + ext, EXTENSION_POSTFIXES_STANDARD):
355				return False
356		return self.arraySize == other.arraySize
357
358	def __ne__ (self, other):
359		return not self == other
360
361class CompositeType:
362	CLASS_STRUCT	= 0
363	CLASS_UNION		= 1
364
365	def __init__ (self, typeClass, name, members, apiVersion = None):
366		self.typeClass	= typeClass
367		self.name		= name
368		self.members	= members
369		self.alias		= None
370		self.isAlias	= False
371		self.apiVersion	= apiVersion
372
373	def getClassName (self):
374		names = {CompositeType.CLASS_STRUCT: 'struct', CompositeType.CLASS_UNION: 'union'}
375		return names[self.typeClass]
376
377	def checkAliasValidity (self):
378		if self.alias != None:
379			if len(self.members) != len(self.alias.members):
380				raise Exception("%s has different number of members than its alias %s." % (self.name, self.alias.name))
381			for index, member in enumerate(self.members ):
382				break
383				#if member != self.alias.members[index]:
384					#raise Exception("Member %s of %s is different than core member %s in %s." % (self.alias.members[index], self.alias.name, member, self.name))
385					#raise Exception("Member ",str(self.alias.members[index])," of ", str(self.alias.name)," is different than core member ", str(member)," in ", str(self.name),".")
386	def __repr__ (self):
387		return '%s (%s)' % (self.name, self.alias)
388
389class Function:
390	TYPE_PLATFORM		= 0 # Not bound to anything
391	TYPE_INSTANCE		= 1 # Bound to VkInstance
392	TYPE_DEVICE			= 2 # Bound to VkDevice
393
394	def __init__ (self, name, returnType, arguments, apiVersion = None):
395		self.name		= name
396		self.returnType	= returnType
397		self.arguments	= arguments
398		self.alias		= None
399		self.isAlias	= False
400		self.apiVersion	= apiVersion
401
402	def getType (self):
403		# Special functions
404		if self.name == "vkGetInstanceProcAddr":
405			return Function.TYPE_PLATFORM
406		assert len(self.arguments) > 0
407		firstArgType = self.arguments[0].getType()
408		if firstArgType in ["VkInstance", "VkPhysicalDevice"]:
409			return Function.TYPE_INSTANCE
410		elif firstArgType in ["VkDevice", "VkCommandBuffer", "VkQueue"]:
411			return Function.TYPE_DEVICE
412		else:
413			return Function.TYPE_PLATFORM
414
415	def checkAliasValidity (self):
416		if self.alias != None:
417			if len(self.arguments) != len(self.alias.arguments):
418				raise Exception("%s has different number of arguments than its alias %s." % (self.name, self.alias.name))
419			if self.returnType != self.alias.returnType or not (self.returnType.startswith(self.alias.returnType) or self.alias.returnType.startswith(self.returnType)):
420				raise Exception("%s has different return value's type than its alias %s." % (self.name, self.alias.name))
421			for index, argument in enumerate(self.arguments):
422				if argument != self.alias.arguments[index]:
423					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))
424
425	def __repr__ (self):
426		return '%s (%s)' % (self.name, self.alias)
427
428class Extension:
429	def __init__ (self, name, handles, enums, bitfields, compositeTypes, functions, definitions, additionalDefinitions, typedefs, versionInCore):
430		self.name			= name
431		self.definitions	= definitions
432		self.additionalDefs = additionalDefinitions
433		self.handles		= handles
434		self.enums			= enums
435		self.bitfields		= bitfields
436		self.compositeTypes	= compositeTypes
437		self.functions		= functions
438		self.typedefs		= typedefs
439		self.versionInCore	= versionInCore
440
441	def __repr__ (self):
442		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)
443
444class API:
445	def __init__ (self, versions, definitions, handles, enums, bitfields, bitfields64, compositeTypes, functions, extensions, additionalExtensionData):
446		self.versions					= versions
447		self.definitions				= definitions
448		self.handles					= handles
449		self.enums						= enums
450		self.bitfields					= bitfields
451		self.bitfields64				= bitfields64
452		self.compositeTypes				= compositeTypes
453		self.functions					= functions					# \note contains extension functions as well
454		self.extensions					= extensions
455		self.additionalExtensionData	= additionalExtensionData	# \note contains mandatory features and information about promotion
456
457def readFile (filename):
458	with open(filename, 'rt') as f:
459		return f.read()
460
461IDENT_PTRN	= r'[a-zA-Z_][a-zA-Z0-9_]*'
462WIDTH_PTRN	= r'[:0-9]*'
463TYPE_PTRN	= r'[a-zA-Z_][a-zA-Z0-9_ \t*&]*'
464
465def getInterfaceName (function):
466	assert function.name[:2] == "vk"
467	return function.name[2].lower() + function.name[3:]
468
469def getFunctionTypeName (function):
470	assert function.name[:2] == "vk"
471	return function.name[2:] + "Func"
472
473def endsWith (str, postfix):
474	return str[-len(postfix):] == postfix
475
476def splitNameExtPostfix (name):
477	knownExtPostfixes = EXTENSION_POSTFIXES
478	for postfix in knownExtPostfixes:
479		if endsWith(name, postfix):
480			return (name[:-len(postfix)], postfix)
481	return (name, "")
482
483def getBitEnumNameForBitfield (bitfieldName):
484	bitfieldName, postfix = splitNameExtPostfix(bitfieldName)
485	assert bitfieldName[-1] == "s"
486	return bitfieldName[:-1] + "Bits" + postfix
487
488def getBitfieldNameForBitEnum (bitEnumName):
489	bitEnumName, postfix = splitNameExtPostfix(bitEnumName)
490	assert bitEnumName[-4:] == "Bits"
491	return bitEnumName[:-4] + "s" + postfix
492
493def parsePreprocDefinedValue (src, name):
494	value = parsePreprocDefinedValueOptional(src, name)
495	if value is None:
496		raise Exception("No such definition: %s" % name)
497	return value
498
499def parsePreprocDefinedValueOptional (src, name):
500	definition = re.search(r'#\s*define\s+' + name + r'\s+([^\n]+)\n', src)
501	if definition is None:
502		return None
503	value = definition.group(1).strip()
504	if value == "UINT32_MAX":
505		value = "(~0u)"
506	return value
507
508def parseEnum (name, src):
509	keyValuePtrn = '(' + IDENT_PTRN + r')\s*=\s*([^\s,\n}]+)\s*[,\n}]'
510	return Enum(name, re.findall(keyValuePtrn, src))
511
512# \note Parses raw enums, some are mapped to bitfields later
513def parseEnums (src):
514	matches	= re.findall(r'typedef enum(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
515	enums	= []
516	for enumname, contents, typename in matches:
517		enums.append(parseEnum(typename, contents))
518	return enums
519
520def parseCompositeType (type, name, src):
521	typeNamePtrn	= r'(' + TYPE_PTRN + r')(\s+' + IDENT_PTRN + r')((\[[^\]]+\]|\s*:\s*[0-9]+)*)\s*;'
522	matches			= re.findall(typeNamePtrn, src)
523	members			= [Variable(t.strip(), n.strip(), a.replace(' ', '')) for t, n, a, _ in matches]
524	return CompositeType(type, name, members)
525
526def parseCompositeTypes (src):
527	typeMap	= { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION }
528	matches	= re.findall(r'typedef (struct|union)(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
529	types	= []
530	for type, structname, contents, typename in matches:
531		types.append(parseCompositeType(typeMap[type], typename, contents))
532	return types
533
534def parseCompositeTypesByVersion (src, versionsData):
535
536	# find occurence of extension is a place where
537	# we cant assign apiVersion to found structures
538	extPtrn		= r'#define\s+[A-Z0-9_]+_EXTENSION_NAME\s+"([^"]+)"'
539	versionEnd	= re.search(extPtrn, src)
540	versions	= [Version((v[2], v[3], v[4], 0)) for v in versionsData]
541	versions.append(None)
542
543	# construct list of locations where version definitions start, and add the end of the file to it
544	sectionLocations = [versionDef[1] for versionDef in versionsData]
545	sectionLocations.append(versionEnd.start())
546	sectionLocations.append(len(src))
547
548	# construct function declaration pattern
549	ptrn		= r'typedef (struct|union)(\s*' + IDENT_PTRN + r')?\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;'
550	regPtrn		= re.compile(ptrn)
551	types		= []
552	typeMap		= { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION }
553
554	# iterate over all versions and find all structure definitions
555	for index, v in enumerate(versions):
556		matches = regPtrn.findall(src, sectionLocations[index], sectionLocations[index+1])
557		for type, structname, contents, typename in matches:
558			compositeType = parseCompositeType(typeMap[type], typename, contents)
559			compositeType.apiVersion = v
560			types.append(compositeType)
561	return types
562
563def parseVersions (src):
564	# returns list of tuples each with four items:
565	# 1. string with version token (without ' 1' at the end)
566	# 2. starting point off version specific definitions in vulkan.h.in
567	# 3. major version number
568	# 4. minor version number
569	return [(m.group()[:-2], m.start(), getApiVariantIndexByName(m.group(1)), int(m.group(2)), int(m.group(3))) for m in re.finditer('VK(SC)?_VERSION_([1-9])_([0-9]) 1', src)]
570
571
572def parseHandles (src):
573	matches	= re.findall(r'VK_DEFINE(_NON_DISPATCHABLE|)_HANDLE\((' + IDENT_PTRN + r')\)[ \t]*[\n\r]', src)
574	handles	= []
575	typeMap	= {'': Handle.TYPE_DISP, '_NON_DISPATCHABLE': Handle.TYPE_NONDISP}
576	for type, name in matches:
577		handle = Handle(typeMap[type], name)
578		handles.append(handle)
579	return handles
580
581def parseArgList (src):
582	typeNamePtrn	= r'(' + TYPE_PTRN + r')(\s+' + IDENT_PTRN + r')((\[[^\]]+\])*)\s*'
583	args			= []
584	for rawArg in src.split(','):
585		m = re.search(typeNamePtrn, rawArg)
586		args.append(Variable(m.group(1).strip(), m.group(2).strip(), m.group(3)))
587	return args
588
589def removeTypeExtPostfix (name):
590	for extPostfix in EXTENSION_POSTFIXES_STANDARD:
591		if endsWith(name, extPostfix):
592			return name[0:-len(extPostfix)]
593	return None
594
595def populateExtensionAliases(allObjects, extensionObjects):
596	for object in extensionObjects:
597		withoutPostfix = removeTypeExtPostfix(object.name)
598		if withoutPostfix != None and withoutPostfix in allObjects:
599			# max 1 alias is assumed by functions in this file
600			assert allObjects[withoutPostfix].alias == None
601			allObjects[withoutPostfix].alias = object
602			object.isAlias = True
603	for object in extensionObjects:
604		object.checkAliasValidity()
605
606def populateAliasesWithTypedefs (objects, src):
607	objectsByName = {}
608	for object in objects:
609		objectsByName[object.name] = object
610		ptrn	= r'\s*typedef\s+' + object.name + r'\s+([^;]+)'
611		stash = re.findall(ptrn, src)
612		if len(stash) == 1:
613			objExt = copy.deepcopy(object)
614			objExt.name = stash[0]
615			object.alias = objExt
616			objExt.isAlias = True
617			objects.append(objExt)
618
619def removeAliasedValues (enum):
620	valueByName = {}
621	for name, value in enum.values:
622		valueByName[name] = value
623
624	def removeDefExtPostfix (name):
625		for extPostfix in EXTENSION_POSTFIXES:
626			if endsWith(name, "_" + extPostfix):
627				return name[0:-(len(extPostfix)+1)]
628		return None
629
630	newValues = []
631	for name, value in enum.values:
632		withoutPostfix = removeDefExtPostfix(name)
633		if withoutPostfix != None and withoutPostfix in valueByName and valueByName[withoutPostfix] == value:
634			continue
635		newValues.append((name, value))
636	enum.values = newValues
637
638def parseFunctions (src):
639	ptrn		= r'VKAPI_ATTR\s+(' + TYPE_PTRN + ')\s+VKAPI_CALL\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;'
640	matches		= re.findall(ptrn, src)
641	functions	= []
642	for returnType, name, argList in matches:
643		functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList)))
644	return functions
645
646def parseFunctionsByVersion (src, versions):
647	# construct list of locations where version definitions start, and add the end of the file to it
648	sectionLocations = [versionDef[1] for versionDef in versions]
649	sectionLocations.append(len(src))
650
651	# construct function declaration pattern
652	ptrn		= r'VKAPI_ATTR\s+(' + TYPE_PTRN + ')\s+VKAPI_CALL\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;'
653	regPtrn		= re.compile(ptrn)
654	functions	= []
655
656	# iterate over all versions and find all function definitions
657	for index, v in enumerate(versions):
658		matches = regPtrn.findall(src, sectionLocations[index], sectionLocations[index+1])
659		for returnType, name, argList in matches:
660			functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList), v[0]))
661	return functions
662
663def splitByExtension (src):
664	ptrn		= r'#define\s+[A-Z0-9_]+_EXTENSION_NAME\s+"([^"]+)"'
665	# Construct long pattern that will be used to split whole source by extensions
666	match		= "#define\s+("
667	for part in re.finditer(ptrn, src):
668		 match += part.group(1)+"|"
669	match = match[:-1] + ")\s+1"
670	parts = re.split(match, src)
671
672	# First part is core, following tuples contain extension name and all its definitions
673	byExtension	= [(None, parts[0])]
674	for ndx in range(1, len(parts), 2):
675		byExtension.append((parts[ndx], parts[ndx+1]))
676	return byExtension
677
678def parseDefinitions (extensionName, src):
679
680	def skipDefinition (extensionName, definition):
681		if extensionName == None:
682			return True
683		extNameUpper = extensionName.upper()
684		extNameUpper = extNameUpper.replace("VK_KHR_SYNCHRONIZATION2", "VK_KHR_SYNCHRONIZATION_2")
685		extNameUpper = extNameUpper.replace("VK_INTEL_SHADER_INTEGER_FUNCTIONS2", "VK_INTEL_SHADER_INTEGER_FUNCTIONS_2")
686		extNameUpper = extNameUpper.replace("VK_EXT_ROBUSTNESS2", "VK_EXT_ROBUSTNESS_2")
687		extNameUpper = extNameUpper.replace("VK_EXT_FRAGMENT_DENSITY_MAP2", "VK_EXT_FRAGMENT_DENSITY_MAP_2")
688		extNameUpper = extNameUpper.replace("VK_EXT_SHADER_ATOMIC_FLOAT2", "VK_EXT_SHADER_ATOMIC_FLOAT_2")
689		extNameUpper = extNameUpper.replace("VK_AMD_SHADER_CORE_PROPERTIES2", "VK_AMD_SHADER_CORE_PROPERTIES_2")
690		extNameUpper = extNameUpper.replace("VK_EXT_EXTENDED_DYNAMIC_STATE2", "VK_EXT_EXTENDED_DYNAMIC_STATE_2")
691		# SPEC_VERSION enums
692		if definition[0].startswith(extNameUpper) and definition[1].isdigit():
693			return False
694		if definition[0].startswith(extNameUpper):
695			return True
696		if definition[0].endswith("_H_"):
697			return True
698		return False
699
700	ptrn		= r'#define\s+([^\s]+)\s+([^\r\n]+)'
701	matches		= re.findall(ptrn, src)
702
703	return [Definition(None, match[0], match[1]) for match in matches if not skipDefinition(extensionName, match)]
704
705def parseTypedefs (src):
706
707	ptrn		= r'typedef\s+([^\s]+)\s+([^\r\n]+);'
708	matches		= re.findall(ptrn, src)
709
710	return [Definition(None, match[0], match[1]) for match in matches]
711
712def parseExtensions (src, versions, allFunctions, allCompositeTypes, allEnums, allBitfields, allHandles, allDefinitions, additionalExtensionData):
713
714	# note registeredExtensionDict is also executed for vulkan 1.0 source for which extension name is None
715	registeredExtensionDict = {None: None}
716	for extensionName, data in additionalExtensionData:
717		# make sure that this extension was registered
718		if 'register_extension' not in data.keys():
719			continue
720		# save array containing 'device' or 'instance' string followed by the optional vulkan version in which this extension is core;
721		# note that register_extension section is also required for partialy promoted extensions like VK_EXT_extended_dynamic_state2
722		# but those extensions should not fill 'core' tag
723		registeredExtensionDict[extensionName] = [ data['register_extension']['type'] ]
724		match = re.match("(\d).(\d).(\d).(\d)", data['register_extension']['core'])
725		if match != None:
726			registeredExtensionDict[extensionName].extend( [ int(match.group(1)), int(match.group(2)), int(match.group(3)), int(match.group(4)) ] )
727
728	splitSrc				= splitByExtension(src)
729	extensions				= []
730	functionsByName			= {function.name: function for function in allFunctions}
731	compositeTypesByName	= {compType.name: compType for compType in allCompositeTypes}
732	enumsByName				= {enum.name: enum for enum in allEnums}
733	bitfieldsByName			= {bitfield.name: bitfield for bitfield in allBitfields}
734	handlesByName			= {handle.name: handle for handle in allHandles}
735	definitionsByName		= {definition.name: definition for definition in allDefinitions}
736
737	for extensionName, extensionSrc in splitSrc:
738		definitions			= [Definition("uint32_t", v.getInHex(), parsePreprocDefinedValueOptional(extensionSrc, v.getInHex())) for v in versions]
739		definitions.extend([Definition(type, name, parsePreprocDefinedValueOptional(extensionSrc, name)) for name, type in DEFINITIONS])
740		definitions			= [definition for definition in definitions if definition.value != None]
741		additionalDefinitions = parseDefinitions(extensionName, extensionSrc)
742		handles				= parseHandles(extensionSrc)
743		functions			= parseFunctions(extensionSrc)
744		compositeTypes		= parseCompositeTypes(extensionSrc)
745		rawEnums			= parseEnums(extensionSrc)
746		bitfieldNames		= parse32bitBitfieldNames(extensionSrc)
747		typedefs			= parseTypedefs(extensionSrc)
748		enumBitfieldNames	= [getBitEnumNameForBitfield(name) for name in bitfieldNames]
749		enums				= [enum for enum in rawEnums if enum.name not in enumBitfieldNames]
750
751		extCoreVersion		= None
752		extData				= registeredExtensionDict.get(extensionName, None)
753		extFunctions		= [functionsByName[function.name] for function in functions]
754		extCompositeTypes	= [compositeTypesByName[compositeType.name] for compositeType in compositeTypes]
755		extEnums			= [enumsByName[enum.name] for enum in enums]
756		extBitfields		= [bitfieldsByName[bitfieldName] for bitfieldName in bitfieldNames]
757		extHandles			= [handlesByName[handle.name] for handle in handles]
758		extDefinitions		= [definitionsByName[definition.name] for definition in definitions]
759
760		if extData != None:
761			populateExtensionAliases(functionsByName, extFunctions)
762			populateExtensionAliases(handlesByName, extHandles)
763			populateExtensionAliases(enumsByName, extEnums)
764			populateExtensionAliases(bitfieldsByName, extBitfields)
765			populateExtensionAliases(compositeTypesByName, extCompositeTypes)
766			if len(extData) > 1:
767				extCoreVersion = extData
768
769		extensions.append(Extension(extensionName, extHandles, extEnums, extBitfields, extCompositeTypes, extFunctions, extDefinitions, additionalDefinitions, typedefs, extCoreVersion))
770	return extensions
771
772def parse32bitBitfieldNames (src):
773	ptrn		= r'typedef\s+VkFlags\s(' + IDENT_PTRN + r')\s*;'
774	matches		= re.findall(ptrn, src)
775
776	return matches
777
778def parse64bitBitfieldNames (src):
779	ptrn		= r'typedef\s+VkFlags64\s(' + IDENT_PTRN + r')\s*;'
780	matches		= re.findall(ptrn, src)
781
782	return matches
783
784def parse64bitBitfieldValues (src, bitfieldNamesList):
785
786	bitfields64 = []
787	for bitfieldName in bitfieldNamesList:
788		ptrn		= r'static const ' + bitfieldName + r'\s*(' + IDENT_PTRN + r')\s*=\s*([a-zA-Z0-9_]+)\s*;'
789		matches		= re.findall(ptrn, src)
790		bitfields64.append(Bitfield(bitfieldName, matches))
791
792	return bitfields64
793
794def parseAPI (src):
795	versionsData	= parseVersions(src)
796	versions		= [Version((v[2], v[3], v[4], 0)) for v in versionsData]
797	definitions		= [Definition("uint32_t", v.getInHex(), parsePreprocDefinedValue(src, v.getInHex())) for v in versions] +\
798					  [Definition(type, name, parsePreprocDefinedValue(src, name)) for name, type in DEFINITIONS]
799
800	handles						= parseHandles(src)
801	rawEnums					= parseEnums(src)
802	bitfieldNames				= parse32bitBitfieldNames(src)
803	bitfieldEnums				= set([getBitEnumNameForBitfield(n) for n in bitfieldNames if getBitEnumNameForBitfield(n) in [enum.name for enum in rawEnums]])
804	bitfield64Names				= parse64bitBitfieldNames(src)
805	bitfields64					= parse64bitBitfieldValues(src, bitfield64Names)
806	enums						= []
807	bitfields					= []
808	compositeTypes				= parseCompositeTypesByVersion(src, versionsData)
809	allFunctions				= parseFunctionsByVersion(src, versionsData)
810	additionalExtensionData		= {}
811
812	# read all files from extensions directory
813	for fileName in glob.glob(os.path.join(SCRIPTS_SRC_DIR, "extensions", "*.json")):
814		extensionName	= os.path.basename(fileName)[:-5]
815		fileContent		= readFile(fileName)
816		try:
817			additionalExtensionData[extensionName] = json.loads(fileContent)
818		except ValueError as err:
819			print("Error in %s: %s" % (os.path.basename(fileName), str(err)))
820			sys.exit(-1)
821	additionalExtensionData = sorted(additionalExtensionData.items(), key=lambda e: e[0])
822
823	for enum in rawEnums:
824		if enum.name in bitfieldEnums:
825			bitfields.append(Bitfield(getBitfieldNameForBitEnum(enum.name), enum.values))
826		else:
827			enums.append(enum)
828
829	for bitfieldName in bitfieldNames:
830		if not bitfieldName in [bitfield.name for bitfield in bitfields]:
831			# Add empty bitfield
832			bitfields.append(Bitfield(bitfieldName, []))
833
834	extensions = parseExtensions(src, versions, allFunctions, compositeTypes, enums, bitfields, handles, definitions, additionalExtensionData)
835
836	# Populate alias fields
837	populateAliasesWithTypedefs(compositeTypes, src)
838	populateAliasesWithTypedefs(enums, src)
839	populateAliasesWithTypedefs(bitfields, src)
840	populateAliasesWithTypedefs(bitfields64, src)
841	populateAliasesWithTypedefs(handles, src)
842
843	for enum in enums:
844		removeAliasedValues(enum)
845
846	# Make generator to create Deleter<VkAccelerationStructureNV>
847	for f in allFunctions:
848		if (f.name == 'vkDestroyAccelerationStructureNV'):
849			f.arguments[1].type[0] = 'VkAccelerationStructureNV'
850
851	# Dealias handles VkAccelerationStructureNV and VkAccelerationStructureKHR
852	for handle in handles:
853		if handle.name == 'VkAccelerationStructureKHR':
854			handle.alias = None
855		if handle.name == 'VkAccelerationStructureNV':
856			handle.isAlias = False
857
858	return API(
859		versions				= versions,
860		definitions				= definitions,
861		handles					= handles,
862		enums					= enums,
863		bitfields				= bitfields,
864		bitfields64				= bitfields64,
865		compositeTypes			= compositeTypes,
866		functions				= allFunctions,
867		extensions				= extensions,
868		additionalExtensionData	= additionalExtensionData)
869
870def splitUniqueAndDuplicatedEntries (handles):
871	listOfUniqueHandles = []
872	duplicates			= OrderedDict()
873	for handle in handles:
874		if handle.alias != None:
875			duplicates[handle.alias] = handle
876		if not handle.isAlias:
877			listOfUniqueHandles.append(handle)
878	return listOfUniqueHandles, duplicates
879
880def writeHandleType (api, filename):
881	uniqeHandles, duplicatedHandles = splitUniqueAndDuplicatedEntries(api.handles)
882
883	def genHandles ():
884		yield "\t%s\t= 0," % uniqeHandles[0].getHandleType()
885		for handle in uniqeHandles[1:]:
886			yield "\t%s," % handle.getHandleType()
887		for duplicate in duplicatedHandles:
888			yield "\t%s\t= %s," % (duplicate.getHandleType(), duplicatedHandles[duplicate].getHandleType())
889		yield "\tHANDLE_TYPE_LAST\t= %s + 1" % (uniqeHandles[-1].getHandleType())
890
891	def genHandlesBlock ():
892		yield "enum HandleType"
893		yield "{"
894
895		for line in indentLines(genHandles()):
896			yield line
897
898		yield "};"
899		yield ""
900
901	writeInlFile(filename, INL_HEADER, genHandlesBlock())
902
903def getEnumValuePrefix (enum):
904	prefix = enum.name[0]
905	for i in range(1, len(enum.name)):
906		if enum.name[i].isupper() and not enum.name[i-1].isupper():
907			prefix += "_"
908		prefix += enum.name[i].upper()
909	return prefix
910
911def parseInt (value):
912	if value[:2] == "0x":
913		return int(value, 16)
914	else:
915		return int(value, 10)
916
917def areEnumValuesLinear (enum):
918	curIndex = 0
919	maxIntCount = 0
920	for name, value in enum.values:
921		if value[:2] != "VK":
922			intValue = parseInt(value)
923			if intValue != curIndex:
924				# enum is linear when all items are in order
925				if intValue != 0x7FFFFFFF:
926					return False
927				# count number of items with 0x7FFFFFFF value;
928				# enum containing single 0x7FFFFFFF item are also
929				# considered as linear (this is usualy *_MAX_ENUM item)
930				maxIntCount += 1
931				# enums containing more then one 0x7FFFFFFF value
932				# are not considered as linear (vulkan video enums)
933				if maxIntCount > 1:
934					return False
935			curIndex += 1
936	return True
937
938def genEnumSrc (enum):
939	yield "enum %s" % enum.name
940	yield "{"
941
942	lines = []
943	if areEnumValuesLinear(enum):
944		hasMaxItem	= parseInt(enum.values[-1][1]) == 0x7FFFFFFF
945
946		values		= enum.values[:-1] if hasMaxItem else enum.values
947		lastItem	= "\t%s_LAST," % getEnumValuePrefix(enum)
948
949		# linear values first, followed by *_LAST
950		lines		+= ["\t%s\t= %s," % v for v in values if v[1][:2] != "VK"]
951		lines.append(lastItem)
952
953		# equivalence enums and *_MAX_ENUM
954		lines		+= ["\t%s\t= %s," % v for v in values if v[1][:2] == "VK"]
955		if hasMaxItem:
956			lines.append("\t%s\t= %s," % enum.values[-1])
957	else:
958		lines		+= ["\t%s\t= %s," % v for v in enum.values]
959
960	for line in indentLines(lines):
961		yield line
962
963	yield "};"
964
965def genBitfieldSrc (bitfield):
966	if len(bitfield.values) > 0:
967		yield "enum %s" % getBitEnumNameForBitfield(bitfield.name)
968		yield "{"
969		for line in indentLines(["\t%s\t= %s," % v for v in bitfield.values]):
970			yield line
971		yield "};"
972	yield "typedef uint32_t %s;" % bitfield.name
973
974def genBitfield64Src (bitfield64):
975	yield "typedef uint64_t %s;" % bitfield64.name
976	if len(bitfield64.values) > 0:
977		ptrn = "static const " + bitfield64.name + " %s\t= %s;"
978		for line in indentLines([ptrn % v for v in bitfield64.values]):
979			yield line
980		yield ""
981
982def genCompositeTypeSrc (type):
983	yield "%s %s" % (type.getClassName(), type.name)
984	yield "{"
985	for line in indentLines(['\t'+m.getAsString('\t')+';' for m in type.members]):
986		yield line
987	yield "};"
988
989def genHandlesSrc (handles):
990	uniqeHandles, duplicatedHandles = splitUniqueAndDuplicatedEntries(handles)
991
992	def genLines (handles):
993		for handle in uniqeHandles:
994			if handle.type == Handle.TYPE_DISP:
995				yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType())
996			elif handle.type == Handle.TYPE_NONDISP:
997				yield "VK_DEFINE_NON_DISPATCHABLE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType())
998
999		for duplicate in duplicatedHandles:
1000			if duplicate.type == Handle.TYPE_DISP:
1001				yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (duplicate.name, duplicatedHandles[duplicate].getHandleType())
1002			elif duplicate.type == Handle.TYPE_NONDISP:
1003				yield "VK_DEFINE_NON_DISPATCHABLE_HANDLE\t(%s,\t%s);" % (duplicate.name, duplicatedHandles[duplicate].getHandleType())
1004
1005	for line in indentLines(genLines(handles)):
1006		yield line
1007
1008def stripTrailingComment(str):
1009	index = str.find("//")
1010	if index == -1:
1011		return str
1012	return str[:index]
1013
1014def genDefinitionsSrc (definitions):
1015	for line in ["#define %s\t(static_cast<%s>\t(%s))" % (definition.name, definition.type, stripTrailingComment(definition.value)) for definition in definitions]:
1016		yield line
1017
1018def genDefinitionsAliasSrc (definitions):
1019	for line in ["#define %s\t%s" % (definition.name, definitions[definition].name) for definition in definitions]:
1020		if definition.value != definitions[definition].value and definition.value != definitions[definition].name:
1021			raise Exception("Value of %s (%s) is different than core definition value %s (%s)." % (definition.name, definition.value, definitions[definition].name, definitions[definition].value))
1022		yield line
1023
1024def genMaxFrameworkVersion (definitions):
1025	maxApiVersionMajor = 1
1026	maxApiVersionMinor = 0
1027	for definition in definitions:
1028		match = re.match("VK_API_VERSION_(\d+)_(\d+)", definition.name)
1029		if match:
1030			apiVersionMajor = int(match.group(1))
1031			apiVersionMinor = int(match.group(2))
1032			if apiVersionMajor > maxApiVersionMajor:
1033				maxApiVersionMajor = apiVersionMajor
1034				maxApiVersionMinor = apiVersionMinor
1035			elif apiVersionMajor == maxApiVersionMajor and apiVersionMinor > maxApiVersionMinor:
1036				maxApiVersionMinor = apiVersionMinor
1037	yield "#define VK_API_MAX_FRAMEWORK_VERSION\tVK_API_VERSION_%d_%d" % (maxApiVersionMajor, maxApiVersionMinor)
1038
1039def genMaxFrameworkVersionSC (definitions):
1040	maxApiVersionMajor = 1
1041	maxApiVersionMinor = 0
1042	for definition in definitions:
1043		match = re.match("VKSC_API_VERSION_(\d+)_(\d+)", definition.name)
1044		if match:
1045			apiVersionMajor = int(match.group(1))
1046			apiVersionMinor = int(match.group(2))
1047			if apiVersionMajor > maxApiVersionMajor:
1048				maxApiVersionMajor = apiVersionMajor
1049				maxApiVersionMinor = apiVersionMinor
1050			elif apiVersionMajor == maxApiVersionMajor and apiVersionMinor > maxApiVersionMinor:
1051				maxApiVersionMinor = apiVersionMinor
1052	yield "#define VKSC_API_MAX_FRAMEWORK_VERSION\tVKSC_API_VERSION_%d_%d" % (maxApiVersionMajor, maxApiVersionMinor)
1053
1054def writeBasicTypes (apiName, api, filename):
1055
1056	def gen ():
1057		definitionsCore, definitionDuplicates = splitUniqueAndDuplicatedEntries(api.definitions)
1058
1059		if apiName == '':
1060			for line in indentLines(chain(genDefinitionsSrc(definitionsCore), genMaxFrameworkVersion(definitionsCore), genDefinitionsAliasSrc(definitionDuplicates))):
1061				yield line
1062			yield ""
1063		elif apiName == 'SC':
1064			for line in indentLines(chain(genDefinitionsSrc(definitionsCore), genMaxFrameworkVersion(definitionsCore), genMaxFrameworkVersionSC(definitionsCore), genDefinitionsAliasSrc(definitionDuplicates))):
1065				yield line
1066			yield ""
1067
1068		for line in genHandlesSrc(api.handles):
1069			yield line
1070		yield ""
1071
1072		for enum in api.enums:
1073			if not enum.isAlias:
1074				for line in genEnumSrc(enum):
1075					yield line
1076			else:
1077				for enum2 in api.enums:
1078					if enum2.alias == enum:
1079						yield "typedef %s %s;" % (enum2.name, enum.name)
1080			yield ""
1081
1082		for bitfield in api.bitfields:
1083			if not bitfield.isAlias:
1084				for line in genBitfieldSrc(bitfield):
1085					yield line
1086			else:
1087				for bitfield2 in api.bitfields:
1088					if bitfield2.alias == bitfield:
1089						yield "typedef %s %s;" % (bitfield2.name, bitfield.name)
1090			yield ""
1091
1092		for bitfield in api.bitfields64:
1093			if not bitfield.isAlias:
1094				for line in genBitfield64Src(bitfield):
1095					yield line
1096			else:
1097				for bitfield2 in api.bitfields64:
1098					if bitfield2.alias == bitfield:
1099						yield "typedef %s %s;" % (bitfield2.name, bitfield.name)
1100			yield ""
1101
1102		for line in indentLines(["VK_DEFINE_PLATFORM_TYPE(%s,\t%s)" % (s[0], c) for n, s, c in PLATFORM_TYPES]):
1103			yield line
1104
1105		for ext in api.extensions:
1106			if ext.additionalDefs != None:
1107				for definition in ext.additionalDefs:
1108					yield "#define " + definition.name + " " + definition.value
1109
1110	writeInlFile(filename, INL_HEADER, gen())
1111
1112def writeCompositeTypes (api, filename):
1113	def gen ():
1114		for type in api.compositeTypes:
1115			type.checkAliasValidity()
1116
1117			if not type.isAlias:
1118				for line in genCompositeTypeSrc(type):
1119					yield line
1120			else:
1121				for type2 in api.compositeTypes:
1122					if type2.alias == type:
1123						yield "typedef %s %s;" % (type2.name, type.name)
1124			yield ""
1125
1126	writeInlFile(filename, INL_HEADER, gen())
1127
1128def argListToStr (args):
1129	return ", ".join(v.getAsStringForArgumentList(' ') for v in args)
1130
1131def writeInterfaceDecl (api, filename, functionTypes, concrete):
1132	def genProtos ():
1133		postfix = "" if concrete else " = 0"
1134		for function in api.functions:
1135			if not function.getType() in functionTypes:
1136				continue
1137			if not function.isAlias:
1138				yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments), postfix)
1139
1140	writeInlFile(filename, INL_HEADER, indentLines(genProtos()))
1141
1142def writeFunctionPtrTypes (api, filename):
1143	def genTypes ():
1144		for function in api.functions:
1145			yield "typedef VKAPI_ATTR %s\t(VKAPI_CALL* %s)\t(%s);" % (function.returnType, getFunctionTypeName(function), argListToStr(function.arguments))
1146
1147	writeInlFile(filename, INL_HEADER, indentLines(genTypes()))
1148
1149def writeFunctionPointers (api, filename, functionTypes):
1150	def FunctionsYielder ():
1151		for function in api.functions:
1152			if function.getType() in functionTypes:
1153				if function.isAlias:
1154					if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice":
1155						yield "%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function))
1156				else:
1157					yield "%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function))
1158
1159	writeInlFile(filename, INL_HEADER, indentLines(FunctionsYielder()))
1160
1161def writeInitFunctionPointers (api, filename, functionTypes, cond = None):
1162	def makeInitFunctionPointers ():
1163		for function in api.functions:
1164			if function.getType() in functionTypes and (cond == None or cond(function)):
1165				interfaceName = getInterfaceName(function)
1166				if function.isAlias:
1167					if function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice":
1168						yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name)
1169				else:
1170					yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name)
1171					if function.alias != None:
1172						yield "if (!m_vk.%s)" % (getInterfaceName(function))
1173						yield "    m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.alias.name)
1174	lines = [line.replace('    ', '\t') for line in indentLines(makeInitFunctionPointers())]
1175	writeInlFile(filename, INL_HEADER, lines)
1176
1177def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className):
1178	def makeFuncPtrInterfaceImpl ():
1179		for function in api.functions:
1180			if function.getType() in functionTypes and not function.isAlias:
1181				yield ""
1182				yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), argListToStr(function.arguments))
1183				yield "{"
1184				if function.name == "vkEnumerateInstanceVersion":
1185					yield "	if (m_vk.enumerateInstanceVersion)"
1186					yield "		return m_vk.enumerateInstanceVersion(pApiVersion);"
1187					yield ""
1188					yield "	*pApiVersion = VK_API_VERSION_1_0;"
1189					yield "	return VK_SUCCESS;"
1190				elif function.getType() == Function.TYPE_INSTANCE and function.arguments[0].getType() == "VkPhysicalDevice" and function.alias != None:
1191					yield "	vk::VkPhysicalDeviceProperties props;"
1192					yield "	m_vk.getPhysicalDeviceProperties(physicalDevice, &props);"
1193					yield "	if (props.apiVersion >= VK_API_VERSION_1_1)"
1194					yield "		%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
1195					yield "	else"
1196					yield "		%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function.alias), ", ".join(a.name for a in function.arguments))
1197				else:
1198					yield "	%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
1199				yield "}"
1200
1201	writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl())
1202
1203def writeFuncPtrInterfaceSCImpl (api, filename, functionTypes, className):
1204	normFuncs = {
1205		"createGraphicsPipelines"		: "\t\treturn createGraphicsPipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
1206		"createComputePipelines"		: "\t\treturn createComputePipelinesHandlerNorm(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
1207		"createSampler"					: "\t\treturn createSamplerHandlerNorm(device, pCreateInfo, pAllocator, pSampler);",
1208		"createSamplerYcbcrConversion"	: "\t\treturn createSamplerYcbcrConversionHandlerNorm(device, pCreateInfo, pAllocator, pYcbcrConversion);",
1209		"createDescriptorSetLayout"		: "\t\treturn createDescriptorSetLayoutHandlerNorm(device, pCreateInfo, pAllocator, pSetLayout);",
1210		"createPipelineLayout"			: "\t\treturn createPipelineLayoutHandlerNorm(device, pCreateInfo, pAllocator, pPipelineLayout);",
1211		"createRenderPass"				: "\t\treturn createRenderPassHandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);",
1212		"createRenderPass2"				: "\t\treturn createRenderPass2HandlerNorm(device, pCreateInfo, pAllocator, pRenderPass);",
1213		"createCommandPool"				: "\t\treturn createCommandPoolHandlerNorm(device, pCreateInfo, pAllocator, pCommandPool);",
1214		"resetCommandPool"				: "\t\treturn resetCommandPoolHandlerNorm(device, commandPool, flags);",
1215		"createFramebuffer"				: "\t\treturn createFramebufferHandlerNorm(device, pCreateInfo, pAllocator, pFramebuffer);",
1216	}
1217	statFuncs = {
1218		"destroyDevice"					: "\t\tdestroyDeviceHandler(device, pAllocator);",
1219		"createDescriptorSetLayout"		: "\t\tcreateDescriptorSetLayoutHandlerStat(device, pCreateInfo, pAllocator, pSetLayout);",
1220		"destroyDescriptorSetLayout"	: "\t\tdestroyDescriptorSetLayoutHandler(device, descriptorSetLayout, pAllocator);",
1221		"createImageView"				: "\t\tcreateImageViewHandler(device, pCreateInfo, pAllocator, pView);",
1222		"destroyImageView"				: "\t\tdestroyImageViewHandler(device, imageView, pAllocator);",
1223		"createSemaphore"				: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(semaphoreRequestCount,1);\n\t\t*pSemaphore = Handle<HANDLE_TYPE_SEMAPHORE>(m_resourceInterface->incResourceCounter());\n\t}",
1224		"destroySemaphore"				: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(semaphore,semaphoreRequestCount,1);\n\t}",
1225		"createFence"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(fenceRequestCount,1);\n\t\t*pFence = Handle<HANDLE_TYPE_FENCE>(m_resourceInterface->incResourceCounter());\n\t}",
1226		"destroyFence"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(fence,fenceRequestCount,1);\n\t}",
1227		"allocateMemory"				: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(deviceMemoryRequestCount,1);\n\t\t*pMemory = Handle<HANDLE_TYPE_DEVICE_MEMORY>(m_resourceInterface->incResourceCounter());\n\t}",
1228		"createBuffer"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferRequestCount,1);\n\t\t*pBuffer = Handle<HANDLE_TYPE_BUFFER>(m_resourceInterface->incResourceCounter());\n\t}",
1229		"destroyBuffer"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(buffer,bufferRequestCount,1);\n\t}",
1230		"createImage"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(imageRequestCount,1);\n\t\t*pImage = Handle<HANDLE_TYPE_IMAGE>(m_resourceInterface->incResourceCounter());\n\t}",
1231		"destroyImage"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(image,imageRequestCount,1);\n\t}",
1232		"createEvent"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(eventRequestCount,1);\n\t\t*pEvent = Handle<HANDLE_TYPE_EVENT>(m_resourceInterface->incResourceCounter());\n\t}",
1233		"destroyEvent"					: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(event,eventRequestCount,1);\n\t}",
1234		"createQueryPool"				: "\t\tcreateQueryPoolHandler(device, pCreateInfo, pAllocator, pQueryPool);",
1235		"createBufferView"				: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(bufferViewRequestCount,1);\n\t\t*pView = Handle<HANDLE_TYPE_BUFFER_VIEW>(m_resourceInterface->incResourceCounter());\n\t}",
1236		"destroyBufferView"				: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(bufferView,bufferViewRequestCount,1);\n\t}",
1237		"createPipelineLayout"			: "\t\tcreatePipelineLayoutHandlerStat(device, pCreateInfo, pAllocator, pPipelineLayout);",
1238		"destroyPipelineLayout"			: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineLayout,pipelineLayoutRequestCount,1);\n\t}",
1239		"createRenderPass"				: "\t\tcreateRenderPassHandlerStat(device, pCreateInfo, pAllocator, pRenderPass);",
1240		"createRenderPass2"				: "\t\tcreateRenderPass2HandlerStat(device, pCreateInfo, pAllocator, pRenderPass);",
1241		"destroyRenderPass"				: "\t\tdestroyRenderPassHandler(device, renderPass, pAllocator);",
1242		"createGraphicsPipelines"		: "\t\tcreateGraphicsPipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
1243		"createComputePipelines"		: "\t\tcreateComputePipelinesHandlerStat(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);",
1244		"destroyPipeline"				: "\t\tdestroyPipelineHandler(device, pipeline, pAllocator);",
1245		"createSampler"					: "\t\tcreateSamplerHandlerStat(device, pCreateInfo, pAllocator, pSampler);",
1246		"destroySampler"				: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(sampler,samplerRequestCount,1);\n\t}",
1247		"createDescriptorPool"			: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(descriptorPoolRequestCount,1);\n\t\t*pDescriptorPool = Handle<HANDLE_TYPE_DESCRIPTOR_POOL>(m_resourceInterface->incResourceCounter());\n\t}",
1248		"resetDescriptorPool"			: "\t\tresetDescriptorPoolHandlerStat(device, descriptorPool, flags);",
1249		"allocateDescriptorSets"		: "\t\tallocateDescriptorSetsHandlerStat(device, pAllocateInfo, pDescriptorSets);",
1250		"freeDescriptorSets"			: "\t\tfreeDescriptorSetsHandlerStat(device, descriptorPool, descriptorSetCount, pDescriptorSets);",
1251		"createFramebuffer"				: "\t\tcreateFramebufferHandlerStat(device, pCreateInfo, pAllocator, pFramebuffer);",
1252		"destroyFramebuffer"			: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(framebuffer,framebufferRequestCount,1);\n\t}",
1253		"createCommandPool"				: "\t\tcreateCommandPoolHandlerStat(device, pCreateInfo, pAllocator, pCommandPool);",
1254		"resetCommandPool"				: "\t\tresetCommandPoolHandlerStat(device, commandPool, flags);",
1255		"allocateCommandBuffers"		: "\t\tallocateCommandBuffersHandler(device, pAllocateInfo, pCommandBuffers);",
1256		"freeCommandBuffers"			: "\t\tfreeCommandBuffersHandler(device, commandPool, commandBufferCount, pCommandBuffers);",
1257		"createSamplerYcbcrConversion"	: "\t\tcreateSamplerYcbcrConversionHandlerStat(device, pCreateInfo, pAllocator, pYcbcrConversion);",
1258		"destroySamplerYcbcrConversion"	: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(ycbcrConversion,samplerYcbcrConversionRequestCount,1);\n\t}",
1259		"getDescriptorSetLayoutSupport"	: "\t\tgetDescriptorSetLayoutSupportHandler(device, pCreateInfo, pSupport);",
1260#		"" : "surfaceRequestCount",
1261#		"" : "swapchainRequestCount",
1262#		"" : "displayModeRequestCount"
1263		"mapMemory"						: "\t{\n\t\tDDSTAT_LOCK();\n\t\tif(m_falseMemory.size() < (static_cast<std::size_t>(offset+size)))\n\t\t\tm_falseMemory.resize(static_cast<std::size_t>(offset+size));\n\t\t*ppData = (void*)m_falseMemory.data();\n\t}",
1264		"getBufferMemoryRequirements"	: "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}",
1265		"getImageMemoryRequirements"	: "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->size = 1048576U;\n\t\tpMemoryRequirements->alignment = 1U;\n\t\tpMemoryRequirements->memoryTypeBits = ~0U;\n\t}",
1266		"getBufferMemoryRequirements2"	: "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->memoryRequirements.size = 1048576U;\n\t\tpMemoryRequirements->memoryRequirements.alignment = 1U;\n\t\tpMemoryRequirements->memoryRequirements.memoryTypeBits = ~0U;\n\t}",
1267		"getImageMemoryRequirements2"	: "\t{\n\t\tDDSTAT_LOCK();\n\t\tpMemoryRequirements->memoryRequirements.size = 1048576U;\n\t\tpMemoryRequirements->memoryRequirements.alignment = 1U;\n\t\tpMemoryRequirements->memoryRequirements.memoryTypeBits = ~0U;\n\t}",
1268		"getImageSubresourceLayout"		: "\t{\n\t\tDDSTAT_LOCK();\n\t\tpLayout->offset = 0U;\n\t\tpLayout->size = 1048576U;\n\t\tpLayout->rowPitch = 0U;\n\t\tpLayout->arrayPitch = 0U;\n\t\tpLayout->depthPitch = 0U;\n\t}",
1269		"createPipelineCache"			: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_CREATE(pipelineCacheRequestCount,1);\n\t\t*pPipelineCache = Handle<HANDLE_TYPE_PIPELINE_CACHE>(m_resourceInterface->incResourceCounter());\n\t}",
1270		"destroyPipelineCache"			: "\t{\n\t\tDDSTAT_LOCK();\n\t\tDDSTAT_HANDLE_DESTROY_IF(pipelineCache,pipelineCacheRequestCount,1);\n\t}",
1271		"cmdUpdateBuffer"				: "\t\tincreaseCommandBufferSize(commandBuffer, dataSize);",
1272		"getDeviceQueue"				: "\t\tm_vk.getDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);",
1273	}
1274
1275	statReturns = {
1276		"VkResult"			: "return VK_SUCCESS;",
1277		"VkDeviceAddress"	: "return 0u;",
1278		"uint64_t"			: "return 0u;",
1279	}
1280	def makeFuncPtrInterfaceStatisticsImpl ():
1281		for function in api.functions:
1282			if function.getType() in functionTypes and not function.isAlias:
1283				yield ""
1284				yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), argListToStr(function.arguments))
1285				yield "{"
1286				if ( getInterfaceName(function) in normFuncs ) or ( getInterfaceName(function) in statFuncs ):
1287					yield "\tstd::lock_guard<std::mutex> lock(functionMutex);"
1288				if getInterfaceName(function) != "getDeviceProcAddr" :
1289					yield "\tif (m_normalMode)"
1290				if getInterfaceName(function) in normFuncs :
1291					yield "%s" % ( normFuncs[getInterfaceName(function)] )
1292				else:
1293					yield "\t\t%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
1294				if getInterfaceName(function) in statFuncs :
1295					yield "\telse"
1296					yield "%s" % ( statFuncs[getInterfaceName(function)] )
1297				elif getInterfaceName(function)[:3] == "cmd" :
1298					yield "\telse"
1299					yield "\t\tincreaseCommandBufferSize(commandBuffer, 0u);"
1300				if function.returnType in statReturns:
1301					yield "\t%s" % ( statReturns[function.returnType] )
1302				yield "}"
1303
1304	writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceStatisticsImpl())
1305
1306def writeStrUtilProto (api, filename):
1307	def makeStrUtilProto ():
1308		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]):
1309			yield line
1310		yield ""
1311		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]):
1312			yield line
1313		yield ""
1314		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]):
1315			yield line
1316		yield ""
1317		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']):
1318			yield line
1319		yield ""
1320		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]):
1321			yield line
1322
1323	writeInlFile(filename, INL_HEADER, makeStrUtilProto())
1324
1325def writeStrUtilImpl (api, filename):
1326	def makeStrUtilImpl ():
1327		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]):
1328			yield line
1329
1330		yield ""
1331		yield "namespace %s" % PLATFORM_TYPE_NAMESPACE
1332		yield "{"
1333
1334		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):
1335			yield line
1336
1337		yield "}"
1338
1339		for enum in api.enums:
1340			if enum.isAlias:
1341				continue
1342			yield ""
1343			yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name)
1344			yield "{"
1345			yield "\tswitch (value)"
1346			yield "\t{"
1347			enumValues = []
1348			lastValue = 0x7FFFFFFF
1349			for n, v in enum.values:
1350				if (v[:2] != "VK") and (v != lastValue):
1351					enumValues.append(f"\t\tcase {n}:\treturn \"{n}\";")
1352				lastValue = v
1353			enumValues.append("\t\tdefault:\treturn DE_NULL;")
1354			for line in indentLines(enumValues):
1355				yield line
1356			yield "\t}"
1357			yield "}"
1358
1359		for bitfield in api.bitfields:
1360			if bitfield.isAlias:
1361				if bitfield.name != 'VkBuildAccelerationStructureFlagsNV':
1362					continue
1363			yield ""
1364			yield "tcu::Format::Bitfield<32> get%sStr (%s value)" % (bitfield.name[2:], bitfield.name)
1365			yield "{"
1366
1367			if len(bitfield.values) > 0:
1368				yield "\tstatic const tcu::Format::BitDesc s_desc[] ="
1369				yield "\t{"
1370				for line in indentLines(["\t\ttcu::Format::BitDesc(%s,\t\"%s\")," % (n, n) for n, v in bitfield.values]):
1371					yield line
1372				yield "\t};"
1373				yield "\treturn tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));"
1374			else:
1375				yield "\treturn tcu::Format::Bitfield<32>(value, DE_NULL, DE_NULL);"
1376			yield "}"
1377
1378		bitfieldTypeNames = set([bitfield.name for bitfield in api.bitfields])
1379
1380		for type in api.compositeTypes:
1381			if not type.isAlias:
1382				yield ""
1383				yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % type.name
1384				yield "{"
1385				yield "\ts << \"%s = {\\n\";" % type.name
1386				for member in type.members:
1387					memberName	= member.name
1388					valFmt		= None
1389					newLine		= ""
1390					if member.getType() in bitfieldTypeNames:
1391						valFmt = "get%sStr(value.%s)" % (member.getType()[2:], member.name)
1392					elif member.getType() == "const char*" or member.getType() == "char*":
1393						valFmt = "getCharPtrStr(value.%s)" % member.name
1394					elif member.getType() == PLATFORM_TYPE_NAMESPACE + "::Win32LPCWSTR":
1395						valFmt = "getWStr(value.%s)" % member.name
1396					elif member.arraySize != '':
1397						singleDimensional = not '][' in member.arraySize
1398						if member.name in ["extensionName", "deviceName", "layerName", "description"]:
1399							valFmt = "(const char*)value.%s" % member.name
1400						elif singleDimensional and (member.getType() == 'char' or member.getType() == 'uint8_t'):
1401							newLine = "'\\n' << "
1402							valFmt	= "tcu::formatArray(tcu::Format::HexIterator<%s>(DE_ARRAY_BEGIN(value.%s)), tcu::Format::HexIterator<%s>(DE_ARRAY_END(value.%s)))" % (member.getType(), member.name, member.getType(), member.name)
1403						else:
1404							if member.name == "memoryTypes" or member.name == "memoryHeaps":
1405								endIter = "DE_ARRAY_BEGIN(value.%s) + value.%sCount" % (member.name, member.name[:-1])
1406							else:
1407								endIter = "DE_ARRAY_END(value.%s)" % member.name
1408							newLine = "'\\n' << "
1409							valFmt	= "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), %s)" % (member.name, endIter)
1410						memberName = member.name
1411					else:
1412						valFmt = "value.%s" % member.name
1413					yield ("\ts << \"\\t%s = \" << " % memberName) + newLine + valFmt + " << '\\n';"
1414				yield "\ts << '}';"
1415				yield "\treturn s;"
1416				yield "}"
1417	writeInlFile(filename, INL_HEADER, makeStrUtilImpl())
1418
1419
1420def writeObjTypeImpl (api, filename):
1421	def makeObjTypeImpl ():
1422
1423		yield "namespace vk"
1424		yield "{"
1425
1426		yield "template<typename T> VkObjectType getObjectType	(void);"
1427
1428		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]):
1429			yield line
1430
1431		yield "}"
1432
1433	writeInlFile(filename, INL_HEADER, makeObjTypeImpl())
1434
1435class ConstructorFunction:
1436	def __init__ (self, type, name, objectType, ifaceArgs, arguments):
1437		self.type		= type
1438		self.name		= name
1439		self.objectType	= objectType
1440		self.ifaceArgs	= ifaceArgs
1441		self.arguments	= arguments
1442
1443def getConstructorFunctions (api):
1444	funcs = []
1445	ifacesDict = {
1446		Function.TYPE_PLATFORM: [Variable("const PlatformInterface&", "vk", "")],
1447		Function.TYPE_INSTANCE: [Variable("const InstanceInterface&", "vk", "")],
1448		Function.TYPE_DEVICE: [Variable("const DeviceInterface&", "vk", "")]
1449	}
1450	for function in api.functions:
1451		if function.isAlias:
1452			continue
1453		if (function.name[:8] == "vkCreate" or function.name == "vkAllocateMemory") and not "createInfoCount" in [a.name for a in function.arguments]:
1454			if function.name == "vkCreateDisplayModeKHR":
1455				continue # No way to delete display modes (bug?)
1456
1457			# \todo [pyry] Rather hacky
1458			ifaceArgs = ifacesDict[function.getType()]
1459			if function.name == "vkCreateDevice":
1460				ifaceArgs = [Variable("const PlatformInterface&", "vkp", ""), Variable("VkInstance", "instance", "")] + ifaceArgs
1461
1462			assert (function.arguments[-2].type == ["const", "VkAllocationCallbacks", "*"])
1463
1464			objectType	= function.arguments[-1].type[0] #not getType() but type[0] on purpose
1465			arguments	= function.arguments[:-1]
1466			funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function), objectType, ifaceArgs, arguments))
1467	return funcs
1468
1469def addVersionDefines(versionSpectrum):
1470	output = ["#define " + ver.getDefineName() + " " + ver.getInHex() for ver in versionSpectrum if not ver.isStandardVersion()]
1471	return output
1472
1473def removeVersionDefines(versionSpectrum):
1474	output = ["#undef " + ver.getDefineName() for ver in versionSpectrum if not ver.isStandardVersion()]
1475	return output
1476
1477def writeRefUtilProto (api, filename):
1478	functions = getConstructorFunctions(api)
1479
1480	def makeRefUtilProto ():
1481		unindented = []
1482		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]):
1483			yield line
1484
1485	writeInlFile(filename, INL_HEADER, makeRefUtilProto())
1486
1487def writeRefUtilImpl (api, filename):
1488	functions = getConstructorFunctions(api)
1489
1490	def makeRefUtilImpl ():
1491		yield "namespace refdetails"
1492		yield "{"
1493		yield ""
1494
1495		for function in api.functions:
1496			if function.getType() == Function.TYPE_DEVICE \
1497			and (function.name[:9] == "vkDestroy" or function.name == "vkFreeMemory") \
1498			and not function.name == "vkDestroyDevice" \
1499			and not function.isAlias:
1500				objectType = function.arguments[-2].getType()
1501				yield "template<>"
1502				yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType)
1503				yield "{"
1504				yield "\tm_deviceIface->%s(m_device, obj, m_allocator);" % (getInterfaceName(function))
1505				yield "}"
1506				yield ""
1507
1508		yield "} // refdetails"
1509		yield ""
1510
1511		dtorDict = {
1512			Function.TYPE_PLATFORM: "object",
1513			Function.TYPE_INSTANCE: "instance",
1514			Function.TYPE_DEVICE: "device"
1515		}
1516
1517		for function in functions:
1518			deleterArgsString = ''
1519			if function.name == "createDevice":
1520				# createDevice requires two additional parameters to setup VkDevice deleter
1521				deleterArgsString = "vkp, instance, object, " +  function.arguments[-1].name
1522			else:
1523				deleterArgsString = "vk, %s, %s" % (dtorDict[function.type], function.arguments[-1].name)
1524
1525			yield "Move<%s> %s (%s)" % (function.objectType, function.name, argListToStr(function.ifaceArgs + function.arguments))
1526			yield "{"
1527			yield "\t%s object = 0;" % function.objectType
1528			yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"]))
1529			yield "\treturn Move<%s>(check<%s>(object), Deleter<%s>(%s));" % (function.objectType, function.objectType, function.objectType, deleterArgsString)
1530			yield "}"
1531			yield ""
1532
1533	writeInlFile(filename, INL_HEADER, makeRefUtilImpl())
1534
1535def writeStructTraitsImpl (api, filename):
1536	def gen ():
1537		for type in api.compositeTypes:
1538			if type.getClassName() == "struct" and type.members[0].name == "sType" and not type.isAlias and type.name != "VkBaseOutStructure" and type.name != "VkBaseInStructure":
1539				yield "template<> VkStructureType getStructureType<%s> (void)" % type.name
1540				yield "{"
1541				yield "\treturn %s;" % prefixName("VK_STRUCTURE_TYPE_", type.name)
1542				yield "}"
1543				yield ""
1544
1545	writeInlFile(filename, INL_HEADER, gen())
1546
1547def writeNullDriverImpl (api, filename):
1548	def genNullDriverImpl ():
1549		specialFuncNames	= [
1550				"vkCreateGraphicsPipelines",
1551				"vkCreateComputePipelines",
1552				"vkCreateRayTracingPipelinesNV",
1553				"vkCreateRayTracingPipelinesKHR",
1554				"vkGetInstanceProcAddr",
1555				"vkGetDeviceProcAddr",
1556				"vkEnumeratePhysicalDevices",
1557				"vkEnumerateInstanceExtensionProperties",
1558				"vkEnumerateDeviceExtensionProperties",
1559				"vkGetPhysicalDeviceFeatures",
1560				"vkGetPhysicalDeviceFeatures2KHR",
1561				"vkGetPhysicalDeviceProperties",
1562				"vkGetPhysicalDeviceProperties2KHR",
1563				"vkGetPhysicalDeviceQueueFamilyProperties",
1564				"vkGetPhysicalDeviceMemoryProperties",
1565				"vkGetPhysicalDeviceFormatProperties",
1566				"vkGetPhysicalDeviceImageFormatProperties",
1567				"vkGetDeviceQueue",
1568				"vkGetBufferMemoryRequirements",
1569				"vkGetBufferMemoryRequirements2KHR",
1570				"vkGetImageMemoryRequirements",
1571				"vkGetImageMemoryRequirements2KHR",
1572				"vkAllocateMemory",
1573				"vkMapMemory",
1574				"vkUnmapMemory",
1575				"vkAllocateDescriptorSets",
1576				"vkFreeDescriptorSets",
1577				"vkResetDescriptorPool",
1578				"vkAllocateCommandBuffers",
1579				"vkFreeCommandBuffers",
1580				"vkCreateDisplayModeKHR",
1581				"vkCreateSharedSwapchainsKHR",
1582				"vkGetPhysicalDeviceExternalBufferPropertiesKHR",
1583				"vkGetPhysicalDeviceImageFormatProperties2KHR",
1584				"vkGetMemoryAndroidHardwareBufferANDROID",
1585			]
1586
1587		coreFunctions		= [f for f in api.functions if not f.isAlias]
1588		specialFuncs		= [f for f in coreFunctions if f.name in specialFuncNames]
1589		createFuncs			= [f for f in coreFunctions if (f.name[:8] == "vkCreate" or f.name == "vkAllocateMemory") and not f in specialFuncs]
1590		destroyFuncs		= [f for f in coreFunctions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs]
1591		dummyFuncs			= [f for f in coreFunctions if f not in specialFuncs + createFuncs + destroyFuncs]
1592
1593		def getHandle (name):
1594			for handle in api.handles:
1595				if handle.name == name[0]:
1596					return handle
1597			raise Exception("No such handle: %s" % name)
1598
1599		for function in createFuncs:
1600			objectType	= function.arguments[-1].type[:-1]
1601			argsStr		= ", ".join([a.name for a in function.arguments[:-1]])
1602
1603			yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
1604			yield "{"
1605			yield "\tDE_UNREF(%s);" % function.arguments[-2].name
1606
1607			if getHandle(objectType).type == Handle.TYPE_NONDISP:
1608				yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[0][2:], objectType[0], argsStr)
1609			else:
1610				yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[0][2:], objectType[0], argsStr)
1611			yield "}"
1612			yield ""
1613
1614		for function in destroyFuncs:
1615			objectArg	= function.arguments[-2]
1616
1617			yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
1618			yield "{"
1619			for arg in function.arguments[:-2]:
1620				yield "\tDE_UNREF(%s);" % arg.name
1621
1622			if getHandle(objectArg.type).type == Handle.TYPE_NONDISP:
1623				yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.getType()[2:], objectArg.getType(), objectArg.name, function.arguments[-1].name)
1624			else:
1625				yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.getType()[2:], objectArg.getType(), objectArg.name, function.arguments[-1].name)
1626
1627			yield "}"
1628			yield ""
1629
1630		for function in dummyFuncs:
1631			yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
1632			yield "{"
1633			for arg in function.arguments:
1634				yield "\tDE_UNREF(%s);" % arg.name
1635			if function.returnType != "void":
1636				yield "\treturn VK_SUCCESS;"
1637			yield "}"
1638			yield ""
1639
1640		def genFuncEntryTable (type, name):
1641			funcs = [f for f in api.functions if f.getType() == type]
1642			refFuncs = {}
1643			for f in api.functions:
1644				if f.alias != None:
1645					refFuncs[f.alias] = f
1646
1647			yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name
1648			yield "{"
1649			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]):
1650				yield line
1651			yield "};"
1652			yield ""
1653
1654		# Func tables
1655		for line in genFuncEntryTable(Function.TYPE_PLATFORM, "s_platformFunctions"):
1656			yield line
1657
1658		for line in genFuncEntryTable(Function.TYPE_INSTANCE, "s_instanceFunctions"):
1659			yield line
1660
1661		for line in genFuncEntryTable(Function.TYPE_DEVICE, "s_deviceFunctions"):
1662			yield line
1663
1664	writeInlFile(filename, INL_HEADER, genNullDriverImpl())
1665
1666def writeTypeUtil (api, filename):
1667	# Structs filled by API queries are not often used in test code
1668	QUERY_RESULT_TYPES = set([
1669			"VkPhysicalDeviceFeatures",
1670			"VkPhysicalDeviceLimits",
1671			"VkFormatProperties",
1672			"VkImageFormatProperties",
1673			"VkPhysicalDeviceSparseProperties",
1674			"VkQueueFamilyProperties",
1675			"VkMemoryType",
1676			"VkMemoryHeap",
1677			"StdVideoH264SpsVuiFlags",
1678			"StdVideoH264SpsFlags",
1679			"StdVideoH264PpsFlags",
1680			"StdVideoDecodeH264PictureInfoFlags",
1681			"StdVideoDecodeH264ReferenceInfoFlags",
1682			"StdVideoEncodeH264SliceHeaderFlags",
1683			"StdVideoEncodeH264PictureInfoFlags",
1684			"StdVideoEncodeH264ReferenceInfoFlags",
1685			"StdVideoH265HrdFlags",
1686			"StdVideoH265VpsFlags",
1687			"StdVideoH265SpsVuiFlags",
1688			"StdVideoH265SpsFlags",
1689			"StdVideoH265PpsFlags",
1690			"StdVideoDecodeH265PictureInfoFlags",
1691			"StdVideoDecodeH265ReferenceInfoFlags",
1692			"StdVideoEncodeH265PictureInfoFlags",
1693			"StdVideoEncodeH265SliceHeaderFlags",
1694			"StdVideoEncodeH265ReferenceInfoFlags",
1695			"StdVideoEncodeH265SliceSegmentHeaderFlags",
1696			"StdVideoEncodeH264ReferenceListsInfoFlags",
1697			"StdVideoEncodeH265ReferenceListsInfoFlags",
1698		])
1699	COMPOSITE_TYPES = set([t.name for t in api.compositeTypes if not t.isAlias])
1700
1701	def isSimpleStruct (type):
1702		def hasArrayMember (type):
1703			for member in type.members:
1704				if member.arraySize != '':
1705					return True
1706			return False
1707
1708		def hasCompositeMember (type):
1709			for member in type.members:
1710				if member.getType() in COMPOSITE_TYPES:
1711					return True
1712			return False
1713
1714		return type.typeClass == CompositeType.CLASS_STRUCT and \
1715		type.members[0].getType() != "VkStructureType" and \
1716		not type.name in QUERY_RESULT_TYPES and \
1717		not hasArrayMember(type) and \
1718		not hasCompositeMember(type)
1719
1720	def gen ():
1721		for type in api.compositeTypes:
1722			if not isSimpleStruct(type) or type.isAlias:
1723				continue
1724
1725			name = type.name[2:] if type.name[:2].lower() == "vk" else type.name
1726
1727			yield ""
1728			yield "inline %s make%s (%s)" % (type.name, name, argListToStr(type.members))
1729			yield "{"
1730			yield "\t%s res;" % type.name
1731			for line in indentLines(["\tres.%s\t= %s;" % (m.name, m.name) for m in type.members]):
1732				yield line
1733			yield "\treturn res;"
1734			yield "}"
1735
1736	writeInlFile(filename, INL_HEADER, gen())
1737
1738def writeDriverIds(apiName, filename):
1739
1740	driverIdsString = []
1741	driverIdsString.append("static const struct\n"
1742					 "{\n"
1743					 "\tstd::string driver;\n"
1744					 "\tuint32_t id;\n"
1745					 "} driverIds [] =\n"
1746					 "{")
1747
1748	vulkanHeaderFile = { "" :	os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "vulkan", "vulkan_core.h"),
1749						"SC" :	os.path.join(SCRIPTS_SRC_DIR, "vulkan_sc_core.h") }
1750	vulkanCore = readFile(vulkanHeaderFile[apiName])
1751
1752	items = re.search(r'(?:typedef\s+enum\s+VkDriverId\s*{)((.*\n)*)(?:}\s*VkDriverId\s*;)', vulkanCore).group(1).split(',')
1753	driverItems = dict()
1754	for item in items:
1755		item.strip()
1756		splitted = item.split('=')
1757		key = splitted[0].strip()
1758		value_str = splitted[1].strip()
1759		try: # is this previously defined value?
1760			value = driverItems[value_str]
1761		except:
1762			value = value_str
1763			value_str = ""
1764		if value_str:
1765			value_str = "\t// " + value_str
1766		driverItems[key] = value
1767		if not item == items[-1]:
1768			driverIdsString.append("\t{\"" + key + "\"" + ", " + value + "}," + value_str)
1769		else:
1770			driverIdsString.append("\t{\"" + key + "\"" + ", " + value + "}" + value_str)
1771		driverItems[key] = value
1772
1773	driverIdsString.append("};")
1774
1775	writeInlFile(filename, INL_HEADER, driverIdsString)
1776
1777
1778def writeSupportedExtensions(apiName, api, filename):
1779
1780	def writeExtensionsForVersions(map):
1781		result = []
1782		for version in map:
1783			result.append("	if (coreVersion >= " + str(version) + ")")
1784			result.append("	{")
1785			for extension in map[version]:
1786				result.append('		dst.push_back("' + extension.name + '");')
1787			result.append("	}")
1788
1789		if not map:
1790			result.append("	DE_UNREF(coreVersion);")
1791
1792		return result
1793
1794	instanceMap		= {}
1795	deviceMap		= {}
1796	versionSet		= set()
1797
1798	for ext in api.extensions:
1799		if ext.versionInCore != None:
1800			currVersion = Version(ext.versionInCore[1:])
1801			# VulkanSC is based on Vulkan 1.2. Any Vulkan version greater than 1.2 should be excluded
1802			if apiName=='SC' and currVersion.api==0 and currVersion.major==1 and currVersion.minor>2:
1803				continue
1804			if ext.versionInCore[0] == 'instance':
1805				list = instanceMap.get(Version(ext.versionInCore[1:]))
1806				instanceMap[Version(ext.versionInCore[1:])] = list + [ext] if list else [ext]
1807			else:
1808				list = deviceMap.get(Version(ext.versionInCore[1:]))
1809				deviceMap[Version(ext.versionInCore[1:])] = list + [ext] if list else [ext]
1810			versionSet.add(Version(ext.versionInCore[1:]))
1811
1812	# add list of extensions missing in Vulkan SC specification
1813	if apiName == 'SC':
1814		for extensionName, data in api.additionalExtensionData:
1815			# make sure that this extension was registered
1816			if 'register_extension' not in data.keys():
1817				continue
1818			# save array containing 'device' or 'instance' string followed by the optional vulkan version in which this extension is core;
1819			# note that register_extension section is also required for partialy promoted extensions like VK_EXT_extended_dynamic_state2
1820			# but those extensions should not fill 'core' tag
1821			match = re.match("(\d).(\d).(\d).(\d)", data['register_extension']['core'])
1822			if match != None:
1823				currVersion = Version([int(match.group(1)), int(match.group(2)), int(match.group(3)), int(match.group(4))])
1824				ext = Extension(extensionName, 0, 0, 0, 0, 0, 0, 0, 0, 0)
1825				if currVersion.api==0 and currVersion.major==1 and currVersion.minor>2:
1826					continue
1827				if data['register_extension']['type'] == 'instance':
1828					list = instanceMap.get(currVersion)
1829					instanceMap[currVersion] = list + [ext] if list else [ext]
1830				else:
1831					list = deviceMap.get(currVersion)
1832					deviceMap[currVersion] = list + [ext] if list else [ext]
1833				versionSet.add(currVersion)
1834
1835	lines = addVersionDefines(versionSet) + [
1836	"",
1837	"void getCoreDeviceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(deviceMap) != 0 or apiName == 'SC' else ""),
1838	"{"] + writeExtensionsForVersions(deviceMap) + [
1839	"}",
1840	"",
1841	"void getCoreInstanceExtensionsImpl (uint32_t coreVersion, ::std::vector<const char*>&%s)" % (" dst" if len(instanceMap) != 0 or apiName == 'SC' else ""),
1842	"{"] + writeExtensionsForVersions(instanceMap) + [
1843	"}",
1844	""] + removeVersionDefines(versionSet)
1845	writeInlFile(filename, INL_HEADER, lines)
1846
1847
1848def writeExtensionFunctions (api, filename):
1849
1850	def isInstanceExtension (ext):
1851		if ext.name and ext.functions:
1852			if ext.functions[0].getType() == Function.TYPE_INSTANCE:
1853				return True
1854			else:
1855				return False
1856
1857	def isDeviceExtension (ext):
1858		if ext.name and ext.functions:
1859			if ext.functions[0].getType() == Function.TYPE_DEVICE:
1860				return True
1861			else:
1862				return False
1863
1864	def writeExtensionNameArrays ():
1865		instanceExtensionNames = []
1866		deviceExtensionNames = []
1867		for ext in api.extensions:
1868			if ext.name and isInstanceExtension(ext):
1869				instanceExtensionNames += [ext.name]
1870			elif ext.name and isDeviceExtension(ext):
1871				deviceExtensionNames += [ext.name]
1872		yield '::std::string instanceExtensionNames[] =\n{'
1873		for instanceExtName in instanceExtensionNames:
1874			if (instanceExtName == instanceExtensionNames[len(instanceExtensionNames) - 1]):
1875				yield '\t"%s"' % instanceExtName
1876			else:
1877				yield '\t"%s",' % instanceExtName
1878		yield '};\n'
1879		yield '::std::string deviceExtensionNames[] =\n{'
1880		for deviceExtName in deviceExtensionNames:
1881			if (deviceExtName == deviceExtensionNames[len(deviceExtensionNames) - 1]):
1882				yield '\t"%s"' % deviceExtName
1883			else:
1884				yield '\t"%s",' % deviceExtName
1885		yield '};'
1886
1887	def writeExtensionFunctions (functionType):
1888		isFirstWrite = True
1889		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
1890		if functionType == Function.TYPE_INSTANCE:
1891			yield 'void getInstanceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{'
1892			dg_list = ["vkGetPhysicalDevicePresentRectanglesKHR"]
1893		elif functionType == Function.TYPE_DEVICE:
1894			yield 'void getDeviceExtensionFunctions (uint32_t apiVersion, ::std::string extName, ::std::vector<const char*>& functions)\n{'
1895			dg_list = ["vkGetDeviceGroupPresentCapabilitiesKHR", "vkGetDeviceGroupSurfacePresentModesKHR", "vkAcquireNextImage2KHR"]
1896		for ext in api.extensions:
1897			funcNames = []
1898			if ext.name:
1899				for func in ext.functions:
1900					if func.getType() == functionType:
1901						# only add functions with same vendor as extension
1902						# this is a workaroudn for entrypoints requiring more
1903						# than one excetions and lack of the dependency in vulkan_core.h
1904						vendor = ext.name.split('_')[1]
1905						if func.name.endswith(vendor):
1906							funcNames.append(func.name)
1907			if ext.name:
1908				yield '\tif (extName == "%s")' % ext.name
1909				yield '\t{'
1910				for funcName in funcNames:
1911					if funcName in dg_list:
1912						yield '\t\tif(apiVersion >= VK_API_VERSION_1_1) functions.push_back("%s");' % funcName
1913					else:
1914						yield '\t\tfunctions.push_back("%s");' % funcName
1915				if ext.name == "VK_KHR_device_group":
1916					for dg_func in dg_list:
1917						yield '\t\tif(apiVersion < VK_API_VERSION_1_1) functions.push_back("%s");' % dg_func
1918				yield '\t\treturn;'
1919				yield '\t}'
1920				isFirstWrite = False
1921		if not isFirstWrite:
1922			yield '\tDE_FATAL("Extension name not found");'
1923			yield '}'
1924
1925	lines = ['']
1926	for line in writeExtensionFunctions(Function.TYPE_INSTANCE):
1927		lines += [line]
1928	lines += ['']
1929	for line in writeExtensionFunctions(Function.TYPE_DEVICE):
1930		lines += [line]
1931	lines += ['']
1932	for line in writeExtensionNameArrays():
1933		lines += [line]
1934
1935	writeInlFile(filename, INL_HEADER, lines)
1936
1937def writeCoreFunctionalities(api, filename):
1938	functionOriginValues    = ["FUNCTIONORIGIN_PLATFORM", "FUNCTIONORIGIN_INSTANCE", "FUNCTIONORIGIN_DEVICE"]
1939	lines					= addVersionDefines(api.versions) + [
1940	"",
1941	'enum FunctionOrigin', '{'] + [line for line in indentLines([
1942	'\t' + functionOriginValues[0] + '\t= 0,',
1943	'\t' + functionOriginValues[1] + ',',
1944	'\t' + functionOriginValues[2]])] + [
1945	"};",
1946	"",
1947	"typedef ::std::pair<const char*, FunctionOrigin> FunctionInfo;",
1948	"typedef ::std::vector<FunctionInfo> FunctionInfosList;",
1949	"typedef ::std::map<uint32_t, FunctionInfosList> ApisMap;",
1950	"",
1951	"void initApisMap (ApisMap& apis)",
1952	"{",
1953	"	apis.clear();"] + [
1954	"	apis.insert(::std::pair<uint32_t, FunctionInfosList>(" + str(v) + ", FunctionInfosList()));" for v in api.versions] + [
1955	""]
1956
1957	apiVersions = []
1958	for index, v in enumerate(api.versions):
1959		funcs = []
1960		apiVersions.append("VK_VERSION_{0}_{1}".format(v.major, v.minor))
1961		# iterate over all functions that are core in latest vulkan version
1962		# note that first item in api.extension array are actually all definitions that are in vulkan.h.in before section with extensions
1963		for fun in api.extensions[0].functions:
1964			if fun.apiVersion in apiVersions:
1965				funcs.append('	apis[' + str(v) + '].push_back(FunctionInfo("' + fun.name + '",\t' + functionOriginValues[fun.getType()] + '));')
1966		lines = lines + [line for line in indentLines(funcs)] + [""]
1967
1968	lines = lines + ["}", ""] + removeVersionDefines(api.versions)
1969	writeInlFile(filename, INL_HEADER, lines)
1970
1971def camelToSnake(name):
1972    name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
1973    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()
1974
1975def writeDeviceFeatures2(api, filename):
1976	def structInAPI(name):
1977		for c in api.compositeTypes:
1978			if c.name == name:
1979				return True
1980		return False
1981
1982	# list of structures that should be tested with getPhysicalDeviceFeatures2
1983	# this is not posible to determine from vulkan_core.h, if new feature structures
1984	# are added they should be manualy added to this list
1985	testedStructures = [
1986		'VkPhysicalDevice4444FormatsFeaturesEXT',
1987		'VkPhysicalDevice8BitStorageFeatures',
1988		'VkPhysicalDevice16BitStorageFeatures',
1989		'VkPhysicalDeviceAccelerationStructureFeaturesKHR',
1990		'VkPhysicalDeviceASTCDecodeFeaturesEXT',
1991		'VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT',
1992		'VkPhysicalDeviceBufferDeviceAddressFeaturesEXT',
1993		'VkPhysicalDeviceBufferDeviceAddressFeatures',
1994		'VkPhysicalDeviceConditionalRenderingFeaturesEXT',
1995		'VkPhysicalDeviceCustomBorderColorFeaturesEXT',
1996		'VkPhysicalDeviceColorWriteEnableFeaturesEXT',
1997		'VkPhysicalDeviceDescriptorIndexingFeatures',
1998		'VkPhysicalDeviceDepthClipEnableFeaturesEXT',
1999		'VkPhysicalDeviceDynamicRenderingFeatures',
2000		'VkPhysicalDeviceExtendedDynamicStateFeaturesEXT',
2001		'VkPhysicalDeviceExtendedDynamicState2FeaturesEXT',
2002		'VkPhysicalDeviceFragmentDensityMapFeaturesEXT',
2003		'VkPhysicalDeviceFragmentDensityMap2FeaturesEXT',
2004		'VkPhysicalDeviceFragmentShadingRateFeaturesKHR',
2005		'VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR',
2006		'VkPhysicalDeviceInlineUniformBlockFeatures',
2007		'VkPhysicalDeviceIndexTypeUint8FeaturesEXT',
2008		'VkPhysicalDeviceImagelessFramebufferFeatures',
2009		'VkPhysicalDeviceImageRobustnessFeatures',
2010		'VkPhysicalDeviceHostQueryResetFeatures',
2011		'VkPhysicalDeviceLineRasterizationFeaturesEXT',
2012		'VkPhysicalDeviceMaintenance4Features',
2013		'VkPhysicalDeviceMultiviewFeatures',
2014		'VkPhysicalDeviceMultiDrawFeaturesEXT',
2015		'VkPhysicalDeviceMemoryPriorityFeaturesEXT',
2016		'VkPhysicalDeviceDeviceMemoryReportFeaturesEXT',
2017		'VkPhysicalDevicePerformanceQueryFeaturesKHR',
2018		'VkPhysicalDevicePipelineCreationCacheControlFeatures',
2019		'VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR',
2020		'VkPhysicalDevicePresentIdFeaturesKHR',
2021		'VkPhysicalDevicePresentWaitFeaturesKHR',
2022		'VkPhysicalDeviceProtectedMemoryFeatures',
2023		'VkPhysicalDeviceProvokingVertexFeaturesEXT',
2024		'VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT',
2025		'VkPhysicalDevicePrivateDataFeatures',
2026		'VkPhysicalDeviceRayTracingPipelineFeaturesKHR',
2027		'VkPhysicalDeviceRayQueryFeaturesKHR',
2028		'VkPhysicalDeviceRobustness2FeaturesEXT',
2029		'VkPhysicalDeviceSamplerYcbcrConversionFeatures',
2030		'VkPhysicalDeviceScalarBlockLayoutFeatures',
2031		'VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures',
2032		'VkPhysicalDeviceShaderAtomicInt64Features',
2033		'VkPhysicalDeviceShaderAtomicFloatFeaturesEXT',
2034		'VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT',
2035		'VkPhysicalDeviceShaderFloat16Int8Features',
2036		'VkPhysicalDeviceShaderClockFeaturesKHR',
2037		'VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures',
2038		'VkPhysicalDeviceShaderDrawParametersFeatures',
2039		'VkPhysicalDeviceShaderIntegerDotProductFeatures',
2040		'VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures',
2041		'VkPhysicalDeviceShaderTerminateInvocationFeatures',
2042		'VkPhysicalDeviceSubgroupSizeControlFeatures',
2043		'VkPhysicalDeviceSynchronization2Features',
2044		'VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT',
2045		'VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT',
2046		'VkPhysicalDeviceTextureCompressionASTCHDRFeatures',
2047		'VkPhysicalDeviceTimelineSemaphoreFeatures',
2048		'VkPhysicalDeviceTransformFeedbackFeaturesEXT',
2049		'VkPhysicalDeviceUniformBufferStandardLayoutFeatures',
2050		'VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR',
2051		'VkPhysicalDeviceVariablePointersFeatures',
2052		'VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT',
2053		'VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT',
2054		'VkPhysicalDeviceVulkanMemoryModelFeaturesKHR',
2055		'VkPhysicalDeviceYcbcrImageArraysFeaturesEXT',
2056		'VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT',
2057		'VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures',
2058	]
2059
2060	# helper class used to encapsulate all data needed during generation
2061	class StructureDetail:
2062		def __init__ (self, name):
2063			nameResult			= re.search('(.*)Features(.*)', name[len('VkPhysicalDevice'):])
2064			nameSplitUp			= ''
2065			# generate structure type name from structure name
2066			# note that sometimes digits are separated with '_':
2067			# VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT
2068			# but mostly they are not:
2069			# VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES
2070			specialCaseDict = {
2071				'FragmentDensityMap2'			: ['FRAGMENT', 'DENSITY', 'MAP', '2'],
2072				'Ycbcr2Plane444Formats'			: ['YCBCR', '2', 'PLANE', '444', 'FORMATS'],
2073				'ASTCDecode'					: ['ASTC', 'DECODE'],
2074				'4444Formats'					: ['4444', 'FORMATS'],
2075				'TextureCompressionASTCHDR'		: ['TEXTURE', 'COMPRESSION', 'ASTC', 'HDR'],
2076				'Synchronization2'				: ['SYNCHRONIZATION', '2'],
2077				'ShaderAtomicFloat2'			: ['SHADER', 'ATOMIC', 'FLOAT', '2'],
2078				'Robustness2'					: ['ROBUSTNESS', '2'],
2079				'Maintenance4'					: ['MAINTENANCE', '4'],
2080				'ExtendedDynamicState2'			: ['EXTENDED', 'DYNAMIC', 'STATE', '2'],
2081			}
2082			nameSplitUp = specialCaseDict.get(nameResult.group(1))
2083			if nameSplitUp == None:
2084				nameSplit		= re.findall(r'[1-9A-Z]+(?:[a-z1-9]+|[A-Z]*(?=[A-Z]|$))', nameResult.group(1))
2085				nameSplitUp		= map(str.upper, nameSplit)
2086			nameSplitUp = list(nameSplitUp) + ['FEATURES']
2087			# check if there is extension suffix
2088			if (len(nameResult.group(2)) != 0):
2089				nameSplitUp.append(nameResult.group(2))
2090			self.name			= name
2091			self.sType			= 'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_' + '_'.join(nameSplitUp)
2092			self.instanceName	= 'd' + name[11:]
2093			self.flagName		= 'is' + name[16:]
2094			self.extension		= None
2095			self.api			= None
2096			self.major			= None
2097			self.minor			= None
2098			self.members		= []
2099	# helper extension class used in algorith below
2100	class StructureFoundContinueToNextOne(Exception):
2101		pass
2102	existingStructures = list(filter(structInAPI, testedStructures)) # remove features not found in API ( important for Vulkan SC )
2103	testedStructureDetail = [StructureDetail(struct) for struct in existingStructures]
2104	# iterate over all searched structures and find extensions that enable them
2105	for structureDetail in testedStructureDetail:
2106		try:
2107			# iterate over all extensions
2108			for extension in api.extensions[1:]:
2109				# check composite types and typedefs in case extension is part of core
2110				for structureList in [extension.compositeTypes, extension.typedefs]:
2111					# iterate over all structures added by extension
2112					for extensionStructure in structureList:
2113						# compare checked structure name to name of structure from extension
2114						if structureDetail.name == extensionStructure.name:
2115							structureDetail.extension = extension.name
2116							if extension.versionInCore is not None:
2117								structureDetail.api   = extension.versionInCore[1]
2118								structureDetail.major = extension.versionInCore[2]
2119								structureDetail.minor = extension.versionInCore[3]
2120							raise StructureFoundContinueToNextOne
2121		except StructureFoundContinueToNextOne:
2122			continue
2123	for structureDetail in testedStructureDetail:
2124		for compositeType in api.compositeTypes:
2125			if structureDetail.name != compositeType.name:
2126				continue
2127			structureMembers = compositeType.members[2:]
2128			structureDetail.members = [m.name for m in structureMembers]
2129			if structureDetail.major is not None:
2130				break
2131			# if structure was not added with extension then check if
2132			# it was added directly with one of vulkan versions
2133			apiVersion = compositeType.apiVersion
2134			if apiVersion is None:
2135				continue
2136			structureDetail.api   = apiVersion.api
2137			structureDetail.major = apiVersion.major
2138			structureDetail.minor = apiVersion.minor
2139			break
2140	# generate file content
2141	structureDefinitions = []
2142	featureEnabledFlags = []
2143	clearStructures = []
2144	structureChain = []
2145	logStructures = []
2146	verifyStructures = []
2147	for index, structureDetail in enumerate(testedStructureDetail):
2148		# create two instances of each structure
2149		nameSpacing = '\t'
2150		structureDefinitions.append(structureDetail.name + nameSpacing + structureDetail.instanceName + '[count];')
2151		# create flags that check if proper extension or vulkan version is available
2152		condition	= ''
2153		extension	= structureDetail.extension
2154		major		= structureDetail.major
2155		if extension is not None:
2156			condition = ' checkExtension(properties, "' + extension + '")'
2157		if major is not None:
2158			if condition != '':
2159				condition += ' || '
2160			else:
2161				condition += ' '
2162			condition += 'context.contextSupports(vk::ApiVersion(' + str(structureDetail.api) + ', ' + str(major) + ', ' + str(structureDetail.minor) + ', 0))'
2163		if condition == '':
2164			condition = 'true'
2165		condition += ';'
2166		nameSpacing = '\t' * int((len(structureDetail.name) - 4) / 4)
2167		featureEnabledFlags.append('const bool' + nameSpacing + structureDetail.flagName + ' =' + condition)
2168		# clear memory of each structure
2169		clearStructures.append('\tdeMemset(&' + structureDetail.instanceName + '[ndx], 0xFF * ndx, sizeof(' + structureDetail.name + '));')
2170		# construct structure chain
2171		nextInstanceName = 'DE_NULL';
2172		if index < len(testedStructureDetail)-1:
2173			nextInstanceName = '&' + testedStructureDetail[index+1].instanceName + '[ndx]'
2174		structureChain.append([
2175			'\t\t' + structureDetail.instanceName + '[ndx].sType = ' + structureDetail.flagName + ' ? ' + structureDetail.sType + ' : VK_STRUCTURE_TYPE_MAX_ENUM;',
2176			'\t\t' + structureDetail.instanceName + '[ndx].pNext = DE_NULL;'])
2177		# construct log section
2178		logStructures.append([
2179			'\tif (' + structureDetail.flagName + ')',
2180			'\t\tlog << TestLog::Message << ' + structureDetail.instanceName + '[0] << TestLog::EndMessage;'
2181			])
2182		#construct verification section
2183		verifyStructure = []
2184		verifyStructure.append('\tif (' + structureDetail.flagName + ' &&')
2185		for index, m in enumerate(structureDetail.members):
2186			prefix = '\t\t(' if index == 0 else '\t\t '
2187			postfix = '))' if index == len(structureDetail.members)-1 else ' ||'
2188			verifyStructure.append(prefix + structureDetail.instanceName + '[0].' + m + ' != ' + structureDetail.instanceName + '[1].' + m + postfix)
2189		if len(structureDetail.members) == 0:
2190			verifyStructure.append('\t\tfalse)')
2191		verifyStructure.append('\t{\n\t\tTCU_FAIL("Mismatch between ' + structureDetail.name + '");\n\t}')
2192		verifyStructures.append(verifyStructure)
2193
2194	# construct file content
2195	stream = []
2196
2197	# individual test functions
2198	for n, x in enumerate(testedStructureDetail):
2199		stream.append("tcu::TestStatus testPhysicalDeviceFeature" + x.instanceName[len('device'):]+" (Context& context)")
2200		stream.append("""{
2201	const VkPhysicalDevice		physicalDevice	= context.getPhysicalDevice();
2202	const CustomInstance		instance		(createCustomInstanceWithExtension(context, "VK_KHR_get_physical_device_properties2"));
2203	const InstanceDriver&		vki				(instance.getDriver());
2204	const int					count			= 2u;
2205	TestLog&					log				= context.getTestContext().getLog();
2206	VkPhysicalDeviceFeatures2	extFeatures;
2207	vector<VkExtensionProperties> properties	= enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL);
2208""")
2209		stream.append("\t"+structureDefinitions[n])
2210		stream.append("\t"+featureEnabledFlags[n])
2211		stream.append('')
2212		stream.append('\tfor (int ndx = 0; ndx < count; ++ndx)\n\t{')
2213		stream.append("\t" + clearStructures[n])
2214		stream.extend(structureChain[n])
2215		stream.append('')
2216		stream.append(
2217				'\t\tdeMemset(&extFeatures.features, 0xcd, sizeof(extFeatures.features));\n'
2218				'\t\textFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n'
2219				'\t\textFeatures.pNext = &' + testedStructureDetail[n].instanceName + '[ndx];\n\n'
2220				'\t\tvki.getPhysicalDeviceFeatures2(physicalDevice, &extFeatures);')
2221		stream.append('\t}\n')
2222		stream.extend(logStructures[n])
2223		stream.append('')
2224		stream.extend(verifyStructures[n])
2225		stream.append('\treturn tcu::TestStatus::pass("Querying succeeded");')
2226		stream.append("}\n")
2227
2228	# function to create tests
2229	stream.append("""
2230void addSeparateFeatureTests (tcu::TestCaseGroup* testGroup)
2231{
2232""")
2233	for x in testedStructureDetail:
2234		stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x.instanceName[len('device'):]) + '", testPhysicalDeviceFeature' + x.instanceName[len('device'):] + ');')
2235	stream.append('}\n')
2236
2237	# write out
2238	writeInlFile(filename, INL_HEADER, stream)
2239
2240def generateDeviceFeaturesDefs(apiName, src):
2241	# look for definitions
2242	ptrnSType	= r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_FEATURES(\w*)\s*='
2243	matches		= re.findall(ptrnSType, src, re.M)
2244	matches		= sorted(matches, key=lambda m: m[0])
2245	# hardcoded list of core extensions having features and missing from Vulkan SC
2246	missingVulkanSCExt = \
2247		'#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME \"VK_KHR_16bit_storage\"\n' \
2248		'#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME \"VK_KHR_8bit_storage\"\n' \
2249		'#define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME \"VK_KHR_buffer_device_address\"\n' \
2250		'#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME \"VK_EXT_descriptor_indexing\"\n' \
2251		'#define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME \"VK_EXT_host_query_reset\"\n' \
2252		'#define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME \"VK_KHR_imageless_framebuffer\"\n' \
2253		'#define VK_KHR_MULTIVIEW_EXTENSION_NAME   \"VK_KHR_multiview\"\n' \
2254		'#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME \"VK_KHR_sampler_ycbcr_conversion\"\n' \
2255		'#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME \"VK_EXT_scalar_block_layout\"\n' \
2256		'#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME \"VK_KHR_separate_depth_stencil_layouts\"\n' \
2257		'#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME \"VK_KHR_shader_atomic_int64\"\n' \
2258		'#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME \"VK_KHR_shader_draw_parameters\"\n' \
2259		'#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME \"VK_KHR_shader_float16_int8\"\n' \
2260		'#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME \"VK_KHR_shader_subgroup_extended_types\"\n' \
2261		'#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME \"VK_KHR_timeline_semaphore\"\n' \
2262		'#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME \"VK_KHR_uniform_buffer_standard_layout\"\n' \
2263		'#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME \"VK_KHR_variable_pointers\"\n' \
2264		'#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME \"VK_KHR_vulkan_memory_model\"\n'
2265	# construct final list
2266	defs = []
2267	for sType, sSuffix in matches:
2268		structName			= re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '')
2269		ptrnStructName		= r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Features' + sSuffix.replace('_', '') + ')'
2270		matchStructName		= re.search(ptrnStructName, src, re.IGNORECASE)
2271		if matchStructName:
2272			# handle special cases
2273			if sType == "EXCLUSIVE_SCISSOR":
2274				sType = "SCISSOR_EXCLUSIVE"
2275			elif sType == "ASTC_DECODE":
2276				sType = "ASTC_DECODE_MODE"
2277			elif sType == "MAINTENANCE_4":
2278				sType = "MAINTENANCE4"
2279			elif sType == "YCBCR_2_PLANE_444_FORMATS":
2280				sType = "YCBCR_2PLANE_444_FORMATS"
2281			elif sType in {'VULKAN_1_1', 'VULKAN_1_2', 'VULKAN_1_3'}:
2282				continue
2283			elif sType == 'RASTERIZATION_ORDER_ATTACHMENT_ACCESS':
2284				# skip case that has const pNext pointer
2285				continue
2286			# end handling special cases
2287			ptrnExtensionName	= r'^\s*#define\s+(\w+' + sSuffix + '_' + sType + '_EXTENSION_NAME).+$'
2288			matchExtensionName	= re.search(ptrnExtensionName, src, re.M)
2289			if matchExtensionName is None and apiName=='SC':
2290				matchExtensionName	= re.search(ptrnExtensionName, missingVulkanSCExt, re.M)
2291			ptrnSpecVersion		= r'^\s*#define\s+(\w+' + sSuffix + '_' + sType + '_SPEC_VERSION).+$'
2292			matchSpecVersion	= re.search(ptrnSpecVersion, src, re.M)
2293			defs.append( (sType, '', sSuffix, matchStructName.group(1), \
2294							matchExtensionName.group(0)	if matchExtensionName	else None,
2295							matchExtensionName.group(1)	if matchExtensionName	else None,
2296							matchSpecVersion.group(1)	if matchSpecVersion		else '0') )
2297	return defs
2298
2299def generateDevicePropertiesDefs(apiName, src):
2300	# look for definitions
2301	ptrnSType	= r'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_(\w+)_PROPERTIES(\w*)\s*='
2302	matches		= re.findall(ptrnSType, src, re.M)
2303	matches		= sorted(matches, key=lambda m: m[0])
2304	# hardcoded list of core extensions having properties and missing from Vulkan SC
2305	missingVulkanSCExt = \
2306		'#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME \"VK_KHR_depth_stencil_resolve\"\n' \
2307		'#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME \"VK_EXT_descriptor_indexing\"\n' \
2308		'#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME \"VK_KHR_driver_properties\"\n' \
2309		'#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME \"VK_KHR_shader_float_controls\"\n' \
2310		'#define VK_KHR_MAINTENANCE3_EXTENSION_NAME \"VK_KHR_maintenance3\"\n' \
2311		'#define VK_KHR_MULTIVIEW_EXTENSION_NAME   \"VK_KHR_multiview\"\n' \
2312		'#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME \"VK_EXT_sampler_filter_minmax\"\n' \
2313		'#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME \"VK_KHR_timeline_semaphore\"\n'
2314	# construct final list
2315	defs = []
2316	for sType, sSuffix in matches:
2317		# handle special cases
2318		if sType in {'VULKAN_1_1', 'VULKAN_1_2', 'VULKAN_1_3', 'VULKAN_SC_1_0', 'GROUP', 'MEMORY_BUDGET', 'MEMORY', 'TOOL'}:
2319			continue
2320		# there are cases like VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD
2321		# where 2 is after PROPERTIES - to handle this we need to split suffix to two parts
2322		sVerSuffix = ''
2323		sExtSuffix = sSuffix
2324		suffixStart = sSuffix.rfind('_')
2325		if suffixStart > 0:
2326			sVerSuffix = sSuffix[:suffixStart]
2327			sExtSuffix = sSuffix[suffixStart:]
2328		# handle special case
2329		if sType == "ID":
2330			structName	= sType
2331		else:
2332			structName	= re.sub("[_0-9][a-z]", lambda match: match.group(0).upper(), sType.capitalize()).replace('_', '')
2333		ptrnStructName		= r'\s*typedef\s+struct\s+(VkPhysicalDevice' + structName + 'Properties' + sSuffix.replace('_', '') + ')'
2334		matchStructName		= re.search(ptrnStructName, src, re.M)
2335		if matchStructName:
2336			extType = sType
2337			if extType == "DISCARD_RECTANGLE":
2338				extType = "DISCARD_RECTANGLES"
2339			elif extType == "DRIVER":
2340				extType = "DRIVER_PROPERTIES"
2341			elif extType == "POINT_CLIPPING":
2342				extType = "MAINTENANCE_2"
2343			elif extType == "SHADER_CORE":
2344				extType = "SHADER_CORE_PROPERTIES"
2345			elif extType == "DRM":
2346				extType = "PHYSICAL_DEVICE_DRM"
2347			if apiName == 'SC':
2348				if extType == "MAINTENANCE_3":
2349					extType = "MAINTENANCE3"
2350				elif extType == "MAINTENANCE_4":
2351					extType = "MAINTENANCE4"
2352				elif extType == "POINT_CLIPPING":
2353					extType = "MAINTENANCE2"
2354			# end handling special cases
2355			ptrnExtensionName	= r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix +'[_0-9]*_EXTENSION_NAME).+$'
2356			matchExtensionName	= re.search(ptrnExtensionName, src, re.M)
2357			if matchExtensionName is None and apiName=='SC':
2358				matchExtensionName	= re.search(ptrnExtensionName, missingVulkanSCExt, re.M)
2359			ptrnSpecVersion		= r'^\s*#define\s+(\w+' + sExtSuffix + '_' + extType + sVerSuffix + '[_0-9]*_SPEC_VERSION).+$'
2360			matchSpecVersion	= re.search(ptrnSpecVersion, src, re.M)
2361			defs.append( (sType, sVerSuffix, sExtSuffix, matchStructName.group(1), \
2362							matchExtensionName.group(0)	if matchExtensionName	else None,
2363							matchExtensionName.group(1)	if matchExtensionName	else None,
2364							matchSpecVersion.group	(1)	if matchSpecVersion		else '0') )
2365	return defs
2366
2367def writeDeviceFeatures(api, dfDefs, filename):
2368	# find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs
2369	# and construct dictionary with all of their attributes
2370	blobMembers = {}
2371	blobStructs = {}
2372	blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$")
2373	for structureType in api.compositeTypes:
2374		match = blobPattern.match(structureType.name)
2375		if match:
2376			allMembers = [member.name for member in structureType.members]
2377			vkVersion = match.group(1)
2378			blobMembers[vkVersion] = allMembers[2:]
2379			blobStructs[vkVersion] = set()
2380	initFromBlobDefinitions = []
2381	emptyInitDefinitions = []
2382	# iterate over all feature structures
2383	allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*")
2384	nonExtFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*$")
2385	for structureType in api.compositeTypes:
2386		# skip structures that are not feature structures
2387		if not allFeaturesPattern.match(structureType.name):
2388			continue
2389		# skip structures that were previously identified as blobs
2390		if blobPattern.match(structureType.name):
2391			continue
2392		if structureType.isAlias:
2393			continue
2394		# skip sType and pNext and just grab third and next attributes
2395		structureMembers = structureType.members[2:]
2396		notPartOfBlob = True
2397		if nonExtFeaturesPattern.match(structureType.name):
2398			# check if this member is part of any of the blobs
2399			for blobName, blobMemberList in blobMembers.items():
2400				# if just one member is not part of this blob go to the next blob
2401				# (we asume that all members are part of blob - no need to check all)
2402				if structureMembers[0].name not in blobMemberList:
2403					continue
2404				# add another feature structure name to this blob
2405				blobStructs[blobName].add(structureType)
2406				# add specialization for this feature structure
2407				memberCopying = ""
2408				for member in structureMembers:
2409					memberCopying += "\tfeatureType.{0} = allFeaturesBlobs.vk{1}.{0};\n".format(member.name, blobName)
2410				wholeFunction = \
2411					"template<> void initFeatureFromBlob<{0}>({0}& featureType, const AllFeaturesBlobs& allFeaturesBlobs)\n" \
2412					"{{\n" \
2413					"{1}" \
2414					"}}".format(structureType.name, memberCopying)
2415				initFromBlobDefinitions.append(wholeFunction)
2416				notPartOfBlob = False
2417				# assuming that all members are part of blob, goto next
2418				break
2419		# add empty template definition as on Fedora there are issue with
2420		# linking using just generic template - all specializations are needed
2421		if notPartOfBlob:
2422			emptyFunction = "template<> void initFeatureFromBlob<{0}>({0}&, const AllFeaturesBlobs&) {{}}"
2423			emptyInitDefinitions.append(emptyFunction.format(structureType.name))
2424	extensionDefines = []
2425	makeFeatureDescDefinitions = []
2426	featureStructWrappers = []
2427	for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extLine, extName, specVer) in enumerate(dfDefs):
2428		extensionNameDefinition = extName
2429		if not extensionNameDefinition:
2430			extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType)
2431		# construct defines with names
2432		if extLine:
2433			extensionDefines.append(extLine)
2434		else:
2435			extensionDefines.append('#define {0} "not_existent_feature"'.format(extensionNameDefinition))
2436		# handle special cases
2437		if sType == "SCISSOR_EXCLUSIVE":
2438			sType = "EXCLUSIVE_SCISSOR"
2439		elif sType == "ASTC_DECODE_MODE":
2440			sType = "ASTC_DECODE"
2441		elif sType == "MAINTENANCE4":
2442			sType = "MAINTENANCE_4"
2443		elif sType == "YCBCR_2PLANE_444_FORMATS":
2444			sType = "YCBCR_2_PLANE_444_FORMATS"
2445		# end handling special cases
2446		# construct makeFeatureDesc template function definitions
2447		sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sVerSuffix + sExtSuffix)
2448		makeFeatureDescDefinitions.append("template<> FeatureDesc makeFeatureDesc<{0}>(void) " \
2449			"{{ return FeatureDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVer, len(dfDefs)-idx))
2450		# construct CreateFeatureStruct wrapper block
2451		featureStructWrappers.append("\t{{ createFeatureStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVer))
2452	# construct function that will check for which vk version structure sType is part of blob
2453	blobChecker = "deUint32 getBlobFeaturesVersion (VkStructureType sType)\n{\n" \
2454				  "\tconst std::map<VkStructureType, deUint32> sTypeBlobMap\n" \
2455				  "\t{\n"
2456	# iterate over blobs with list of structures
2457	for blobName in sorted(blobStructs.keys()):
2458		blobChecker += "\t\t// Vulkan{0}\n".format(blobName)
2459		# iterate over all feature structures in current blob
2460		structuresList = list(blobStructs[blobName])
2461		structuresList = sorted(structuresList, key=lambda s: s.name)
2462		for structType in structuresList:
2463			# find definition of this structure in dfDefs
2464			structName = structType.name
2465			# handle special cases
2466			if structName == 'VkPhysicalDeviceShaderDrawParameterFeatures':
2467				structName = 'VkPhysicalDeviceShaderDrawParametersFeatures'
2468			# end handling special cases
2469			structDef = [s for s in dfDefs if s[3] == structName][0]
2470			sType = structDef[0]
2471			sSuffix = structDef[1] + structDef[2]
2472			# handle special cases
2473			if sType == "SCISSOR_EXCLUSIVE":
2474				sType = "EXCLUSIVE_SCISSOR"
2475			elif sType == "MAINTENANCE4":
2476				sType = "MAINTENANCE_4"
2477			# end handling special cases
2478			sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_FEATURES{1}".format(sType, sSuffix)
2479			tabs = "\t" * int((88 - len(sTypeName)) / 4)
2480			blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1])
2481	blobChecker += "\t};\n\n" \
2482				   "\tauto it = sTypeBlobMap.find(sType);\n" \
2483				   "\tif(it == sTypeBlobMap.end())\n" \
2484				   "\t\treturn 0;\n" \
2485				   "\treturn it->second;\n" \
2486				   "}\n"
2487	# combine all definition lists
2488	stream = [
2489	'#include "vkDeviceFeatures.hpp"\n',
2490	'namespace vk\n{']
2491	stream.extend(extensionDefines)
2492	stream.append('\n')
2493	stream.extend(initFromBlobDefinitions)
2494	stream.append('\n// generic template is not enough for some compilers')
2495	stream.extend(emptyInitDefinitions)
2496	stream.append('\n')
2497	stream.extend(makeFeatureDescDefinitions)
2498	stream.append('\n')
2499	stream.append('static const FeatureStructCreationData featureStructCreationArray[]\n{')
2500	stream.extend(featureStructWrappers)
2501	stream.append('};\n')
2502	stream.append(blobChecker)
2503	stream.append('} // vk\n')
2504	writeInlFile(filename, INL_HEADER, stream)
2505
2506def writeDeviceFeatureTest(apiName, api, filename):
2507
2508	coreFeaturesPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Features[0-9]*$")
2509	featureItems = []
2510	testFunctions = []
2511	# iterate over all feature structures
2512	allFeaturesPattern = re.compile("^VkPhysicalDevice\w+Features[1-9]*")
2513	for structureType in api.compositeTypes:
2514		# skip structures that are not feature structures
2515		if not allFeaturesPattern.match(structureType.name):
2516			continue
2517		# skip alias structures
2518		if structureType.isAlias:
2519			continue
2520		# skip sType and pNext and just grab third and next attributes
2521		structureMembers = structureType.members[2:]
2522
2523		items = []
2524		for member in structureMembers:
2525			items.append("		FEATURE_ITEM ({0}, {1}),".format(structureType.name, member.name))
2526
2527		testBlock = """
2528tcu::TestStatus createDeviceWithUnsupportedFeaturesTest{4} (Context& context)
2529{{
2530	const PlatformInterface&				vkp						= context.getPlatformInterface();
2531	tcu::TestLog&							log						= context.getTestContext().getLog();
2532	tcu::ResultCollector					resultCollector			(log);
2533	const CustomInstance					instance				(createCustomInstanceWithExtensions(context, context.getInstanceExtensions(), DE_NULL, true));
2534	const InstanceDriver&					instanceDriver			(instance.getDriver());
2535	const VkPhysicalDevice					physicalDevice			= chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine());
2536	const deUint32							queueFamilyIndex		= 0;
2537	const deUint32							queueCount				= 1;
2538	const float								queuePriority			= 1.0f;
2539	const DeviceFeatures					deviceFeaturesAll		(context.getInstanceInterface(), context.getUsedApiVersion(), physicalDevice, context.getInstanceExtensions(), context.getDeviceExtensions(), DE_TRUE);
2540	const VkPhysicalDeviceFeatures2			deviceFeatures2			= deviceFeaturesAll.getCoreFeatures2();
2541	int										numErrors				= 0;
2542	bool                                                                    isSubProcess                    = context.getTestContext().getCommandLine().isSubProcess();
2543{6}
2544
2545	VkPhysicalDeviceFeatures emptyDeviceFeatures;
2546	deMemset(&emptyDeviceFeatures, 0, sizeof(emptyDeviceFeatures));
2547
2548	// Only non-core extensions will be used when creating the device.
2549	const auto& extensionNames = context.getDeviceCreationExtensions();
2550	DE_UNREF(extensionNames); // In some cases this may not be used.
2551
2552	if (const void* featuresStruct = findStructureInChain(const_cast<const void*>(deviceFeatures2.pNext), getStructureType<{0}>()))
2553	{{
2554		static const Feature features[] =
2555		{{
2556{1}
2557		}};
2558		auto* supportedFeatures = reinterpret_cast<const {0}*>(featuresStruct);
2559		checkFeatures(vkp, instance, instanceDriver, physicalDevice, {2}, features, supportedFeatures, queueFamilyIndex, queueCount, queuePriority, numErrors, resultCollector, {3}, emptyDeviceFeatures, {5});
2560	}}
2561
2562	if (numErrors > 0)
2563		return tcu::TestStatus(resultCollector.getResult(), "Enabling unsupported features didn't return VK_ERROR_FEATURE_NOT_PRESENT.");
2564	else
2565		return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
2566}}
2567"""
2568		additionalParams = ( 'memReservationStatMax, isSubProcess' if apiName == 'SC' else 'isSubProcess' )
2569		additionalDefs = ( '	VkDeviceObjectReservationCreateInfo memReservationStatMax = context.getResourceInterface()->getStatMax();' if apiName == 'SC' else '')
2570		featureItems.append(testBlock.format(structureType.name, "\n".join(items), len(items), ("DE_NULL" if coreFeaturesPattern.match(structureType.name) else "&extensionNames"), structureType.name[len('VkPhysicalDevice'):], additionalParams, additionalDefs))
2571
2572		testFunctions.append("createDeviceWithUnsupportedFeaturesTest" + structureType.name[len('VkPhysicalDevice'):])
2573
2574	stream = ['']
2575	stream.extend(featureItems)
2576	stream.append("""
2577void addSeparateUnsupportedFeatureTests (tcu::TestCaseGroup* testGroup)
2578{
2579""")
2580	for x in testFunctions:
2581		stream.append('\taddFunctionCase(testGroup, "' + camelToSnake(x[len('createDeviceWithUnsupportedFeaturesTest'):]) + '", ' + x + ');')
2582	stream.append('}\n')
2583
2584	writeInlFile(filename, INL_HEADER, stream)
2585
2586def writeDeviceProperties(api, dpDefs, filename):
2587	# find VkPhysicalDeviceVulkan[1-9][0-9]Features blob structurs
2588	# and construct dictionary with all of their attributes
2589	blobMembers = {}
2590	blobStructs = {}
2591	blobPattern = re.compile("^VkPhysicalDeviceVulkan([1-9][0-9])Properties[0-9]*$")
2592	for structureType in api.compositeTypes:
2593		match = blobPattern.match(structureType.name)
2594		if match:
2595			allMembers = [member.name for member in structureType.members]
2596			vkVersion = match.group(1)
2597			blobMembers[vkVersion] = allMembers[2:]
2598			blobStructs[vkVersion] = set()
2599	initFromBlobDefinitions = []
2600	emptyInitDefinitions = []
2601	# iterate over all property structures
2602	allPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*")
2603	nonExtPropertiesPattern = re.compile("^VkPhysicalDevice\w+Properties[1-9]*$")
2604	for structureType in api.compositeTypes:
2605		# skip structures that are not property structures
2606		if not allPropertiesPattern.match(structureType.name):
2607			continue
2608		# skip structures that were previously identified as blobs
2609		if blobPattern.match(structureType.name):
2610			continue
2611		if structureType.isAlias:
2612			continue
2613		# skip sType and pNext and just grab third and next attributes
2614		structureMembers = structureType.members[2:]
2615		notPartOfBlob = True
2616		if nonExtPropertiesPattern.match(structureType.name):
2617			# check if this member is part of any of the blobs
2618			for blobName, blobMemberList in blobMembers.items():
2619				# if just one member is not part of this blob go to the next blob
2620				# (we asume that all members are part of blob - no need to check all)
2621				if structureMembers[0].name not in blobMemberList:
2622					continue
2623				# add another property structure name to this blob
2624				blobStructs[blobName].add(structureType)
2625				# add specialization for this property structure
2626				memberCopying = ""
2627				for member in structureMembers:
2628					if not member.arraySize:
2629						# handle special case
2630						if structureType.name == "VkPhysicalDeviceSubgroupProperties" and "subgroup" not in member.name :
2631							blobMemberName = "subgroup" + member.name[0].capitalize() + member.name[1:]
2632							memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{2};\n".format(member.name, blobName, blobMemberName)
2633						# end handling special case
2634						else:
2635							memberCopying += "\tpropertyType.{0} = allPropertiesBlobs.vk{1}.{0};\n".format(member.name, blobName)
2636					else:
2637						memberCopying += "\tmemcpy(propertyType.{0}, allPropertiesBlobs.vk{1}.{0}, sizeof({2}) * {3});\n".format(member.name, blobName, member.type[0], member.arraySize[1:-1])
2638				wholeFunction = \
2639					"template<> void initPropertyFromBlob<{0}>({0}& propertyType, const AllPropertiesBlobs& allPropertiesBlobs)\n" \
2640					"{{\n" \
2641					"{1}" \
2642					"}}".format(structureType.name, memberCopying)
2643				initFromBlobDefinitions.append(wholeFunction)
2644				notPartOfBlob = False
2645				# assuming that all members are part of blob, goto next
2646				break
2647		# add empty template definition as on Fedora there are issue with
2648		# linking using just generic template - all specializations are needed
2649		if notPartOfBlob:
2650			emptyFunction = "template<> void initPropertyFromBlob<{0}>({0}&, const AllPropertiesBlobs&) {{}}"
2651			emptyInitDefinitions.append(emptyFunction.format(structureType.name))
2652	extensionDefines = []
2653	makePropertyDescDefinitions = []
2654	propertyStructWrappers = []
2655	for idx, (sType, sVerSuffix, sExtSuffix, extStruct, extLine, extName, specVer) in enumerate(dpDefs):
2656		extensionNameDefinition = extName
2657		if not extensionNameDefinition:
2658			extensionNameDefinition = 'DECL{0}_{1}_EXTENSION_NAME'.format((sExtSuffix if sExtSuffix else ''), sType)
2659		# construct defines with names
2660		if extLine:
2661			extensionDefines.append(extLine)
2662		else:
2663			extensionDefines.append('#define {0} "core_property"'.format(extensionNameDefinition))
2664		# construct makePropertyDesc template function definitions
2665		sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sVerSuffix + sExtSuffix)
2666		makePropertyDescDefinitions.append("template<> PropertyDesc makePropertyDesc<{0}>(void) " \
2667			"{{ return PropertyDesc{{{1}, {2}, {3}, {4}}}; }}".format(extStruct, sTypeName, extensionNameDefinition, specVer, len(dpDefs)-idx))
2668		# construct CreateProperty struct wrapper block
2669		propertyStructWrappers.append("\t{{ createPropertyStructWrapper<{0}>, {1}, {2} }},".format(extStruct, extensionNameDefinition, specVer))
2670	# construct method that will check if structure sType is part of blob
2671	blobChecker = "deUint32 getBlobPropertiesVersion (VkStructureType sType)\n{\n" \
2672				  "\tconst std::map<VkStructureType, deUint32> sTypeBlobMap\n" \
2673				  "\t{\n"
2674	# iterate over blobs with list of structures
2675	for blobName in sorted(blobStructs.keys()):
2676		blobChecker += "\t\t// Vulkan{0}\n".format(blobName)
2677		# iterate over all feature structures in current blob
2678		structuresList = list(blobStructs[blobName])
2679		structuresList = sorted(structuresList, key=lambda s: s.name)
2680		for structType in structuresList:
2681			# find definition of this structure in dpDefs
2682			structName = structType.name
2683			structDef = [s for s in dpDefs if s[3] == structName][0]
2684			sType = structDef[0]
2685			sSuffix = structDef[1] + structDef[2]
2686			sTypeName = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_{0}_PROPERTIES{1}".format(sType, sSuffix)
2687			tabs = "\t" * int((76 - len(sTypeName)) / 4)
2688			blobChecker += "\t\t{{ {0},{1}VK_API_VERSION_{2}_{3} }},\n".format(sTypeName, tabs, blobName[0], blobName[1])
2689	blobChecker += "\t};\n\n" \
2690				   "\tauto it = sTypeBlobMap.find(sType);\n" \
2691				   "\tif(it == sTypeBlobMap.end())\n" \
2692				   "\t\treturn 0;\n" \
2693				   "\treturn it->second;\n" \
2694				   "}\n"
2695	# combine all definition lists
2696	stream = [
2697	'#include "vkDeviceProperties.hpp"\n',
2698	'namespace vk\n{']
2699	stream.extend(extensionDefines)
2700	stream.append('\n')
2701	stream.extend(initFromBlobDefinitions)
2702	stream.append('\n// generic template is not enough for some compilers')
2703	stream.extend(emptyInitDefinitions)
2704	stream.append('\n')
2705	stream.extend(makePropertyDescDefinitions)
2706	stream.append('\n')
2707	stream.append('static const PropertyStructCreationData propertyStructCreationArray[] =\n{')
2708	stream.extend(propertyStructWrappers)
2709	stream.append('};\n')
2710	stream.append(blobChecker)
2711	stream.append('} // vk\n')
2712	writeInlFile(filename, INL_HEADER, stream)
2713
2714def genericDeviceFeaturesWriter(dfDefs, pattern, filename):
2715	stream = []
2716	for _, _, _, extStruct, _, _, _ in dfDefs:
2717		nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "")
2718		stream.append(pattern.format(extStruct, nameSubStr))
2719	writeInlFile(filename, INL_HEADER, indentLines(stream))
2720
2721def writeDeviceFeaturesDefaultDeviceDefs(dfDefs, filename):
2722	pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceFeatures.getFeatureType<{0}>();\t}}"
2723	genericDeviceFeaturesWriter(dfDefs, pattern, filename)
2724
2725def writeDeviceFeaturesContextDecl(dfDefs, filename):
2726	pattern = "const vk::{0}&\tget{1}\t(void) const;"
2727	genericDeviceFeaturesWriter(dfDefs, pattern, filename)
2728
2729def writeDeviceFeaturesContextDefs(dfDefs, filename):
2730	pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}"
2731	genericDeviceFeaturesWriter(dfDefs, pattern, filename)
2732
2733def genericDevicePropertiesWriter(dfDefs, pattern, filename):
2734	stream = []
2735	for _, _, _, extStruct, _, _, _ in dfDefs:
2736		nameSubStr = extStruct.replace("VkPhysicalDevice", "").replace("KHR", "").replace("NV", "")
2737		if extStruct == "VkPhysicalDeviceRayTracingPropertiesNV":
2738			nameSubStr += "NV"
2739		stream.append(pattern.format(extStruct, nameSubStr))
2740	writeInlFile(filename, INL_HEADER, indentLines(stream))
2741
2742def writeDevicePropertiesDefaultDeviceDefs(dfDefs, filename):
2743	pattern = "const {0}&\tget{1}\t(void) const {{ return m_deviceProperties.getPropertyType<{0}>();\t}}"
2744	genericDevicePropertiesWriter(dfDefs, pattern, filename)
2745
2746def writeDevicePropertiesContextDecl(dfDefs, filename):
2747	pattern = "const vk::{0}&\tget{1}\t(void) const;"
2748	genericDevicePropertiesWriter(dfDefs, pattern, filename)
2749
2750def writeDevicePropertiesContextDefs(dfDefs, filename):
2751	pattern = "const vk::{0}&\tContext::get{1}\t(void) const {{ return m_device->get{1}();\t}}"
2752	genericDevicePropertiesWriter(dfDefs, pattern, filename)
2753
2754def writeMandatoryFeatures(api, filename):
2755
2756	def structInAPI(name):
2757		for c in api.compositeTypes:
2758			if c.name == name:
2759				return True
2760		return False
2761	stream = []
2762
2763	dictStructs = {}
2764	dictData = []
2765	for _, data in api.additionalExtensionData:
2766		if 'mandatory_features' not in data.keys():
2767			continue
2768		# sort to have same results for py2 and py3
2769		listStructFeatures = sorted(data['mandatory_features'].items(), key=lambda tup: tup[0])
2770		for structure, featuresList in listStructFeatures:
2771			for featureData in featuresList:
2772				# allow for featureless VKSC only extensions
2773				if not 'features' in featureData.keys() or 'requirements' not in featureData.keys():
2774					continue
2775				requirements = featureData['requirements']
2776
2777				mandatory_variant = ''
2778				try:
2779					mandatory_variant = featureData['mandatory_variant']
2780				except KeyError:
2781					mandatory_variant = ''
2782
2783				dictData.append( [ structure, featureData['features'], requirements, mandatory_variant] )
2784
2785				if structure == 'VkPhysicalDeviceFeatures':
2786					continue
2787				# if structure is not in dict construct name of variable and add is as a first item
2788				if (structure not in dictStructs):
2789					dictStructs[structure] = ([structure[2:3].lower() + structure[3:]], mandatory_variant)
2790				# add first requirement if it is unique
2791				if requirements and (requirements[0] not in dictStructs[structure][0]):
2792					dictStructs[structure][0].append(requirements[0])
2793
2794
2795	stream.extend(['bool checkMandatoryFeatures(const vkt::Context& context)\n{',
2796				   '\tif (!context.isInstanceFunctionalitySupported("VK_KHR_get_physical_device_properties2"))',
2797				   '\t\tTCU_THROW(NotSupportedError, "Extension VK_KHR_get_physical_device_properties2 is not present");',
2798				   '',
2799				   '\tVkPhysicalDevice\t\t\t\t\tphysicalDevice\t\t= context.getPhysicalDevice();',
2800				   '\tconst InstanceInterface&\t\t\tvki\t\t\t\t\t= context.getInstanceInterface();',
2801				   '\tconst vector<VkExtensionProperties>\tdeviceExtensions\t= enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL);',
2802				   '',
2803				   '\ttcu::TestLog& log = context.getTestContext().getLog();',
2804				   '\tvk::VkPhysicalDeviceFeatures2 coreFeatures;',
2805				   '\tdeMemset(&coreFeatures, 0, sizeof(coreFeatures));',
2806				   '\tcoreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;',
2807				   '\tvoid** nextPtr = &coreFeatures.pNext;',
2808				   ''])
2809
2810	listStruct = sorted(dictStructs.items(), key=lambda tup: tup[0]) # sort to have same results for py2 and py3
2811	apiStruct	= list( filter(lambda x : structInAPI(x[0]), listStruct)) # remove items not defined in current A
2812
2813	for k, v in apiStruct:
2814		metaCondition = ''
2815		if v[1] != '':
2816			metaCondition = metaCondition + ' || defined(CTS_USES_' + v[1][0].upper() + ')'
2817			stream.extend(['#if ' + metaCondition[4:]])
2818		if (v[0][1].startswith("ApiVersion")):
2819			cond = '\tif (context.contextSupports(vk::' + v[0][1] + '))'
2820		else:
2821			cond = '\tif (vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "' + v[0][1] + '"))'
2822		stream.extend(['\tvk::' + k + ' ' + v[0][0]+ ';',
2823					'\tdeMemset(&' + v[0][0] + ', 0, sizeof(' + v[0][0] + '));',
2824					''])
2825		reqs = v[0][1:]
2826		if len(reqs) > 0 :
2827			cond = ''
2828			for i, req in enumerate(reqs) :
2829				if len(cond) > 0:
2830					cond += ' || '
2831				if (req.startswith("ApiVersion")):
2832					cond = cond + 'context.contextSupports(vk::' + req + ')'
2833				elif (req.startswith("VK_")):
2834					cond = cond + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))'
2835			if len(cond) == 0:
2836				cond = 'false'
2837			cond = 'if ( ' + cond + ' )'
2838			stream.append('\t' + cond)
2839		stream.extend(['\t{',
2840					   '\t\t' + v[0][0] + '.sType = getStructureType<' + k + '>();',
2841					   '\t\t*nextPtr = &' + v[0][0] + ';',
2842					   '\t\tnextPtr  = &' + v[0][0] + '.pNext;',
2843					   '\t}'])
2844		if metaCondition != '':
2845			stream.extend(['#endif // ' + metaCondition[4:],
2846						  ''])
2847		else:
2848			stream.extend([''])
2849	stream.extend(['\tcontext.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &coreFeatures);',
2850				   '\tbool result = true;',
2851				   ''])
2852
2853
2854	for v in dictData:
2855		if not structInAPI(v[0]): # remove items not defined in current API ( important for Vulkan SC )
2856			continue
2857		structType = v[0];
2858		structName = 'coreFeatures.features';
2859		metaCondition = ''
2860		if len(v) == 4 and v[3] != '':
2861			# for x in v[3].split('_'):
2862			metaCondition = metaCondition + ' || defined(CTS_USES_' + v[3][0].upper() + ')'
2863			stream.extend(['#if ' + metaCondition[4:]])
2864		if v[0] != 'VkPhysicalDeviceFeatures' :
2865			structName = dictStructs[v[0]][0][0]
2866		if len(v[2]) > 0 :
2867			condition = 'if ( '
2868			for i, req in enumerate(v[2]) :
2869				if (req.startswith("ApiVersion")):
2870					condition = condition + 'context.contextSupports(vk::' + req + ')'
2871				elif '.' in req:
2872					condition = condition + req
2873				else:
2874					condition = condition + 'isExtensionStructSupported(deviceExtensions, RequiredExtension("' + req + '"))'
2875				if i+1 < len(v[2]) :
2876					condition = condition + ' && '
2877			condition = condition + ' )'
2878			stream.append('\t' + condition)
2879		stream.append('\t{')
2880		# Don't need to support an AND case since that would just be another line in the .txt
2881		if len(v[1]) == 1:
2882			stream.append('\t\tif ( ' + structName + '.' + v[1][0] + ' == VK_FALSE )')
2883		else:
2884			condition = 'if ( '
2885			for i, feature in enumerate(v[1]):
2886				if i != 0:
2887					condition = condition + ' && '
2888				condition = condition + '( ' + structName + '.' + feature + ' == VK_FALSE )'
2889			condition = condition + ' )'
2890			stream.append('\t\t' + condition)
2891		featureSet = " or ".join(v[1])
2892		stream.extend(['\t\t{',
2893					   '\t\t\tlog << tcu::TestLog::Message << "Mandatory feature ' + featureSet + ' not supported" << tcu::TestLog::EndMessage;',
2894					   '\t\t\tresult = false;',
2895					   '\t\t}',
2896					   '\t}'])
2897		if metaCondition != '':
2898			stream.extend(['#endif // ' + metaCondition[4:],
2899						  ''])
2900		else:
2901			stream.extend([''])
2902
2903	stream.append('\treturn result;')
2904	stream.append('}\n')
2905	writeInlFile(filename, INL_HEADER, stream)
2906
2907def writeExtensionList(apiName, api, filename, extensionType):
2908	extensionList = []
2909	for extensionName, data in api.additionalExtensionData:
2910		# make sure extension name starts with VK_KHR
2911		if not extensionName.startswith('VK_KHR'):
2912			continue
2913		# make sure that this extension was registered
2914		if 'register_extension' not in data.keys():
2915			continue
2916		# make sure extension is intended for the vulkan variant
2917		is_sc_only = False
2918
2919		if apiName != 'SC':
2920			if 'mandatory_features' in data.keys():
2921				for structure, listStruct in data['mandatory_features'].items():
2922					for featureData in listStruct:
2923						mandatory_variant = ''
2924						try:
2925							mandatory_variant = featureData['mandatory_variant']
2926						except KeyError:
2927							mandatory_variant = ''
2928						# VKSC only
2929						if 'vulkansc' in mandatory_variant:
2930							is_sc_only = True
2931		if is_sc_only:
2932			continue
2933
2934		# make sure extension has proper type
2935		if extensionType == data['register_extension']['type']:
2936			extensionList.append(extensionName)
2937	extensionList.sort()
2938	# write list of all found extensions
2939	stream = []
2940	stream.append('static const char* s_allowed{0}KhrExtensions[] =\n{{'.format(extensionType.title()))
2941	for n in extensionList:
2942		stream.append('\t"' + n + '",')
2943	stream.append('};\n')
2944	writeInlFile(filename, INL_HEADER, stream)
2945
2946def parseCmdLineArgs():
2947	parser = argparse.ArgumentParser(description = "Generate Vulkan INL files",
2948									 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
2949	parser.add_argument("-a",
2950						"--api",
2951						dest="api",
2952						default="",
2953						help="Choose between Vulkan and Vulkan SC")
2954	parser.add_argument("-o",
2955						"--outdir",
2956						dest="outdir",
2957						default="",
2958						help="Choose output directory")
2959	return parser.parse_args()
2960
2961def preprocessTopInclude(src, dir):
2962	pattern = r'#include\s+"([^\n]+)"'
2963	while True:
2964		inc = re.search(pattern, src)
2965		if inc is None:
2966			return src
2967		incFileName = inc.string[inc.start(1):inc.end(1)]
2968		patternIncNamed = r'#include\s+"' + incFileName + '"'
2969		incBody = readFile(os.path.join(dir, incFileName)) if incFileName != 'vk_platform.h' else ''
2970		incBodySanitized = re.sub(pattern, '', incBody)
2971		bodyEndSanitized = re.sub(patternIncNamed, '', src[inc.end(0):])
2972		src = src[0:inc.start(0)] + incBodySanitized + bodyEndSanitized
2973	return src
2974
2975if __name__ == "__main__":
2976	args = parseCmdLineArgs()
2977
2978	outputPath = DEFAULT_OUTPUT_DIR[args.api]
2979	# if argument was specified it is interpreted as a path to which .inl files will be written
2980	if args.outdir != '':
2981		outputPath = args.outdir
2982
2983	files = []
2984	src = ""
2985	if args.api == '':
2986
2987		# Generate vulkan headers from vk.xml
2988		currentDir			= os.getcwd()
2989		pythonExecutable	= sys.executable or "python"
2990		os.chdir(os.path.join(VULKAN_HEADERS_INCLUDE_DIR, "..", "xml"))
2991		vkTargets = [
2992			"vulkan_android.h",
2993			"vulkan_beta.h",
2994			"vulkan_core.h",
2995			"vulkan_fuchsia.h",
2996			"vulkan_ggp.h",
2997			"vulkan_ios.h",
2998			"vulkan_macos.h",
2999			"vulkan_metal.h",
3000			"vulkan_vi.h",
3001			"vulkan_wayland.h",
3002			"vulkan_win32.h",
3003			"vulkan_xcb.h",
3004			"vulkan_xlib.h",
3005			"vulkan_xlib_xrandr.h",
3006		]
3007		for target in vkTargets:
3008			execute([pythonExecutable, "../scripts/genvk.py", "-o", "../include/vulkan", target])
3009
3010		videoDir = "../include/vk_video"
3011		if (not os.path.isdir(videoDir)):
3012			os.mkdir(videoDir)
3013
3014		videoTargets = [
3015			'vulkan_video_codecs_common.h',
3016			'vulkan_video_codec_h264std.h',
3017			'vulkan_video_codec_h264std_decode.h',
3018			'vulkan_video_codec_h264std_encode.h',
3019			'vulkan_video_codec_h265std.h',
3020			'vulkan_video_codec_h265std_decode.h',
3021			'vulkan_video_codec_h265std_encode.h',
3022		]
3023		for target in videoTargets:
3024			execute([pythonExecutable, "../scripts/genvk.py", "-registry", "video.xml", "-o", videoDir, target])
3025
3026		os.chdir(currentDir)
3027
3028		# Read all .h files and make sure vulkan_core.h is first out of vulkan files
3029		vkTargets.remove("vulkan_core.h")
3030		vkTargets.sort()
3031		vkTargets.insert(0, "vulkan_core.h")
3032		vkFilesWithCatalog = [os.path.join("vulkan", f) for f in vkTargets]
3033
3034		for file in vkFilesWithCatalog:
3035			src += preprocessTopInclude(readFile(os.path.join(VULKAN_HEADERS_INCLUDE_DIR,file)), VULKAN_HEADERS_INCLUDE_DIR)
3036	elif args.api=='SC':
3037		# At the moment vulkan-docs does not have vulkan_sc_core.h. We will use a file from external/vulkancts/scripts/src
3038		src = preprocessTopInclude(readFile(os.path.join(os.path.dirname(__file__), "src", "vulkan_sc_core.h" )), VULKAN_HEADERS_INCLUDE_DIR)
3039		src += preprocessTopInclude(readFile(os.path.join(os.path.dirname(__file__), "src", "vulkan_sci.h" )), VULKAN_HEADERS_INCLUDE_DIR)
3040
3041	src = re.sub('\s*//[^\n]*', '', src)
3042	src = re.sub('\n\n', '\n', src)
3043
3044	api				= parseAPI(src)
3045
3046	platformFuncs	= [Function.TYPE_PLATFORM]
3047	instanceFuncs	= [Function.TYPE_INSTANCE]
3048	deviceFuncs		= [Function.TYPE_DEVICE]
3049
3050	dfd										= generateDeviceFeaturesDefs(args.api, src)
3051	writeDeviceFeatures						(api, dfd, os.path.join(outputPath, "vkDeviceFeatures.inl"))
3052	writeDeviceFeaturesDefaultDeviceDefs	(dfd, os.path.join(outputPath, "vkDeviceFeaturesForDefaultDeviceDefs.inl"))
3053	writeDeviceFeaturesContextDecl			(dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDecl.inl"))
3054	writeDeviceFeaturesContextDefs			(dfd, os.path.join(outputPath, "vkDeviceFeaturesForContextDefs.inl"))
3055	writeDeviceFeatureTest					(args.api, api, os.path.join(outputPath, "vkDeviceFeatureTest.inl"))
3056
3057	dpd										= generateDevicePropertiesDefs(args.api, src)
3058	writeDeviceProperties					(api, dpd, os.path.join(outputPath, "vkDeviceProperties.inl"))
3059
3060	writeDevicePropertiesDefaultDeviceDefs	(dpd, os.path.join(outputPath, "vkDevicePropertiesForDefaultDeviceDefs.inl"))
3061	writeDevicePropertiesContextDecl		(dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDecl.inl"))
3062	writeDevicePropertiesContextDefs		(dpd, os.path.join(outputPath, "vkDevicePropertiesForContextDefs.inl"))
3063
3064	writeHandleType							(api, os.path.join(outputPath, "vkHandleType.inl"))
3065	writeBasicTypes							(args.api, api, os.path.join(outputPath, "vkBasicTypes.inl"))
3066	writeCompositeTypes						(api, os.path.join(outputPath, "vkStructTypes.inl"))
3067	writeInterfaceDecl						(api, os.path.join(outputPath, "vkVirtualPlatformInterface.inl"),		platformFuncs,	False)
3068	writeInterfaceDecl						(api, os.path.join(outputPath, "vkVirtualInstanceInterface.inl"),		instanceFuncs,	False)
3069	writeInterfaceDecl						(api, os.path.join(outputPath, "vkVirtualDeviceInterface.inl"),			deviceFuncs,	False)
3070	writeInterfaceDecl						(api, os.path.join(outputPath, "vkConcretePlatformInterface.inl"),		platformFuncs,	True)
3071	writeInterfaceDecl						(api, os.path.join(outputPath, "vkConcreteInstanceInterface.inl"),		instanceFuncs,	True)
3072	writeInterfaceDecl						(api, os.path.join(outputPath, "vkConcreteDeviceInterface.inl"),		deviceFuncs,	True)
3073	writeFunctionPtrTypes					(api, os.path.join(outputPath, "vkFunctionPointerTypes.inl"))
3074	writeFunctionPointers					(api, os.path.join(outputPath, "vkPlatformFunctionPointers.inl"),		platformFuncs)
3075	writeFunctionPointers					(api, os.path.join(outputPath, "vkInstanceFunctionPointers.inl"),		instanceFuncs)
3076	writeFunctionPointers					(api, os.path.join(outputPath, "vkDeviceFunctionPointers.inl"),			deviceFuncs)
3077	writeInitFunctionPointers				(api, os.path.join(outputPath, "vkInitPlatformFunctionPointers.inl"),	platformFuncs,	lambda f: f.name != "vkGetInstanceProcAddr")
3078	writeInitFunctionPointers				(api, os.path.join(outputPath, "vkInitInstanceFunctionPointers.inl"),	instanceFuncs)
3079	writeInitFunctionPointers				(api, os.path.join(outputPath, "vkInitDeviceFunctionPointers.inl"),		deviceFuncs)
3080	writeFuncPtrInterfaceImpl				(api, os.path.join(outputPath, "vkPlatformDriverImpl.inl"),				platformFuncs,	"PlatformDriver")
3081	writeFuncPtrInterfaceImpl				(api, os.path.join(outputPath, "vkInstanceDriverImpl.inl"),				instanceFuncs,	"InstanceDriver")
3082	writeFuncPtrInterfaceImpl				(api, os.path.join(outputPath, "vkDeviceDriverImpl.inl"),				deviceFuncs,	"DeviceDriver")
3083	if args.api=='SC':
3084		writeFuncPtrInterfaceSCImpl			(api, os.path.join(outputPath, "vkDeviceDriverSCImpl.inl"),				deviceFuncs,	"DeviceDriverSC")
3085	writeStrUtilProto						(api, os.path.join(outputPath, "vkStrUtil.inl"))
3086	writeStrUtilImpl						(api, os.path.join(outputPath, "vkStrUtilImpl.inl"))
3087	writeRefUtilProto						(api, os.path.join(outputPath, "vkRefUtil.inl"))
3088	writeRefUtilImpl						(api, os.path.join(outputPath, "vkRefUtilImpl.inl"))
3089	writeStructTraitsImpl					(api, os.path.join(outputPath, "vkGetStructureTypeImpl.inl"))
3090	writeNullDriverImpl						(api, os.path.join(outputPath, "vkNullDriverImpl.inl"))
3091	writeTypeUtil							(api, os.path.join(outputPath, "vkTypeUtil.inl"))
3092	writeSupportedExtensions				(args.api, api, os.path.join(outputPath, "vkSupportedExtensions.inl"))
3093	writeCoreFunctionalities				(api, os.path.join(outputPath, "vkCoreFunctionalities.inl"))
3094	writeExtensionFunctions					(api, os.path.join(outputPath, "vkExtensionFunctions.inl"))
3095	writeDeviceFeatures2					(api, os.path.join(outputPath, "vkDeviceFeatures2.inl"))
3096	writeMandatoryFeatures					(api, os.path.join(outputPath, "vkMandatoryFeatures.inl"))
3097	writeExtensionList						(args.api, api, os.path.join(outputPath, "vkInstanceExtensions.inl"),				'instance')
3098	writeExtensionList						(args.api, api, os.path.join(outputPath, "vkDeviceExtensions.inl"),				'device')
3099	writeDriverIds							(args.api, os.path.join(outputPath, "vkKnownDriverIds.inl"))
3100	writeObjTypeImpl						(api, os.path.join(outputPath, "vkObjTypeImpl.inl"))
3101	# NOTE: when new files are generated then they should also be added to the
3102	# vk-gl-cts\external\vulkancts\framework\vulkan\CMakeLists.txt outputs list
3103