• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group 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 VK_EXT_device_fault extension tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktPostmortemDeviceFaultTests.hpp"
25 #include "vktCustomInstancesDevices.hpp"
26 
27 #include "deStringUtil.hpp"
28 #include "vkDefs.hpp"
29 #include "vktTestCase.hpp"
30 #include "vktTestGroupUtil.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuCommandLine.hpp"
33 
34 #include <functional>
35 #include <limits>
36 #include <sstream>
37 #include <utility>
38 #include <vector>
39 
40 #define ARRAY_LENGTH(a_) std::extent<decltype(a_)>::value
41 
42 #ifndef VK_EXT_DEVICE_FAULT_EXTENSION_NAME
43 	#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault"
44 #else
45 	// This should never have happened
46 	// static_assert(false, "Trying to redefine VK_EXT_DEVICE_FAULT_EXTENSION_NAME");
47 #endif
48 
49 namespace vkt
50 {
51 namespace postmortem
52 {
53 namespace
54 {
55 using namespace vk;
56 using namespace tcu;
57 
58 enum class TestType
59 {
60 	Fake,
61 	Real,
62 	CustomDevice
63 };
64 
65 struct TestParams
66 {
67 	TestType	type;
68 };
69 
70 class DeviceFaultCase : public TestCase
71 {
72 public:
DeviceFaultCase(TestContext & testCtx,const std::string & name,const TestParams & params)73 							DeviceFaultCase		(TestContext&		testCtx,
74 												 const std::string&	name,
75 												 const TestParams&	params)
76 								: TestCase	(testCtx, name)
77 								, m_params	(params) {}
78 	virtual					~DeviceFaultCase	() = default;
79 	virtual TestInstance*	createInstance		(Context&			context) const override;
80 	virtual void			checkSupport		(Context&			context) const override;
81 private:
82 	const TestParams	m_params;
83 };
84 
85 class DeviceFaultInstance : public TestInstance
86 {
87 public:
DeviceFaultInstance(Context & context,const TestParams & params)88 							DeviceFaultInstance	(Context& context, const TestParams& params)
89 								: TestInstance				(context)
90 								, m_params					(params) {}
91 	virtual					~DeviceFaultInstance() =  default;
92 
93 	virtual TestStatus		iterate				(void) override;
94 	void					log					(const std::vector<VkDeviceFaultAddressInfoEXT>&	addressInfos,
95 												 const std::vector<VkDeviceFaultVendorInfoEXT>&		vendorInfos,
96 												 const std::vector<deUint8>&						vendorBinaryData) const;
97 private:
98 	const TestParams	m_params;
99 };
100 
101 class DeviceFaultCustomInstance : public TestInstance
102 {
103 public:
DeviceFaultCustomInstance(Context & context)104 							DeviceFaultCustomInstance	(Context& context)
105 								: TestInstance			(context) {}
106 	virtual					~DeviceFaultCustomInstance	() =  default;
107 
108 	virtual TestStatus		iterate						(void) override;
109 };
110 
createInstance(Context & context) const111 TestInstance* DeviceFaultCase::createInstance (Context& context) const
112 {
113 	TestInstance* instance = nullptr;
114 	if (m_params.type == TestType::CustomDevice)
115 		instance = new DeviceFaultCustomInstance(context);
116 	else instance = new DeviceFaultInstance(context, m_params);
117 	return instance;
118 }
119 
120 class CustomDevice
121 {
122 	Move<VkDevice>				m_logicalDevice;
123 
124 public:
CustomDevice(Context & context)125 	CustomDevice (Context& context)
126 	{
127 		const bool								useValidation		= context.getTestContext().getCommandLine().isValidationEnabled();
128 		const PlatformInterface&				platformInterface	= context.getPlatformInterface();
129 		const VkInstance						instance			= context.getInstance();
130 		const InstanceInterface&				instanceInterface	= context.getInstanceInterface();
131 		const VkPhysicalDevice					physicalDevice		= context.getPhysicalDevice();
132 		const deUint32							queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
133 		const float								queuePriority		= 1.0f;
134 
135 		const VkDeviceQueueCreateInfo			queueCreateInfo
136 		{
137 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,				// VkStructureType					sType;
138 			nullptr,												// const void*						pNext;
139 			0,														// VkDeviceQueueCreateFlags			flags;
140 			queueFamilyIndex,										// uint32_t							queueFamilyIndex;
141 			1u,														// uint32_t							queueCount;
142 			&queuePriority											// const float*						pQueuePriorities;
143 		};
144 
145 		VkPhysicalDeviceFaultFeaturesEXT		deviceFaultFeatures
146 		{
147 			VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT,	// VkStructureType					sType;
148 			nullptr,												// void*							pNext;
149 			VK_TRUE,												// VkBool32							deviceFault;
150 			VK_TRUE													// VkBool32							deviceFaultVendorBinary;
151 		};
152 
153 		VkPhysicalDeviceFeatures2				deviceFeatures2
154 		{
155 			VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,			// VkStructureType					sType;
156 			&deviceFaultFeatures,									// void*							pNext;
157 			{ /* zeroed automatically since c++11 */ }				// VkPhysicalDeviceFeatures			features;
158 		};
159 		instanceInterface.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
160 
161 		const VkDeviceCreateInfo				deviceCreateInfo
162 		{
163 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,					// VkStructureType					sType;
164 			&deviceFeatures2,										// const void*						pNext;
165 			0u,														// VkDeviceCreateFlags				flags;
166 			1,														// deUint32							queueCreateInfoCount;
167 			&queueCreateInfo,										// const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
168 			0u,														// deUint32							enabledLayerCount;
169 			nullptr,												// const char* const*				ppEnabledLayerNames;
170 			0u,														// deUint32							enabledExtensionCount;
171 			nullptr,												// const char* const*				ppEnabledExtensionNames;
172 			nullptr													// const VkPhysicalDeviceFeatures*	pEnabledFeatures;
173 		};
174 
175 		m_logicalDevice = createCustomDevice(useValidation, platformInterface, instance, instanceInterface, physicalDevice, &deviceCreateInfo);
176 	}
177 
getDevice() const178 	VkDevice	getDevice () const { return *m_logicalDevice;	}
179 };
180 
181 class FakeInstanceInterface : public InstanceDriver
182 {
183 	const InstanceInterface&	m_instanceInterface;
184 public:
185 
FakeInstanceInterface(Context & ctx)186 	FakeInstanceInterface (Context& ctx)
187 		: InstanceDriver		(ctx.getPlatformInterface(), ctx.getInstance())
188 		, m_instanceInterface	(ctx.getInstanceInterface()) {}
189 
getPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures2 * pFeatures) const190 	virtual void getPhysicalDeviceFeatures2 (VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) const override
191 	{
192 		DE_ASSERT(pFeatures);
193 
194 		InstanceDriver::getPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
195 
196 		auto pBaseStructure = reinterpret_cast<VkBaseOutStructure*>(pFeatures)->pNext;
197 		while (pBaseStructure)
198 		{
199 			if (pBaseStructure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT)
200 			{
201 				const VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures
202 				{
203 					VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT,	// VkStructureType	sType;
204 					nullptr,												// void*			pNext;
205 					VK_TRUE,												// VkBool32		deviceFault;
206 					VK_TRUE													// VkBool32		deviceFaultVendorBinary;
207 				};
208 				*(VkPhysicalDeviceFaultFeaturesEXT*)pBaseStructure = deviceFaultFeatures;
209 				break;
210 			}
211 			pBaseStructure = pBaseStructure->pNext;
212 		}
213 	}
214 };
215 
216 class FakeDeviceInterface : public DeviceDriver
217 {
218 public:
FakeDeviceInterface(Context & ctx)219 	FakeDeviceInterface (Context& ctx)
220 		: DeviceDriver(ctx.getPlatformInterface(), ctx.getInstance(), ctx.getDevice(), ctx.getUsedApiVersion()) {}
221 
222 	struct Header : VkDeviceFaultVendorBinaryHeaderVersionOneEXT
223 	{
224 		char applicationName[32];
225 		char engineName[32];
Headervkt::postmortem::__anon401f98370111::FakeDeviceInterface::Header226 		Header() {
227 			headerSize				= sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT);
228 			headerVersion			= VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT;
229 			vendorID				= 0x9876;
230 			deviceID				= 0x5432;
231 			driverVersion			= VK_MAKE_VERSION(3,4,5);
232 			deMemcpy(pipelineCacheUUID, this, sizeof(pipelineCacheUUID));
233 			applicationNameOffset	= deUint32(sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT));
234 			applicationVersion		= VK_MAKE_API_VERSION(1,7,3,11);
235 			engineNameOffset		= deUint32(applicationNameOffset + sizeof(applicationName));
236 
237 			strcpy(applicationName, "application.exe");
238 			strcpy(engineName, "driver.so.3.4.5");
239 		}
240 	};
241 
getDeviceFaultInfoEXT(VkDevice,VkDeviceFaultCountsEXT * pFaultCounts,VkDeviceFaultInfoEXT * pFaultInfo) const242 	virtual VkResult getDeviceFaultInfoEXT (VkDevice, VkDeviceFaultCountsEXT* pFaultCounts, VkDeviceFaultInfoEXT* pFaultInfo) const override
243 	{
244 		static std::vector<VkDeviceFaultAddressInfoEXT>	addressInfos;
245 		static std::vector<VkDeviceFaultVendorInfoEXT>	vendorInfos;
246 		static VkDeviceFaultAddressTypeEXT				addressTypes[]
247 		{
248 			VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT,
249 			VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT,
250 			VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT,
251 			VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT,
252 			VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT,
253 			VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT,
254 			VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT,
255 		};
256 		static VkDeviceSize								addressPrecisions[]
257 		{
258 			2, 4, 8, 16
259 		};
260 		static deUint64									vendorFaultCodes[]
261 		{
262 			0x11223344, 0x22334455, 0xAABBCCDD, 0xCCDDEEFF
263 		};
264 		static Header									vendorBinaryData;
265 
266 		if (DE_NULL == pFaultInfo)
267 		{
268 			if (DE_NULL == pFaultCounts) return VK_ERROR_UNKNOWN;
269 
270 			DE_ASSERT(pFaultCounts->sType == VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT);
271 			DE_ASSERT(pFaultCounts->pNext == nullptr);
272 
273 			pFaultCounts->vendorBinarySize = sizeof(Header);
274 			pFaultCounts->vendorInfoCount = 2;
275 			pFaultCounts->addressInfoCount = 2;
276 		}
277 		else
278 		{
279 			DE_ASSERT(pFaultCounts);
280 			DE_ASSERT(pFaultCounts->sType == VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT);
281 			DE_ASSERT(pFaultCounts->pNext == nullptr);
282 			DE_ASSERT(pFaultInfo->sType == VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT);
283 			DE_ASSERT(pFaultInfo->pNext == nullptr);
284 
285 			if (pFaultCounts->addressInfoCount && pFaultInfo->pAddressInfos)
286 			{
287 				VkDeviceAddress	deviceAddress = 1024;
288 				addressInfos.resize(pFaultCounts->addressInfoCount);
289 				for (deUint32 i = 0; i < pFaultCounts->addressInfoCount; ++i)
290 				{
291 					VkDeviceFaultAddressInfoEXT& info = addressInfos[i];
292 					info.addressType		= addressTypes[ i % ARRAY_LENGTH(addressTypes) ];
293 					info.addressPrecision	= addressPrecisions[ i % ARRAY_LENGTH(addressPrecisions) ];
294 					info.reportedAddress	= deviceAddress;
295 					deviceAddress			<<= 1;
296 
297 					pFaultInfo->pAddressInfos[i] = info;
298 				}
299 			}
300 
301 			if (pFaultCounts->vendorInfoCount && pFaultInfo->pVendorInfos)
302 			{
303 				vendorInfos.resize(pFaultCounts->vendorInfoCount);
304 				for (deUint32 i = 0; i < pFaultCounts->vendorInfoCount; ++i)
305 				{
306 					VkDeviceFaultVendorInfoEXT& info = vendorInfos[i];
307 					info.vendorFaultCode = vendorFaultCodes[ i % ARRAY_LENGTH(vendorFaultCodes) ];
308 					info.vendorFaultData = (i + 1) % ARRAY_LENGTH(vendorFaultCodes);
309 					deMemset(info.description, 0, sizeof(info.description));
310 
311 					std::stringstream s;
312 					s << "VendorFaultDescription" << info.vendorFaultData;
313 					s.sync();
314 					const auto& str = s.str();
315 					deMemcpy(info.description, str.c_str(), str.length());
316 
317 					pFaultInfo->pVendorInfos[i] = info;
318 				}
319 			}
320 
321 			if (pFaultCounts->vendorBinarySize && pFaultInfo->pVendorBinaryData)
322 			{
323 				DE_ASSERT(pFaultCounts->vendorBinarySize >= sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT));
324 				deMemcpy(pFaultInfo->pVendorBinaryData, &vendorBinaryData,
325 						 deMaxu32(sizeof(Header), deUint32(pFaultCounts->vendorBinarySize)));
326 			}
327 		}
328 
329 		return VK_SUCCESS;
330 	}
331 };
332 
333 class FakeContext
334 {
335 	FakeDeviceInterface		m_deviceInterface;
336 	FakeInstanceInterface	m_instanceInterface;
337 public:
338 
FakeContext(Context & ctx)339 	FakeContext (Context& ctx)
340 		: m_deviceInterface		(ctx)
341 		, m_instanceInterface	(ctx) {}
342 
getDeviceInterface() const343 	const DeviceInterface&		getDeviceInterface () const { return m_deviceInterface; }
getInstanceInterface() const344 	const InstanceInterface&	getInstanceInterface () const { return m_instanceInterface; }
345 };
346 
checkSupport(Context & context) const347 void DeviceFaultCase::checkSupport (Context& context) const
348 {
349 	FakeContext					fakeContext			(context);
350 	VkPhysicalDevice			physicalDevice		= context.getPhysicalDevice();
351 	const InstanceInterface&	instanceInterface	= (m_params.type == TestType::Real) ? context.getInstanceInterface() : fakeContext.getInstanceInterface();
352 
353 	context.requireInstanceFunctionality(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
354 
355 	if (m_params.type == TestType::Real)
356 	{
357 		context.requireDeviceFunctionality(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
358 	}
359 
360 	VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures{};
361 	deviceFaultFeatures.sType	= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
362 
363 	VkPhysicalDeviceFeatures2		deviceFeatures2{};
364 	deviceFeatures2.sType		= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
365 	deviceFeatures2.pNext		= &deviceFaultFeatures;
366 
367 	instanceInterface.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
368 
369 	if (VK_FALSE == deviceFaultFeatures.deviceFault)
370 		TCU_THROW(NotSupportedError, "VK_EXT_device_fault extension is not supported by device");
371 }
372 
iterate(void)373 TestStatus DeviceFaultCustomInstance::iterate (void)
374 {
375 	CustomDevice		customDevice	(m_context);
376 	const VkDevice		device			= customDevice.getDevice();
377 	return (device != DE_NULL) ? TestStatus::pass("") : TestStatus::fail("");
378 }
379 
log(const std::vector<VkDeviceFaultAddressInfoEXT> & addressInfos,const std::vector<VkDeviceFaultVendorInfoEXT> & vendorInfos,const std::vector<deUint8> & vendorBinaryData) const380 void DeviceFaultInstance::log (const std::vector<VkDeviceFaultAddressInfoEXT>&	addressInfos,
381 							   const std::vector<VkDeviceFaultVendorInfoEXT>&	vendorInfos,
382 							   const std::vector<deUint8>&						vendorBinaryData) const
383 {
384 	const char*	nl = "\n";
385 	deUint32	cnt = 0;
386 	TestLog&	log = m_context.getTestContext().getLog();
387 
388 	if (addressInfos.size())
389 	{
390 		log << TestLog::Section("addressInfos", "");
391 		auto msg = log << TestLog::Message;
392 		cnt = 0;
393 		for (const auto& addressInfo : addressInfos)
394 		{
395 			if (cnt++) msg << nl;
396 			msg << addressInfo;
397 		}
398 		msg << TestLog::EndMessage << TestLog::EndSection;
399 	}
400 
401 	if (vendorInfos.size())
402 	{
403 		log << TestLog::Section("vendorInfos", "");
404 		auto msg = log << TestLog::Message;
405 		cnt = 0;
406 		for (const auto& vendorInfo : vendorInfos)
407 		{
408 			if (cnt++) msg << nl;
409 			msg << vendorInfo;
410 		}
411 		msg << TestLog::EndMessage << TestLog::EndSection;
412 	}
413 
414 	if (vendorBinaryData.size())
415 	{
416 		DE_ASSERT(vendorBinaryData.size() >= sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT));
417 
418 		log << TestLog::Section("vendorBinaryData", "");
419 		auto msg = log << TestLog::Message;
420 		auto pHeader = reinterpret_cast<VkDeviceFaultVendorBinaryHeaderVersionOneEXT const*>(vendorBinaryData.data());
421 		msg << *pHeader;
422 		msg << TestLog::EndMessage << TestLog::EndSection;
423 	}
424 }
425 
iterate(void)426 TestStatus DeviceFaultInstance::iterate (void)
427 {
428 	FakeContext					fakeContext			(m_context);
429 	const VkDevice				device				= m_context.getDevice();
430 	const VkPhysicalDevice		physicalDevice		= m_context.getPhysicalDevice();
431 	const DeviceInterface&		deviceInterface		= (m_params.type == TestType::Fake) ? fakeContext.getDeviceInterface() : m_context.getDeviceInterface();
432 	const InstanceInterface&	instanceInterface	= (m_params.type == TestType::Fake) ? fakeContext.getInstanceInterface() : m_context.getInstanceInterface();
433 
434 	VkDeviceFaultCountsEXT	fc{};
435 	fc.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
436 	fc.pNext = nullptr;
437 	deviceInterface.getDeviceFaultInfoEXT(device, &fc, nullptr);
438 
439 	const deUint32 vendorBinarySize = std::min(deUint32(fc.vendorBinarySize), std::numeric_limits<deUint32>::max());
440 
441 	VkPhysicalDeviceFaultFeaturesEXT	deviceFaultFeatures{};
442 	deviceFaultFeatures.sType	= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
443 
444 	VkPhysicalDeviceFeatures2			deviceFeatures2{};
445 	deviceFeatures2.sType		= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
446 	deviceFeatures2.pNext		= &deviceFaultFeatures;
447 
448 	instanceInterface.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
449 
450 	fc.vendorBinarySize = deviceFaultFeatures.deviceFaultVendorBinary ? vendorBinarySize : 0;
451 
452 	std::vector<VkDeviceFaultAddressInfoEXT>	addressInfos	(fc.addressInfoCount);
453 	std::vector<VkDeviceFaultVendorInfoEXT>		vendorInfos		(fc.vendorInfoCount);
454 	std::vector<deUint8>						vendorBinaryData(vendorBinarySize);
455 
456 	VkDeviceFaultInfoEXT fi{};
457 	fi.sType				= VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
458 	fi.pNext				= nullptr;
459 	fi.pAddressInfos		= addressInfos.data();
460 	fi.pVendorInfos			= vendorInfos.data();
461 	fi.pVendorBinaryData	= deviceFaultFeatures.deviceFaultVendorBinary ? vendorBinaryData.data() : nullptr;
462 
463 	const VkResult result = deviceInterface.getDeviceFaultInfoEXT(device, &fc, &fi);
464 
465 	log(addressInfos, vendorInfos, vendorBinaryData);
466 
467 	return (result == VK_SUCCESS) ? TestStatus::pass("") : TestStatus::fail("");
468 }
469 
470 } // unnamed
471 
createDeviceFaultTests(tcu::TestContext & testCtx)472 tcu::TestCaseGroup*	createDeviceFaultTests (tcu::TestContext& testCtx)
473 {
474 	TestParams p;
475 	struct {
476 		TestType	type;
477 		const char*	name;
478 	} const types[] = { { TestType::Real, "real" }, { TestType::Fake, "fake" }, { TestType::CustomDevice, "custom_device" } };
479 
480 	auto rootGroup = new TestCaseGroup(testCtx, "device_fault");
481 	for (const auto& type : types)
482 	{
483 		p.type = type.type;
484 		rootGroup->addChild(new DeviceFaultCase(testCtx, type.name, p));
485 	}
486 	return rootGroup;
487 }
488 
489 } // postmortem
490 } // vkt
491