1# -*- coding: utf-8 -*-
2
3#-------------------------------------------------------------------------
4# drawElements Quality Program utilities
5# --------------------------------------
6#
7# Copyright 2018 The Android Open Source Project
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 sys
25
26sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "..", "scripts"))
27
28import khr_util.format
29import khr_util.registry_cache
30from collections import defaultdict
31
32VK_SOURCE						= khr_util.registry_cache.RegistrySource(
33									"https://github.com/KhronosGroup/Vulkan-Docs.git",
34									"xml/vk.xml",
35									"cee0f4b12acde766e64d0d038b03458c74bb67f1",
36									"eb31286278b1ecf55ae817198a4238f82ea8fe028aa0631e2c1b09747f10ebb4")
37VK_INL_FILE						= os.path.join(os.path.dirname(__file__), "..", "framework", "vulkan", "vkApiExtensionDependencyInfo.inl")
38VK_INL_HEADER					= khr_util.format.genInlHeader("Khronos Vulkan API description (vk.xml)", VK_SOURCE.getRevision())
39
40def VK_MAKE_VERSION(major, minor, patch):
41	return (((major) << 22) | ((minor) << 12) | (patch))
42
43VK_EXT_NOT_PROMOTED				= 0xFFFFFFFF
44VK_EXT_TYPE_INSTANCE			= 0
45VK_EXT_TYPE_DEVICE				= 1
46VK_EXT_DEP_INSTANCE				= 'instanceExtensionDependencies'
47VK_EXT_DEP_DEVICE				= 'deviceExtensionDependencies'
48VK_EXT_API_VERSIONS				= 'releasedApiVersions'
49VK_XML_EXT_DEPS					= 'requires'
50VK_XML_EXT_NAME					= 'name'
51VK_XML_EXT_PROMO				= 'promotedto'
52VK_XML_EXT_REQUIRES_CORE		= 'requiresCore'
53VK_XML_EXT_SUPPORTED			= 'supported'
54VK_XML_EXT_SUPPORTED_VULKAN		= 'vulkan'
55VK_XML_EXT_API					= 'api'
56VK_XML_EXT_TYPE					= 'type'
57VK_XML_EXT_TYPE_DEVICE			= 'device'
58VK_XML_EXT_TYPE_INSTANCE		= 'instance'
59
60def writeInlFile(filename, lines):
61	khr_util.format.writeInlFile(filename, VK_INL_HEADER, lines)
62
63def genExtDepArray(extDepsName, extDepsDict):
64	yield 'static const std::tuple<deUint32, deUint32, const char*, const char*>\t{}[]\t='.format(extDepsName)
65	yield '{'
66	for ( major, minor, ext, extDeps ) in extDepsDict:
67		for dep in extDeps:
68			yield '\tstd::make_tuple({}, {}, "{}", "{}"),'.format(major, minor, ext, dep)
69	yield '};'
70
71def genApiVersions(name, apiVersions):
72	yield 'static const std::tuple<deUint32, deUint32, deUint32>\t{}[]\t='.format(name)
73	yield '{'
74	for ( version, major, minor ) in apiVersions:
75		yield '\tstd::make_tuple({}, {}, {}),'.format(version, major, minor)
76	yield '};'
77
78def genExtDepInl(dependenciesAndVersions):
79	allExtDepsDict, apiVersions = dependenciesAndVersions
80	apiVersions.reverse()
81	lines = []
82
83	lines = lines + [line for line in genExtDepArray(VK_EXT_DEP_INSTANCE, allExtDepsDict[VK_EXT_TYPE_INSTANCE])]
84	lines = lines + [line for line in genExtDepArray(VK_EXT_DEP_DEVICE, allExtDepsDict[VK_EXT_TYPE_DEVICE])]
85	lines = lines + [line for line in genApiVersions(VK_EXT_API_VERSIONS, apiVersions)]
86
87	writeInlFile(VK_INL_FILE, lines)
88
89class extInfo:
90	def __init__(self):
91		self.type	= VK_EXT_TYPE_INSTANCE
92		self.core	= VK_MAKE_VERSION(1, 0, 0)
93		self.promo	= VK_EXT_NOT_PROMOTED
94		self.deps	= []
95
96def genExtDepsOnApiVersion(ext, extInfoDict, apiVersion):
97	deps = []
98
99	for dep in extInfoDict[ext].deps:
100		if apiVersion >= extInfoDict[dep].promo:
101			continue
102
103		deps.append(dep)
104
105	return deps
106
107def genExtDeps(extensionsAndVersions):
108	extInfoDict, apiVersionID = extensionsAndVersions
109
110	allExtDepsDict	= defaultdict(list)
111	apiVersions		= []
112
113	for (major,minor) in apiVersionID:
114		apiVersions.append((VK_MAKE_VERSION(major, minor, 0),major,minor))
115	apiVersions.sort(key=lambda x: x[0])
116
117	for ext, info in extInfoDict.items():
118		if info.deps == None:
119			continue
120
121		for (version,major,minor) in apiVersions:
122			if info.core <= version:
123				extDeps = genExtDepsOnApiVersion(ext, extInfoDict, version)
124				if extDeps == None:
125					continue
126				allExtDepsDict[info.type].append( ( major, minor, ext, extDeps ) )
127
128	for key, value in allExtDepsDict.items():
129		value.sort(key=lambda x: x[2])
130	return allExtDepsDict, apiVersions
131
132def getExtInfoDict(vkRegistry):
133	extInfoDict = {}
134	apiVersionID = []
135
136	for feature in vkRegistry.features:
137		if feature.attrib[VK_XML_EXT_API] != VK_XML_EXT_SUPPORTED_VULKAN:
138			continue
139		featureName = feature.attrib[VK_XML_EXT_NAME].split('_')
140		if len(featureName)!=4 or featureName[0] != 'VK' or featureName[1] != 'VERSION' :
141			continue
142		apiVersionID.append( (int(featureName[2]), int(featureName[3])) )
143
144	apiVersionsByName	= {}
145	apiVersionsByNumber	= {}
146	for (major,minor) in apiVersionID:
147		apiVersionsByName['VK_VERSION_{}_{}'.format(major,minor)]	= VK_MAKE_VERSION(major, minor, 0);
148		apiVersionsByNumber['{}.{}'.format(major,minor)]			= VK_MAKE_VERSION(major, minor, 0);
149
150	for ext in vkRegistry.extensions:
151		if ext.attrib[VK_XML_EXT_SUPPORTED] != VK_XML_EXT_SUPPORTED_VULKAN:
152			continue
153
154		name				= ext.attrib[VK_XML_EXT_NAME]
155		extInfoDict[name]	= extInfo()
156		if ext.attrib[VK_XML_EXT_TYPE] == VK_XML_EXT_TYPE_DEVICE:
157			extInfoDict[name].type = VK_EXT_TYPE_DEVICE
158		if VK_XML_EXT_REQUIRES_CORE in ext.attrib and ext.attrib[VK_XML_EXT_REQUIRES_CORE] in apiVersionsByNumber:
159			extInfoDict[name].core = apiVersionsByNumber[ext.attrib[VK_XML_EXT_REQUIRES_CORE]]
160		if VK_XML_EXT_PROMO in ext.attrib and ext.attrib[VK_XML_EXT_PROMO] in apiVersionsByName :
161			extInfoDict[name].promo = apiVersionsByName[ext.attrib[VK_XML_EXT_PROMO]]
162		if VK_XML_EXT_DEPS in ext.attrib:
163			extInfoDict[name].deps = ext.attrib[VK_XML_EXT_DEPS].split(',')
164
165	return extInfoDict, apiVersionID
166
167def getVKRegistry():
168	return khr_util.registry_cache.getRegistry(VK_SOURCE)
169
170if __name__ == '__main__':
171	genExtDepInl(genExtDeps(getExtInfoDict(getVKRegistry())))
172