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