1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Khronos Group
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 API Version Check test - prints out version info
22 *//*--------------------------------------------------------------------*/
23 
24 #include <iostream>
25 #include <typeinfo>
26 
27 #include "tcuDefs.hpp"
28 #include "tcuTestCase.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuFunctionLibrary.hpp"
31 #include "tcuPlatform.hpp"
32 
33 #include "vkApiVersion.hpp"
34 #include "vkDefs.hpp"
35 #include "vkPlatform.hpp"
36 
37 #include "vktApiVersionCheck.hpp"
38 #include "vktTestCase.hpp"
39 
40 #include "vkRefUtil.hpp"
41 #include "vkDeviceUtil.hpp"
42 
43 #include "deString.h"
44 #include "deStringUtil.hpp"
45 
46 #include <map>
47 #include <vector>
48 
49 using namespace vk;
50 using namespace std;
51 
52 namespace vkt
53 {
54 
55 namespace api
56 {
57 
58 namespace
59 {
60 
61 #include "vkCoreFunctionalities.inl"
62 
63 class APIVersionTestInstance : public TestInstance
64 {
65 public:
APIVersionTestInstance(Context & ctx)66 								APIVersionTestInstance	(Context&				ctx)
67 									: TestInstance	(ctx)
68 	{}
iterate(void)69 	virtual tcu::TestStatus		iterate					(void)
70 	{
71 		tcu::TestLog&			log				= m_context.getTestContext().getLog();
72 		const vk::ApiVersion	instanceVersion	= vk::unpackVersion(m_context.getAvailableInstanceVersion());
73 		const vk::ApiVersion	deviceVersion	= vk::unpackVersion(m_context.getDeviceVersion());
74 		const vk::ApiVersion	usedApiVersion	= vk::unpackVersion(m_context.getUsedApiVersion());
75 
76 		log << tcu::TestLog::Message << "availableInstanceVersion: " << instanceVersion << tcu::TestLog::EndMessage;
77 		log << tcu::TestLog::Message << "deviceVersion: " << deviceVersion << tcu::TestLog::EndMessage;
78 		log << tcu::TestLog::Message << "usedApiVersion: " << usedApiVersion << tcu::TestLog::EndMessage;
79 		const ::std::string		result			= de::toString(usedApiVersion.majorNum) + ::std::string(".") + de::toString(usedApiVersion.minorNum) + ::std::string(".") + de::toString(usedApiVersion.patchNum);
80 		return tcu::TestStatus::pass(result);
81 	}
82 };
83 
84 class APIVersionTestCase : public TestCase
85 {
86 public:
APIVersionTestCase(tcu::TestContext & testCtx)87 							APIVersionTestCase	(tcu::TestContext&		testCtx)
88 								: TestCase	(testCtx, "version", "Prints out API info.")
89 	{}
90 
~APIVersionTestCase(void)91 	virtual					~APIVersionTestCase	(void)
92 	{}
createInstance(Context & ctx) const93 	virtual TestInstance*	createInstance		(Context&				ctx) const
94 	{
95 		return new APIVersionTestInstance(ctx);
96 	}
97 
98 private:
99 };
100 
101 class APIEntryPointsTestInstance : public TestInstance
102 {
103 public:
APIEntryPointsTestInstance(Context & ctx)104 								APIEntryPointsTestInstance	(Context&				ctx)
105 									: TestInstance	(ctx)
106 	{
107 
108 	}
iterate(void)109 	virtual tcu::TestStatus		iterate						(void)
110 	{
111 		tcu::TestLog&						log					= m_context.getTestContext().getLog();
112 		const vk::Platform&					platform			= m_context.getTestContext().getPlatform().getVulkanPlatform();
113 		de::MovePtr<vk::Library>			vkLibrary			= de::MovePtr<vk::Library>(platform.createLibrary());
114 		const tcu::FunctionLibrary&			funcLibrary			= vkLibrary->getFunctionLibrary();
115 		std::vector<std::string>			empty				= std::vector<std::string>();
116 											instance			= createDefaultInstance(m_context.getPlatformInterface(), m_context.getUsedApiVersion(), empty, empty, DE_NULL);
117 											device				= createTestDevice(m_context.getPlatformInterface(), m_context.getInstanceInterface(), m_context.getPhysicalDevice());
118 											getInstanceProcAddr	= reinterpret_cast<GetInstanceProcAddrFunc>(funcLibrary.getFunction("vkGetInstanceProcAddr"));
119 											getDeviceProcAddr	= reinterpret_cast<GetDeviceProcAddrFunc>(getInstanceProcAddr(*instance, "vkGetDeviceProcAddr"));
120 
121 		deUint32							failsQuantity		= 0u;
122 
123 		{
124 			ApisMap							functions			= ApisMap();
125 			initApisMap(functions);
126 			ApisMap::const_iterator			lastGoodVersion		= functions.begin();
127 			const ApisMap::const_iterator	versionsEnd			= functions.end();
128 			for (ApisMap::const_iterator it = lastGoodVersion; it != versionsEnd; ++it)
129 			{
130 				if (it->first <= m_context.getUsedApiVersion())
131 					lastGoodVersion = it;
132 			}
133 
134 			log << tcu::TestLog::Message << "Regular check - tries to get core functions from proper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
135 			const char* const				regularResult		= regularCheck(log, failsQuantity, lastGoodVersion->second) ? "Passed" : "Failed";
136 			log << tcu::TestLog::Message << regularResult << tcu::TestLog::EndMessage;
137 
138 			log << tcu::TestLog::Message << "Cross check - tries to get core functions from improper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
139 			const char* const				mixupResult			= mixupAddressProcCheck(log, failsQuantity, lastGoodVersion->second) ? "Passed" : "Failed";
140 			log << tcu::TestLog::Message << mixupResult << tcu::TestLog::EndMessage;
141 		}
142 
143 		{
144 			FunctionInfosList				extFunctions		= FunctionInfosList();
145 			extFunctions.push_back(FunctionInfo("vkTrimCommandPoolKHR", FUNCTIONORIGIN_DEVICE));
146 			extFunctions.push_back(FunctionInfo("vkCmdPushDescriptorSetKHR", FUNCTIONORIGIN_DEVICE));
147 			extFunctions.push_back(FunctionInfo("vkCreateSamplerYcbcrConversionKHR", FUNCTIONORIGIN_DEVICE));
148 			extFunctions.push_back(FunctionInfo("vkGetSwapchainStatusKHR", FUNCTIONORIGIN_DEVICE));
149 			extFunctions.push_back(FunctionInfo("vkCreateSwapchainKHR", FUNCTIONORIGIN_DEVICE));
150 			extFunctions.push_back(FunctionInfo("vkGetImageSparseMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE));
151 			extFunctions.push_back(FunctionInfo("vkBindBufferMemory2KHR", FUNCTIONORIGIN_DEVICE));
152 			extFunctions.push_back(FunctionInfo("vkImportFenceWin32HandleKHR", FUNCTIONORIGIN_DEVICE));
153 			extFunctions.push_back(FunctionInfo("vkGetBufferMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE));
154 			extFunctions.push_back(FunctionInfo("vkGetImageMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE));
155 
156 			log << tcu::TestLog::Message << "Extensions check - tries to get functions of disabled extensions from proper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
157 			const char * const				result				= specialCasesCheck(log, failsQuantity, extFunctions) ? "Passed" : "Failed";
158 			log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
159 		}
160 
161 		{
162 			FunctionInfosList				dummyFunctions		= FunctionInfosList();
163 			for (deUint32 i = 0; i <= FUNCTIONORIGIN_DEVICE; ++i)
164 			{
165 				const FunctionOrigin origin = static_cast<FunctionOrigin>(i);
166 				dummyFunctions.push_back(FunctionInfo("vkSomeName", origin));
167 				dummyFunctions.push_back(FunctionInfo("vkNonexistingKHR", origin));
168 				dummyFunctions.push_back(FunctionInfo("", origin));
169 			}
170 
171 			log << tcu::TestLog::Message << "Special check - tries to get some dummy functions from various vkGet*ProcAddr." << tcu::TestLog::EndMessage;
172 			const char * const				result				= specialCasesCheck(log, failsQuantity, dummyFunctions) ? "Passed" : "Failed";
173 			log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
174 		}
175 
176 		if (failsQuantity > 0u)
177 			return tcu::TestStatus::fail("Fail");
178 		else
179 			return tcu::TestStatus::pass("Pass");
180 	}
181 
182 private:
183 
184 	GetDeviceProcAddrFunc	getDeviceProcAddr;
185 	GetInstanceProcAddrFunc	getInstanceProcAddr;
186 	Move<VkInstance>		instance;
187 	Move<VkDevice>			device;
188 
findQueueFamilyIndex(const InstanceInterface & vkInstance,VkPhysicalDevice physicalDevice,VkQueueFlags requiredCaps)189 	deUint32 findQueueFamilyIndex(const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
190 	{
191 		deUint32								numQueues = 0;
192 		vkInstance.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, DE_NULL);
193 		if (numQueues > 0)
194 		{
195 			vector<VkQueueFamilyProperties>		properties(numQueues);
196 			vkInstance.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, &properties[0]);
197 			if (numQueues != static_cast<deUint32>(properties.size()))
198 				TCU_FAIL("Returned queue family count changes between queries.");
199 			for (deUint32 queueNdx = 0u; queueNdx < numQueues; queueNdx++)
200 				if ((properties[queueNdx].queueFlags & requiredCaps) == requiredCaps)
201 					return queueNdx;
202 		}
203 		TCU_FAIL("Returned queue family count was 0.");
204 		return 0u;
205 	}
206 
createTestDevice(const PlatformInterface & vkp,const InstanceInterface & vki,VkPhysicalDevice physicalDevice)207 	Move<VkDevice> createTestDevice (const PlatformInterface& vkp, const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
208 	{
209 		vector<string>				enabledLayers;
210 		vector<const char*>			layerPtrs;
211 		vector<const char*>			extensionPtrs;
212 		const float					queuePriority	= 1.0f;
213 		const deUint32				queueIndex		= findQueueFamilyIndex(vki, physicalDevice, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
214 		VkDeviceQueueCreateInfo		queueInfo		= {
215 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
216 			DE_NULL,
217 			static_cast<VkDeviceQueueCreateFlags>(0u),
218 			queueIndex,
219 			1u,
220 			&queuePriority
221 		};
222 		VkDeviceCreateInfo			deviceInfo		= {
223 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
224 			DE_NULL,
225 			static_cast<VkDeviceCreateFlags>(0u),
226 			1u,
227 			&queueInfo,
228 			0u,
229 			DE_NULL,
230 			0u,
231 			DE_NULL,
232 			DE_NULL,
233 		};
234 		return vk::createDevice(vkp, *instance, vki, physicalDevice, &deviceInfo);
235 	}
236 
reportFail(tcu::TestLog & log,const char * const functionName,const char * const firstParamName,const char * const secondParamName,deBool shouldBeNonNull,deUint32 & failsQuantity)237 	void reportFail (tcu::TestLog& log, const char* const functionName, const char* const firstParamName, const char* const secondParamName, deBool shouldBeNonNull, deUint32& failsQuantity)
238 	{
239 		log << tcu::TestLog::Message
240 			<< "[" << failsQuantity << "] " << functionName << '(' << firstParamName << ", \"" << secondParamName << "\") "
241 			<< "returned " << (shouldBeNonNull ? "nullptr" : "non-null") << " should return " << (shouldBeNonNull ? "valid function address" : "nullptr")
242 			<< tcu::TestLog::EndMessage;
243 		++failsQuantity;
244 	}
245 
checkPlatformFunction(tcu::TestLog & log,const char * const name,deBool shouldBeNonNull,deUint32 & failsQuantity)246 	void checkPlatformFunction (tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)
247 	{
248 		if ((getInstanceProcAddr(DE_NULL, name) == DE_NULL) == shouldBeNonNull)
249 			reportFail(log, "vkGetInstanceProcAddr", "DE_NULL", name, shouldBeNonNull, failsQuantity);
250 	}
251 
checkInstanceFunction(tcu::TestLog & log,const char * const name,deBool shouldBeNonNull,deUint32 & failsQuantity)252 	void checkInstanceFunction (tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)
253 	{
254 		if ((getInstanceProcAddr(*instance, name) == DE_NULL) == shouldBeNonNull)
255 			reportFail(log, "vkGetInstanceProcAddr", "instance", name, shouldBeNonNull, failsQuantity);
256 	}
257 
checkDeviceFunction(tcu::TestLog & log,const char * const name,deBool shouldBeNonNull,deUint32 & failsQuantity)258 	void checkDeviceFunction (tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)
259 	{
260 		if ((getDeviceProcAddr(*device, name) == DE_NULL) == shouldBeNonNull)
261 			reportFail(log, "vkGetDeviceProcAddr", "device", name, shouldBeNonNull, failsQuantity);
262 	}
263 
mixupAddressProcCheck(tcu::TestLog & log,deUint32 & failsQuantity,const vector<pair<const char *,FunctionOrigin>> & testsArr)264 	deBool mixupAddressProcCheck (tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)
265 	{
266 		const deUint32 startingQuantity = failsQuantity;
267 		for (deUint32 ndx = 0u; ndx < testsArr.size(); ++ndx)
268 		{
269 			if (deStringEqual(testsArr[ndx].first, "vkGetInstanceProcAddr") || deStringEqual(testsArr[ndx].first, "vkEnumerateInstanceVersion"))
270 				continue;
271 
272 			const char*	   functionName = testsArr[ndx].first;
273 			const deUint32 functionType = testsArr[ndx].second;
274 			if (functionType == FUNCTIONORIGIN_INSTANCE)
275 			{
276 				checkPlatformFunction(log, functionName, DE_FALSE, failsQuantity);
277 				checkDeviceFunction(log, functionName, DE_FALSE, failsQuantity);
278 			}
279 			else if (functionType == FUNCTIONORIGIN_DEVICE)
280 				checkPlatformFunction(log, functionName, DE_FALSE, failsQuantity);
281 		}
282 		return startingQuantity == failsQuantity;
283 	}
284 
specialCasesCheck(tcu::TestLog & log,deUint32 & failsQuantity,const vector<pair<const char *,FunctionOrigin>> & testsArr)285 	deBool specialCasesCheck (tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)
286 	{
287 		const deUint32 startingQuantity = failsQuantity;
288 		for (deUint32 ndx = 0u; ndx < testsArr.size(); ++ndx)
289 		{
290 			const deUint32 functionType = testsArr[ndx].second;
291 			if (functionType == FUNCTIONORIGIN_PLATFORM)
292 				checkPlatformFunction(log, testsArr[ndx].first, DE_FALSE, failsQuantity);
293 			else if (functionType == FUNCTIONORIGIN_INSTANCE)
294 				checkInstanceFunction(log, testsArr[ndx].first, DE_FALSE, failsQuantity);
295 			else if (functionType == FUNCTIONORIGIN_DEVICE)
296 				checkDeviceFunction(log, testsArr[ndx].first, DE_FALSE, failsQuantity);
297 		}
298 		return startingQuantity == failsQuantity;
299 	}
300 
regularCheck(tcu::TestLog & log,deUint32 & failsQuantity,const vector<pair<const char *,FunctionOrigin>> & testsArr)301 	deBool regularCheck (tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)
302 	{
303 		const deUint32 startingQuantity = failsQuantity;
304 		for (deUint32 ndx = 0u; ndx < testsArr.size(); ++ndx)
305 		{
306 			if (deStringEqual(testsArr[ndx].first, "vkGetInstanceProcAddr") || deStringEqual(testsArr[ndx].first, "vkEnumerateInstanceVersion"))
307 				continue;
308 
309 			const deUint32 functionType	= testsArr[ndx].second;
310 			if (functionType == FUNCTIONORIGIN_PLATFORM)
311 				checkPlatformFunction(log, testsArr[ndx].first, DE_TRUE, failsQuantity);
312 			else if (functionType == FUNCTIONORIGIN_INSTANCE)
313 				checkInstanceFunction(log, testsArr[ndx].first, DE_TRUE, failsQuantity);
314 			else if (functionType == FUNCTIONORIGIN_DEVICE)
315 				checkDeviceFunction(log, testsArr[ndx].first, DE_TRUE, failsQuantity);
316 		}
317 		return startingQuantity == failsQuantity;
318 	}
319 };
320 
321 class APIEntryPointsTestCase : public TestCase
322 {
323 public:
APIEntryPointsTestCase(tcu::TestContext & testCtx)324 							APIEntryPointsTestCase			(tcu::TestContext&		testCtx)
325 								: TestCase	(testCtx, "entry_points", "Prints out API info.")
326 	{}
327 
~APIEntryPointsTestCase(void)328 	virtual					~APIEntryPointsTestCase			(void)
329 	{}
createInstance(Context & ctx) const330 	virtual TestInstance*	createInstance					(Context&				ctx) const
331 	{
332 		return new APIEntryPointsTestInstance(ctx);
333 	}
334 
335 private:
336 };
337 
338 } // anonymous
339 
createVersionSanityCheckTests(tcu::TestContext & testCtx)340 tcu::TestCaseGroup*			createVersionSanityCheckTests	(tcu::TestContext & testCtx)
341 {
342 	de::MovePtr<tcu::TestCaseGroup>	versionTests	(new tcu::TestCaseGroup(testCtx, "version_check", "API Version Tests"));
343 	versionTests->addChild(new APIVersionTestCase(testCtx));
344 	versionTests->addChild(new APIEntryPointsTestCase(testCtx));
345 	return versionTests.release();
346 }
347 
348 } // api
349 
350 } // vkt
351