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