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