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