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