1/*-------------------------------------------------------------------------
2 * Vulkan CTS Framework
3 * --------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Vulkan api version.
22 *//*--------------------------------------------------------------------*/
23
24#include "vkApiVersion.hpp"
25#include <vector>
26#include <set>
27#include <algorithm>
28
29namespace vk
30{
31
32ApiVersion unpackVersion (deUint32 version)
33{
34	return ApiVersion(VK_API_VERSION_VARIANT(version),
35					  VK_API_VERSION_MAJOR(version),
36					  VK_API_VERSION_MINOR(version),
37					  VK_API_VERSION_PATCH(version));
38}
39
40deUint32 pack (const ApiVersion& version)
41{
42	DE_ASSERT((version.variantNum & ~0x7)   == 0);
43	DE_ASSERT((version.majorNum   & ~0x7F)  == 0);
44	DE_ASSERT((version.minorNum   & ~0x3FF) == 0);
45	DE_ASSERT((version.patchNum   & ~0xFFF) == 0);
46
47	return (version.variantNum << 29) | (version.majorNum << 22) | (version.minorNum << 12) | version.patchNum;
48}
49
50deUint32 apiVersionClearPatch(deUint32 version)
51{
52	return version & ~0xFFF;
53}
54
55// Direct acyclic graph of Vulkan API versions and its predecessors.
56// At the moment it's linear ( 0.1.0.0 < 0.1.1.0 < 0.1.2.0 < 1.1.0.0 ).
57// But with the introduction of Vulkan 1.3 it won't be, because Vulkan 1.2 will have 2 successors orthogonal to each other.
58// Moreover - when in the future new Vulkan SC 1.1 version will be created - it's possible that
59// it will have 2 predecessors : Vulkan SC 1.0 and Vulkan 1.3 ( or later version - it's just example )
60// When it happens : two new predecessors will look like this:
61//	{ VK_MAKE_API_VERSION(1, 1, 1, 0), VK_MAKE_API_VERSION(1, 1, 0, 0) },
62//	{ VK_MAKE_API_VERSION(1, 1, 1, 0), VK_MAKE_API_VERSION(0, 1, 3, 0) },
63
64const static std::vector<std::pair<deUint32,deUint32>> apiVersionPredecessors =
65{
66	{ VK_MAKE_API_VERSION(0, 1, 0, 0), 0 },
67	{ VK_MAKE_API_VERSION(0, 1, 1, 0), VK_MAKE_API_VERSION(0, 1, 0, 0) },
68	{ VK_MAKE_API_VERSION(0, 1, 2, 0), VK_MAKE_API_VERSION(0, 1, 1, 0) },
69	{ VK_MAKE_API_VERSION(1, 1, 0, 0), VK_MAKE_API_VERSION(0, 1, 2, 0) },
70	{ VK_MAKE_API_VERSION(0, 1, 3, 0), VK_MAKE_API_VERSION(0, 1, 2, 0) },
71};
72
73bool isApiVersionEqual(deUint32 lhs, deUint32 rhs)
74{
75	deUint32 lhsp = apiVersionClearPatch(lhs);
76	deUint32 rhsp = apiVersionClearPatch(rhs);
77	return lhsp == rhsp;
78}
79
80bool isApiVersionPredecessor(deUint32 version, deUint32 predVersion)
81{
82	std::vector<deUint32> versions;
83	versions.push_back(apiVersionClearPatch(version));
84
85	deUint32 p = apiVersionClearPatch(predVersion);
86
87	while (!versions.empty())
88	{
89		deUint32 v = versions.back();
90		versions.pop_back();
91
92		for (auto it = begin(apiVersionPredecessors); it != end(apiVersionPredecessors); ++it)
93		{
94			if (it->first != v)
95				continue;
96			if (it->second == p)
97				return true;
98			versions.push_back(it->second);
99		}
100	}
101	return false;
102}
103
104bool isApiVersionSupported(deUint32 yourVersion, deUint32 versionInQuestion)
105{
106	if (isApiVersionEqual(yourVersion, versionInQuestion))
107		return true;
108	return isApiVersionPredecessor(yourVersion, versionInQuestion);
109}
110
111deUint32 minVulkanAPIVersion(deUint32 lhs, deUint32 rhs)
112{
113	deUint32 lhsp = apiVersionClearPatch(lhs);
114	deUint32 rhsp = apiVersionClearPatch(rhs);
115	if (lhsp == rhsp)
116		return de::min(lhs, rhs);
117	if (isApiVersionPredecessor(rhs, lhs))
118		return lhs;
119	if (isApiVersionPredecessor(lhs, rhs))
120		return rhs;
121	// both versions are located in different DAG paths - we will return common predecessor
122	static std::vector<deUint32> commonPredecessors;
123	if (commonPredecessors.empty())
124	{
125		std::set<deUint32> pred;
126		for (auto it = begin(apiVersionPredecessors); it != end(apiVersionPredecessors); ++it)
127		{
128			if (pred.find(it->second) != end(pred))
129				commonPredecessors.push_back(it->second);
130			pred.insert(it->second);
131		}
132		std::sort(begin(commonPredecessors), end(commonPredecessors), [](deUint32 xlhs, deUint32 xrhs) { return isApiVersionPredecessor(xrhs, xlhs); });
133	}
134	for (auto it = begin(commonPredecessors); it != end(commonPredecessors); ++it)
135		if (isApiVersionPredecessor(rhs, *it) && isApiVersionPredecessor(lhs, *it))
136			return *it;
137	return 0;
138}
139
140} // vk
141