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