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