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