1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 *
6 * Copyright (c) 2019 Google Inc.
7 * Copyright (c) 2019 Khronos Group
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 * \file
23 * \brief API Version Check test - prints out version info
24 *//*--------------------------------------------------------------------*/
25 
26 #include <iostream>
27 #include <typeinfo>
28 
29 #include "tcuDefs.hpp"
30 #include "tcuTestCase.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuFunctionLibrary.hpp"
33 #include "tcuPlatform.hpp"
34 #include "tcuCommandLine.hpp"
35 
36 #include "vkApiVersion.hpp"
37 #include "vkDefs.hpp"
38 #include "vkPlatform.hpp"
39 #include "vkSafetyCriticalUtil.hpp"
40 
41 #include "vktApiVersionCheck.hpp"
42 #include "vktTestCase.hpp"
43 #include "vktCustomInstancesDevices.hpp"
44 
45 #include "vkDeviceUtil.hpp"
46 #include "vkQueryUtil.hpp"
47 #include "vkRefUtil.hpp"
48 
49 #include "deString.h"
50 #include "deStringUtil.hpp"
51 
52 #include <map>
53 #include <vector>
54 
55 using namespace vk;
56 using namespace std;
57 
58 namespace vkt
59 {
60 
61 namespace api
62 {
63 
64 namespace
65 {
66 
67 #include "vkExtensionFunctions.inl"
68 #include "vkCoreFunctionalities.inl"
69 
70 class APIVersionTestInstance : public TestInstance
71 {
72 public:
APIVersionTestInstance(Context& ctx)73 								APIVersionTestInstance	(Context&				ctx)
74 									: TestInstance	(ctx)
75 	{}
iterate(void)76 	virtual tcu::TestStatus		iterate					(void)
77 	{
78 		tcu::TestLog&			log						= m_context.getTestContext().getLog();
79 		const vk::ApiVersion	maxVulkanVersion		= vk::unpackVersion(m_context.getMaximumFrameworkVulkanVersion());
80 		const vk::ApiVersion	instanceVersion			= vk::unpackVersion(m_context.getAvailableInstanceVersion());
81 		const ::std::string		instanceVersionString	= de::toString(instanceVersion.majorNum) + ::std::string(".") + de::toString(instanceVersion.minorNum) + ::std::string(".") + de::toString(instanceVersion.patchNum);
82 		const vk::ApiVersion	deviceVersion			= vk::unpackVersion(m_context.getDeviceVersion());
83 		const ::std::string		deviceVersionString		= de::toString(deviceVersion.majorNum) + ::std::string(".") + de::toString(deviceVersion.minorNum) + ::std::string(".") + de::toString(deviceVersion.patchNum);
84 		const vk::ApiVersion	usedApiVersion			= vk::unpackVersion(m_context.getUsedApiVersion());
85 		const ::std::string		usedApiVersionString	= de::toString(usedApiVersion.majorNum) + ::std::string(".") + de::toString(usedApiVersion.minorNum) + ::std::string(".") + de::toString(usedApiVersion.patchNum);
86 
87 		log << tcu::TestLog::Message << "availableInstanceVersion: " << instanceVersion << tcu::TestLog::EndMessage;
88 		log << tcu::TestLog::Message << "deviceVersion: " << deviceVersion << tcu::TestLog::EndMessage;
89 		log << tcu::TestLog::Message << "usedApiVersion: " << usedApiVersion << tcu::TestLog::EndMessage;
90 
91 		if (deviceVersion.majorNum > maxVulkanVersion.majorNum || deviceVersion.minorNum > maxVulkanVersion.minorNum)
92 			return tcu::TestStatus::fail(de::toString("This version of CTS does not support Vulkan device version ") + deviceVersionString);
93 		else
94 			return tcu::TestStatus::pass(usedApiVersionString);
95 	}
96 };
97 
98 class APIVersionTestCase : public TestCase
99 {
100 public:
APIVersionTestCase(tcu::TestContext& testCtx)101 							APIVersionTestCase	(tcu::TestContext&		testCtx)
102 								: TestCase	(testCtx, "version")
103 	{}
104 
~APIVersionTestCase(void)105 	virtual					~APIVersionTestCase	(void)
106 	{}
createInstance(Context& ctx) const107 	virtual TestInstance*	createInstance		(Context&				ctx) const
108 	{
109 		return new APIVersionTestInstance(ctx);
110 	}
111 
112 private:
113 };
114 
115 class APIEntryPointsTestInstance : public TestInstance
116 {
117 public:
118 	struct APIContext
119 	{
120 		VkInstance				instance;
121 		VkDevice				device;
122 		GetInstanceProcAddrFunc	getInstanceProcAddr;
123 		GetDeviceProcAddrFunc	getDeviceProcAddr;
124 	};
125 
APIEntryPointsTestInstance(Context& ctx)126 								APIEntryPointsTestInstance	(Context&				ctx)
127 									: TestInstance	(ctx)
128 	{
129 	}
130 
iterate(void)131 	virtual tcu::TestStatus		iterate						(void)
132 	{
133 		tcu::TestLog&						log					= m_context.getTestContext().getLog();
134 		const deUint32						instanceApiVersion	= m_context.getAvailableInstanceVersion();
135 		const deUint32						deviceApiVersion	= m_context.getUsedApiVersion();
136 		const vk::Platform&					platform			= m_context.getTestContext().getPlatform().getVulkanPlatform();
137 #ifdef DE_PLATFORM_USE_LIBRARY_TYPE
138 		de::MovePtr<vk::Library>			vkLibrary			= de::MovePtr<vk::Library>(platform.createLibrary(vk::Platform::LibraryType::LIBRARY_TYPE_VULKAN, m_context.getTestContext().getCommandLine().getVkLibraryPath()));
139 #else
140 		de::MovePtr<vk::Library>			vkLibrary			= de::MovePtr<vk::Library>(platform.createLibrary(m_context.getTestContext().getCommandLine().getVkLibraryPath()));
141 #endif
142 		const tcu::FunctionLibrary&			funcLibrary			= vkLibrary->getFunctionLibrary();
143 		deUint32							failsQuantity		= 0u;
144 
145 		// Tests with default instance and device without extensions
146 		{
147 			CustomInstance			instance			= createCustomInstanceFromContext(m_context, DE_NULL, false);
148 			Move<VkDevice>			device				= createTestDevice(m_context, instance, vector<string>(), false);
149 			GetInstanceProcAddrFunc	getInstanceProcAddr	= reinterpret_cast<GetInstanceProcAddrFunc>(funcLibrary.getFunction("vkGetInstanceProcAddr"));
150 			GetDeviceProcAddrFunc	getDeviceProcAddr	= reinterpret_cast<GetDeviceProcAddrFunc>(getInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
151 			APIContext				ctx					= { instance, *device, getInstanceProcAddr, getDeviceProcAddr };
152 
153 			// Check entry points of core functions
154 			{
155 				ApisMap							functions			= ApisMap();
156 				initApisMap(functions);
157 				ApisMap::const_iterator			lastGoodVersion		= functions.begin();
158 				const ApisMap::const_iterator	versionsEnd			= functions.end();
159 				for (ApisMap::const_iterator it = lastGoodVersion; it != versionsEnd; ++it)
160 				{
161 					if (it->first <= m_context.getUsedApiVersion())
162 						lastGoodVersion = it;
163 				}
164 
165 				log << tcu::TestLog::Message << "Regular check - tries to get core functions from proper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
166 				const char* const				regularResult		= regularCheck(ctx, log, failsQuantity, lastGoodVersion->second) ? "Passed" : "Failed";
167 				log << tcu::TestLog::Message << regularResult << tcu::TestLog::EndMessage;
168 
169 				log << tcu::TestLog::Message << "Cross check - tries to get core functions from improper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
170 				const char* const				mixupResult			= mixupAddressProcCheck(ctx, log, failsQuantity, lastGoodVersion->second) ? "Passed" : "Failed";
171 				log << tcu::TestLog::Message << mixupResult << tcu::TestLog::EndMessage;
172 			}
173 
174 			// Check function entry points of disabled extensions
175 			{
176 				FunctionInfosList				extFunctions		= FunctionInfosList();
177 				extFunctions.push_back(FunctionInfo("vkTrimCommandPoolKHR", FUNCTIONORIGIN_DEVICE));
178 				extFunctions.push_back(FunctionInfo("vkCmdPushDescriptorSetKHR", FUNCTIONORIGIN_DEVICE));
179 				extFunctions.push_back(FunctionInfo("vkCreateSamplerYcbcrConversionKHR", FUNCTIONORIGIN_DEVICE));
180 				extFunctions.push_back(FunctionInfo("vkGetSwapchainStatusKHR", FUNCTIONORIGIN_DEVICE));
181 				extFunctions.push_back(FunctionInfo("vkCreateSwapchainKHR", FUNCTIONORIGIN_DEVICE));
182 				extFunctions.push_back(FunctionInfo("vkGetImageSparseMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE));
183 				extFunctions.push_back(FunctionInfo("vkBindBufferMemory2KHR", FUNCTIONORIGIN_DEVICE));
184 				extFunctions.push_back(FunctionInfo("vkImportFenceWin32HandleKHR", FUNCTIONORIGIN_DEVICE));
185 				extFunctions.push_back(FunctionInfo("vkGetBufferMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE));
186 				extFunctions.push_back(FunctionInfo("vkGetImageMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE));
187 
188 				log << tcu::TestLog::Message << "Disabled extensions check - tries to get functions of disabled extensions from proper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
189 				const char * const				result					= specialCasesCheck(ctx, log, failsQuantity, extFunctions) ? "Passed" : "Failed";
190 				log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
191 			}
192 
193 			// Check special cases
194 			{
195 				FunctionInfosList				nonexistingFunctions	= FunctionInfosList();
196 				for (deUint32 i = 0; i <= FUNCTIONORIGIN_DEVICE; ++i)
197 				{
198 					const FunctionOrigin origin = static_cast<FunctionOrigin>(i);
199 					nonexistingFunctions.push_back(FunctionInfo("vkSomeName", origin));
200 					nonexistingFunctions.push_back(FunctionInfo("vkNonexistingKHR", origin));
201 					nonexistingFunctions.push_back(FunctionInfo("", origin));
202 				}
203 
204 				log << tcu::TestLog::Message << "Special check - tries to get some nonexisting functions from various vkGet*ProcAddr." << tcu::TestLog::EndMessage;
205 				const char * const				result				= specialCasesCheck(ctx, log, failsQuantity, nonexistingFunctions) ? "Passed" : "Failed";
206 				log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
207 			}
208 		}
209 
210 		// Tests with instance and device with extensions
211 		{
212 			CustomInstance			instance			= createCustomInstanceWithExtensions(m_context, getSupportedInstanceExtensions(instanceApiVersion), DE_NULL, false);
213 			Move<VkDevice>			device				= createTestDevice(m_context, instance, getSupportedDeviceExtensions(deviceApiVersion), false);
214 			GetInstanceProcAddrFunc	getInstanceProcAddr	= reinterpret_cast<GetInstanceProcAddrFunc>(funcLibrary.getFunction("vkGetInstanceProcAddr"));
215 			GetDeviceProcAddrFunc	getDeviceProcAddr	= reinterpret_cast<GetDeviceProcAddrFunc>(getInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
216 			APIContext				ctx					= { instance, *device, getInstanceProcAddr, getDeviceProcAddr };
217 
218 			// Check function entry points of enabled extensions
219 			{
220 				vector<FunctionInfo>	extFunctions;
221 
222 				// Add supported instance extension functions
223 				for (size_t instanceExtNdx = 0; instanceExtNdx < DE_LENGTH_OF_ARRAY(instanceExtensionNames); instanceExtNdx++)
224 				{
225 					vector<const char*> instanceExtFunctions;
226 					vector<const char*> deviceExtFunctions;
227 
228 					if (isSupportedInstanceExt(instanceExtensionNames[instanceExtNdx], instanceApiVersion))
229 					{
230 						getInstanceExtensionFunctions(instanceApiVersion, instanceExtensionNames[instanceExtNdx], instanceExtFunctions);
231 					}
232 					if (isSupportedInstanceExt(instanceExtensionNames[instanceExtNdx], deviceApiVersion))
233 					{
234 						getDeviceExtensionFunctions(deviceApiVersion, instanceExtensionNames[instanceExtNdx], deviceExtFunctions);
235 					}
236 
237 					for (size_t instanceFuncNdx = 0; instanceFuncNdx < instanceExtFunctions.size(); instanceFuncNdx++)
238 						extFunctions.push_back(FunctionInfo(instanceExtFunctions[instanceFuncNdx], FUNCTIONORIGIN_INSTANCE));
239 
240 					for (size_t deviceFuncNdx = 0; deviceFuncNdx < deviceExtFunctions.size(); deviceFuncNdx++)
241 						extFunctions.push_back(FunctionInfo(deviceExtFunctions[deviceFuncNdx], FUNCTIONORIGIN_DEVICE));
242 				}
243 
244 				// Add supported device extension functions
245 				for (size_t deviceExtNdx = 0; deviceExtNdx < DE_LENGTH_OF_ARRAY(deviceExtensionNames); deviceExtNdx++)
246 				{
247 					vector<const char*> deviceExtFunctions;
248 
249 					if (isSupportedDeviceExt(deviceExtensionNames[deviceExtNdx], deviceApiVersion))
250 						getDeviceExtensionFunctions(deviceApiVersion, deviceExtensionNames[deviceExtNdx], deviceExtFunctions);
251 
252 					for (size_t deviceFuncNdx = 0; deviceFuncNdx < deviceExtFunctions.size(); deviceFuncNdx++)
253 						extFunctions.push_back(FunctionInfo(deviceExtFunctions[deviceFuncNdx], FUNCTIONORIGIN_DEVICE));
254 				}
255 
256 				log << tcu::TestLog::Message << "Enabled extensions check - tries to get functions of supported extensions from proper vkGet*ProcAddr." << tcu::TestLog::EndMessage;
257 				const char * const		result = regularCheck(ctx, log, failsQuantity, extFunctions) ? "Passed" : "Failed";
258 				log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
259 			}
260 		}
261 
262 		if (failsQuantity > 0u)
263 			return tcu::TestStatus::fail("Fail");
264 		else
265 			return tcu::TestStatus::pass("Pass");
266 	}
267 
268 private:
269 
findQueueFamilyIndex(const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)270 	deUint32 findQueueFamilyIndex(const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
271 	{
272 		deUint32								numQueues = 0;
273 		vkInstance.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, DE_NULL);
274 		if (numQueues > 0)
275 		{
276 			vector<VkQueueFamilyProperties>		properties(numQueues);
277 			vkInstance.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, &properties[0]);
278 			if (numQueues != static_cast<deUint32>(properties.size()))
279 				TCU_FAIL("Returned queue family count changes between queries.");
280 			for (deUint32 queueNdx = 0u; queueNdx < numQueues; queueNdx++)
281 				if ((properties[queueNdx].queueFlags & requiredCaps) == requiredCaps)
282 					return queueNdx;
283 		}
284 		TCU_FAIL("Returned queue family count was 0.");
285 		return 0u;
286 	}
287 
filterMultiAuthorExtensions(vector<VkExtensionProperties> extProperties)288 	vector<string> filterMultiAuthorExtensions (vector<VkExtensionProperties> extProperties)
289 	{
290 		vector<string>	multiAuthorExtensions;
291 		const char*		extensionGroups[] =
292 		{
293 			"VK_KHR_",
294 			"VK_EXT_"
295 		};
296 
297 		for (size_t extNdx = 0; extNdx < extProperties.size(); extNdx++)
298 		{
299 			for (int extGroupNdx = 0; extGroupNdx < DE_LENGTH_OF_ARRAY(extensionGroups); extGroupNdx++)
300 			{
301 				if (deStringBeginsWith(extProperties[extNdx].extensionName, extensionGroups[extGroupNdx]))
302 					multiAuthorExtensions.push_back(extProperties[extNdx].extensionName);
303 			}
304 		}
305 
306 		return multiAuthorExtensions;
307 	}
308 
getSupportedInstanceExtensions(const deUint32 apiVersion)309 	vector<string> getSupportedInstanceExtensions (const deUint32 apiVersion)
310 	{
311 		vector<VkExtensionProperties>	enumeratedExtensions (enumerateInstanceExtensionProperties(m_context.getPlatformInterface(), DE_NULL));
312 		vector<VkExtensionProperties>	supportedExtensions;
313 
314 		for (size_t extNdx = 0; extNdx < enumeratedExtensions.size(); extNdx++)
315 		{
316 			if (!isCoreInstanceExtension(apiVersion, enumeratedExtensions[extNdx].extensionName))
317 				supportedExtensions.push_back(enumeratedExtensions[extNdx]);
318 		}
319 
320 		return filterMultiAuthorExtensions(supportedExtensions);
321 	}
322 
getSupportedDeviceExtensions(const deUint32 apiVersion)323 	vector<string> getSupportedDeviceExtensions (const deUint32 apiVersion)
324 	{
325 		vector<VkExtensionProperties>	enumeratedExtensions (enumerateDeviceExtensionProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), DE_NULL));
326 		vector<VkExtensionProperties>	supportedExtensions;
327 
328 		for (size_t extNdx = 0; extNdx < enumeratedExtensions.size(); extNdx++)
329 		{
330 			if (!isCoreDeviceExtension(apiVersion, enumeratedExtensions[extNdx].extensionName))
331 				supportedExtensions.push_back(enumeratedExtensions[extNdx]);
332 		}
333 
334 		return filterMultiAuthorExtensions(supportedExtensions);
335 	}
336 
createTestDevice(const Context& context, VkInstance instance, vector<string> extensions = vector<string>(), bool allowLayers = true)337 	Move<VkDevice> createTestDevice (const Context& context, VkInstance instance, vector<string> extensions = vector<string>(), bool allowLayers = true)
338 	{
339 		auto&						cmdLine			= context.getTestContext().getCommandLine();
340 		const PlatformInterface&	vkp				= context.getPlatformInterface();
341 		const InstanceInterface&	vki				= context.getInstanceInterface();
342 		VkPhysicalDevice			physicalDevice	= chooseDevice(context.getInstanceInterface(), instance, cmdLine);
343 		vector<const char*>			extensionPtrs;
344 		const float					queuePriority	= 1.0f;
345 		const deUint32				queueIndex		= findQueueFamilyIndex(vki, physicalDevice, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
346 
347 		for (size_t i = 0; i < extensions.size(); i++)
348 			extensionPtrs.push_back(extensions[i].c_str());
349 
350 		VkDeviceQueueCreateInfo		queueInfo		= {
351 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
352 			DE_NULL,
353 			static_cast<VkDeviceQueueCreateFlags>(0u),
354 			queueIndex,
355 			1u,
356 			&queuePriority
357 		};
358 
359 		void* pNext									= DE_NULL;
360 #ifdef CTS_USES_VULKANSC
361 		VkDeviceObjectReservationCreateInfo memReservationInfo	= context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo();
362 		memReservationInfo.pNext								= pNext;
363 		pNext													= &memReservationInfo;
364 
365 		VkPhysicalDeviceVulkanSC10Features sc10Features			= createDefaultSC10Features();
366 		sc10Features.pNext										= pNext;
367 		pNext													= &sc10Features;
368 
369 		VkPipelineCacheCreateInfo			pcCI;
370 		std::vector<VkPipelinePoolSize>		poolSizes;
371 		if (context.getTestContext().getCommandLine().isSubProcess())
372 		{
373 			if (context.getResourceInterface()->getCacheDataSize() > 0)
374 			{
375 				pcCI =
376 				{
377 					VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,		// VkStructureType				sType;
378 					DE_NULL,											// const void*					pNext;
379 					VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
380 						VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT,	// VkPipelineCacheCreateFlags	flags;
381 					context.getResourceInterface()->getCacheDataSize(),	// deUintptr					initialDataSize;
382 					context.getResourceInterface()->getCacheData()		// const void*					pInitialData;
383 				};
384 				memReservationInfo.pipelineCacheCreateInfoCount		= 1;
385 				memReservationInfo.pPipelineCacheCreateInfos		= &pcCI;
386 			}
387 
388 			poolSizes							= context.getResourceInterface()->getPipelinePoolSizes();
389 			if (!poolSizes.empty())
390 			{
391 				memReservationInfo.pipelinePoolSizeCount		= deUint32(poolSizes.size());
392 				memReservationInfo.pPipelinePoolSizes			= poolSizes.data();
393 			}
394 		}
395 #endif // CTS_USES_VULKANSC
396 
397 		const VkDeviceCreateInfo	deviceInfo		= {
398 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
399 			pNext,
400 			static_cast<VkDeviceCreateFlags>(0u),
401 			1u,
402 			&queueInfo,
403 			0u,
404 			DE_NULL,
405 			(deUint32)extensions.size(),
406 			extensions.size() ? &extensionPtrs[0] : DE_NULL,
407 			DE_NULL,
408 		};
409 
410 		const bool					validationEnabled = (cmdLine.isValidationEnabled() && allowLayers);
411 		return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceInfo);
412 	}
413 
reportFail(tcu::TestLog& log, const char* const functionName, const char* const firstParamName, const char* const secondParamName, deBool shouldBeNonNull, deUint32& failsQuantity)414 	void reportFail (tcu::TestLog& log, const char* const functionName, const char* const firstParamName, const char* const secondParamName, deBool shouldBeNonNull, deUint32& failsQuantity)
415 	{
416 		log << tcu::TestLog::Message
417 			<< "[" << failsQuantity << "] " << functionName << '(' << firstParamName << ", \"" << secondParamName << "\") "
418 			<< "returned " << (shouldBeNonNull ? "nullptr" : "non-null") << ". Should return " << (shouldBeNonNull ? "valid function address." : "nullptr.")
419 			<< tcu::TestLog::EndMessage;
420 		++failsQuantity;
421 	}
422 
checkPlatformFunction(const APIContext& ctx, tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)423 	void checkPlatformFunction (const APIContext& ctx, tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)
424 	{
425 		if ((ctx.getInstanceProcAddr(DE_NULL, name) == DE_NULL) == shouldBeNonNull)
426 			reportFail(log, "vkGetInstanceProcAddr", "DE_NULL", name, shouldBeNonNull, failsQuantity);
427 	}
428 
checkInstanceFunction(const APIContext& ctx, tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)429 	void checkInstanceFunction (const APIContext& ctx, tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)
430 	{
431 		if ((ctx.getInstanceProcAddr(ctx.instance, name) == DE_NULL) == shouldBeNonNull)
432 			reportFail(log, "vkGetInstanceProcAddr", "instance", name, shouldBeNonNull, failsQuantity);
433 	}
434 
checkDeviceFunction(const APIContext& ctx, tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)435 	void checkDeviceFunction (const APIContext& ctx, tcu::TestLog& log, const char* const name, deBool shouldBeNonNull, deUint32& failsQuantity)
436 	{
437 		if ((ctx.getDeviceProcAddr(ctx.device, name) == DE_NULL) == shouldBeNonNull)
438 			reportFail(log, "vkGetDeviceProcAddr", "device", name, shouldBeNonNull, failsQuantity);
439 	}
440 
isSupportedInstanceExt(const string extName, const deUint32 apiVersion)441 	deBool isSupportedInstanceExt (const string extName, const deUint32 apiVersion)
442 	{
443 		const vector<string> supportedInstanceExtensions (getSupportedInstanceExtensions(apiVersion));
444 
445 		return de::contains(supportedInstanceExtensions.begin(), supportedInstanceExtensions.end(), extName);
446 	}
447 
isSupportedDeviceExt(const string extName, const deUint32 apiVersion)448 	deBool isSupportedDeviceExt (const string extName, const deUint32 apiVersion)
449 	{
450 		const vector<string> supportedDeviceExtensions (getSupportedDeviceExtensions(apiVersion));
451 
452 		return de::contains(supportedDeviceExtensions.begin(), supportedDeviceExtensions.end(), extName);
453 	}
454 
mixupAddressProcCheck(const APIContext& ctx, tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)455 	deBool mixupAddressProcCheck (const APIContext& ctx, tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)
456 	{
457 		const deUint32 startingQuantity = failsQuantity;
458 		for (deUint32 ndx = 0u; ndx < testsArr.size(); ++ndx)
459 		{
460 			if (deStringEqual(testsArr[ndx].first, "vkGetInstanceProcAddr") || deStringEqual(testsArr[ndx].first, "vkEnumerateInstanceVersion"))
461 				continue;
462 
463 			const char*	   functionName = testsArr[ndx].first;
464 			const deUint32 functionType = testsArr[ndx].second;
465 			if (functionType == FUNCTIONORIGIN_INSTANCE)
466 			{
467 				checkPlatformFunction(ctx, log, functionName, DE_FALSE, failsQuantity);
468 				checkDeviceFunction(ctx, log, functionName, DE_FALSE, failsQuantity);
469 			}
470 			else if (functionType == FUNCTIONORIGIN_DEVICE)
471 				checkPlatformFunction(ctx, log, functionName, DE_FALSE, failsQuantity);
472 		}
473 		return startingQuantity == failsQuantity;
474 	}
475 
specialCasesCheck(const APIContext& ctx, tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)476 	deBool specialCasesCheck (const APIContext& ctx, tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)
477 	{
478 		const deUint32 startingQuantity = failsQuantity;
479 		for (deUint32 ndx = 0u; ndx < testsArr.size(); ++ndx)
480 		{
481 			const deUint32 functionType = testsArr[ndx].second;
482 			if (functionType == FUNCTIONORIGIN_PLATFORM)
483 				checkPlatformFunction(ctx, log, testsArr[ndx].first, DE_FALSE, failsQuantity);
484 			else if (functionType == FUNCTIONORIGIN_INSTANCE)
485 				checkInstanceFunction(ctx, log, testsArr[ndx].first, DE_FALSE, failsQuantity);
486 			else if (functionType == FUNCTIONORIGIN_DEVICE)
487 				checkDeviceFunction(ctx, log, testsArr[ndx].first, DE_FALSE, failsQuantity);
488 		}
489 		return startingQuantity == failsQuantity;
490 	}
491 
regularCheck(const APIContext& ctx, tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)492 	deBool regularCheck (const APIContext& ctx, tcu::TestLog& log, deUint32& failsQuantity, const vector<pair<const char*, FunctionOrigin> >& testsArr)
493 	{
494 		const deUint32 startingQuantity = failsQuantity;
495 
496 		for (deUint32 ndx = 0u; ndx < testsArr.size(); ++ndx)
497 		{
498 			const auto&	funcName	= testsArr[ndx].first;
499 			const auto&	funcType	= testsArr[ndx].second;
500 			const auto	apiVersion	= m_context.getUsedApiVersion();
501 
502 			if (deStringEqual(funcName, "vkGetInstanceProcAddr") && apiVersion < VK_API_VERSION_1_2)
503 				continue;
504 
505 			// VK_KHR_draw_indirect_count was promoted to core in Vulkan 1.2, but these entrypoints are not mandatory unless the
506 			// device supports the extension. In that case, the drawIndirectCount feature bit will also be true. Any of the two
507 			// checks is valid. We use the extension name for convenience here.
508 			if ((deStringEqual(funcName, "vkCmdDrawIndirectCount") || deStringEqual(funcName, "vkCmdDrawIndexedIndirectCount"))
509 				&& !isSupportedDeviceExt("VK_KHR_draw_indirect_count", apiVersion))
510 				continue;
511 
512 			// vkCmdPushDescriptorSetWithTemplateKHR is available if:
513 			// - VK_KHR_push_descriptor is supported AND
514 			//   - API >= VK_VERSION_1_1 OR
515 			//   - VK_KHR_descriptor_update_template is supported
516 			if (deStringEqual(funcName, "vkCmdPushDescriptorSetWithTemplateKHR") &&
517 			    (!isSupportedDeviceExt("VK_KHR_push_descriptor", apiVersion) ||
518 			      (apiVersion < VK_API_VERSION_1_1 && !isSupportedDeviceExt("VK_KHR_descriptor_update_template", apiVersion))))
519 				continue;
520 
521 			if (funcType == FUNCTIONORIGIN_PLATFORM)
522 			{
523 				checkPlatformFunction(ctx, log, funcName, DE_TRUE, failsQuantity);
524 			}
525 			else if (funcType == FUNCTIONORIGIN_INSTANCE)
526 			{
527 				checkInstanceFunction(ctx, log, funcName, DE_TRUE, failsQuantity);
528 				checkDeviceFunction(ctx, log, funcName, DE_FALSE, failsQuantity);
529 			}
530 			else if (funcType == FUNCTIONORIGIN_DEVICE)
531 			{
532 				checkInstanceFunction(ctx, log, funcName, DE_TRUE, failsQuantity);
533 				checkDeviceFunction(ctx, log, funcName, DE_TRUE, failsQuantity);
534 			}
535 		}
536 
537 		return startingQuantity == failsQuantity;
538 	}
539 };
540 
541 class APIEntryPointsTestCase : public TestCase
542 {
543 public:
APIEntryPointsTestCase(tcu::TestContext& testCtx)544 							APIEntryPointsTestCase			(tcu::TestContext&		testCtx)
545 								: TestCase	(testCtx, "entry_points")
546 	{}
547 
~APIEntryPointsTestCase(void)548 	virtual					~APIEntryPointsTestCase			(void)
549 	{}
createInstance(Context& ctx) const550 	virtual TestInstance*	createInstance					(Context&				ctx) const
551 	{
552 		return new APIEntryPointsTestInstance(ctx);
553 	}
554 
555 private:
556 };
557 
558 class APIUnavailableEntryPointsTestInstance : public TestInstance
559 {
560 public:
APIUnavailableEntryPointsTestInstance(Context& ctx)561 	APIUnavailableEntryPointsTestInstance(Context& ctx): TestInstance(ctx)
562 	{}
563 
iterate(void)564 	virtual tcu::TestStatus iterate(void)
565 	{
566 		const vk::PlatformInterface&	vkp					= m_context.getPlatformInterface();
567 		tcu::TestLog&					log					= m_context.getTestContext().getLog();
568 		const auto						supportedApiVersion	= m_context.getUsedApiVersion();
569 		bool							testPassed			= true;
570 
571 		ApisMap functionsPerVersion;
572 		initApisMap(functionsPerVersion);
573 
574 		// create custom instance for each api version
575 		for (const auto& testedApiVersion : functionsPerVersion)
576 		{
577 			// we cant test api versions that are higher then api version support by this device
578 			if (testedApiVersion.first > supportedApiVersion)
579 				break;
580 
581 			// there is no api version above the last api version
582 			if (testedApiVersion.first == functionsPerVersion.rbegin()->first)
583 				break;
584 
585 			VkApplicationInfo appInfo	= initVulkanStructure();
586 			appInfo.pApplicationName	= "a";
587 			appInfo.pEngineName			= "b";
588 			appInfo.apiVersion			= testedApiVersion.first;
589 			VkInstanceCreateInfo instanceCreateInfo	= initVulkanStructure();
590 			instanceCreateInfo.pApplicationInfo		= &appInfo;
591 
592 #ifndef CTS_USES_VULKANSC
593 			char const * requiredExtensionForVk10 = "VK_KHR_get_physical_device_properties2";
594 			if (appInfo.apiVersion == VK_API_VERSION_1_0)
595 			{
596 				instanceCreateInfo.enabledExtensionCount = 1U;
597 				instanceCreateInfo.ppEnabledExtensionNames = &requiredExtensionForVk10;
598 			}
599 #endif // CTS_USES_VULKANSC
600 
601 			// create instance for currentluy tested vulkan version
602 			Move<VkInstance>					customInstance			(vk::createInstance(vkp, &instanceCreateInfo, DE_NULL));
603 			std::unique_ptr<vk::InstanceDriver>	instanceDriver			(new InstanceDriver(vkp, *customInstance));
604 			const VkPhysicalDevice				physicalDevice			= chooseDevice(*instanceDriver, *customInstance, m_context.getTestContext().getCommandLine());
605 			const auto							queueFamilyProperties	= getPhysicalDeviceQueueFamilyProperties(*instanceDriver, physicalDevice);
606 
607 			const float queuePriority = 1.0f;
608 			VkDeviceQueueCreateInfo deviceQueueCreateInfo	= initVulkanStructure();
609 			deviceQueueCreateInfo.queueCount				= 1;
610 			deviceQueueCreateInfo.pQueuePriorities			= &queuePriority;
611 
612 			VkDeviceCreateInfo deviceCreateInfo				= initVulkanStructure();
613 			deviceCreateInfo.queueCreateInfoCount			= 1u;
614 			deviceCreateInfo.pQueueCreateInfos				= &deviceQueueCreateInfo;
615 
616 #ifndef CTS_USES_VULKANSC
617 			char const * extensionName						= "VK_KHR_maintenance5";
618 			deviceCreateInfo.enabledExtensionCount			= 1u;
619 			deviceCreateInfo.ppEnabledExtensionNames		= &extensionName;
620 
621 			vk::VkPhysicalDeviceMaintenance5FeaturesKHR maint5 = initVulkanStructure();
622 			vk::VkPhysicalDeviceFeatures2 features2			= initVulkanStructure(&maint5);
623 			instanceDriver->getPhysicalDeviceFeatures2(physicalDevice, &features2);
624 			deviceCreateInfo.pNext							= &features2;
625 #endif // CTS_USES_VULKANSC
626 
627 			// create custom device
628 			const Unique<VkDevice>	device			(createCustomDevice(false, vkp, *customInstance, *instanceDriver, physicalDevice, &deviceCreateInfo));
629 			const DeviceDriver		deviceDriver	(vkp, *customInstance, *device, supportedApiVersion);
630 
631 			log << tcu::TestLog::Message << "Checking apiVersion("
632 				<< VK_API_VERSION_MAJOR(testedApiVersion.first) << ", "
633 				<< VK_API_VERSION_MINOR(testedApiVersion.first) << ")" << tcu::TestLog::EndMessage;
634 
635 			// iterate over api versions that are above tested api version
636 			auto& previousVersionFunctions = functionsPerVersion[VK_API_VERSION_1_0];
637 			for (const auto& versionFunctions : functionsPerVersion)
638 			{
639 				// skip api versions that are not above tested api version
640 				if (versionFunctions.first <= testedApiVersion.first)
641 				{
642 					previousVersionFunctions = versionFunctions.second;
643 					continue;
644 				}
645 
646 				// iterate over all functions
647 				for (const auto& function : versionFunctions.second)
648 				{
649 					// we are interested only in device functions
650 					if (function.second != FUNCTIONORIGIN_DEVICE)
651 						continue;
652 
653 					// skip functions that are present in previous version;
654 					// functionsPerVersion contains all functions that are
655 					// available in vulkan version, not only ones that were added
656 					const auto&	funcName	= function.first;
657 					const auto	isMatch		= [&funcName](const FunctionInfo& fi) { return !strcmp(funcName, fi.first); };
658 					auto matchIt = std::find_if(begin(previousVersionFunctions), end(previousVersionFunctions), isMatch);
659 					if (matchIt != previousVersionFunctions.end())
660 						continue;
661 
662 					// check if returned function pointer is NULL
663 					if (deviceDriver.getDeviceProcAddr(*device, funcName) != DE_NULL)
664 					{
665 						log << tcu::TestLog::Message << "getDeviceProcAddr(" << funcName
666 							<< ") returned non-null pointer, expected NULL" << tcu::TestLog::EndMessage;
667 						testPassed = false;
668 					}
669 				}
670 
671 				previousVersionFunctions = versionFunctions.second;
672 			}
673 		}
674 
675 		if (testPassed)
676 			return tcu::TestStatus::pass("Pass");
677 		return tcu::TestStatus::fail("Fail");
678 	}
679 };
680 
681 class APIUnavailableEntryPointsTestCase : public TestCase
682 {
683 public:
684 	// Check if vkGetDeviceProcAddr returns NULL for functions beyond app version.
APIUnavailableEntryPointsTestCase(tcu::TestContext& testCtx)685 	APIUnavailableEntryPointsTestCase(tcu::TestContext& testCtx)
686 		: TestCase(testCtx, "unavailable_entry_points")
687 	{}
688 
checkSupport(Context& context) const689 	virtual void			checkSupport(Context& context) const
690 	{
691 		context.requireDeviceFunctionality("VK_KHR_maintenance5");
692 	}
693 
createInstance(Context& ctx) const694 	virtual TestInstance*	createInstance(Context& ctx) const
695 	{
696 		return new APIUnavailableEntryPointsTestInstance(ctx);
697 	}
698 };
699 
700 } // anonymous
701 
createVersionSanityCheckTests(tcu::TestContext & testCtx)702 tcu::TestCaseGroup*			createVersionSanityCheckTests	(tcu::TestContext & testCtx)
703 {
704 	de::MovePtr<tcu::TestCaseGroup>	versionTests	(new tcu::TestCaseGroup(testCtx, "version_check"));
705 	versionTests->addChild(new APIVersionTestCase(testCtx));
706 	versionTests->addChild(new APIEntryPointsTestCase(testCtx));
707 
708 #ifndef CTS_USES_VULKANSC
709 	versionTests->addChild(new APIUnavailableEntryPointsTestCase(testCtx));
710 #endif
711 
712 	return versionTests.release();
713 }
714 
715 } // api
716 
717 } // vkt
718