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 Vulkan SC fault handling tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktFaultHandlingTests.hpp"
25
26 #include <set>
27 #include <vector>
28 #include <string>
29
30 #include "vktTestCaseUtil.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkSafetyCriticalUtil.hpp"
33 #include "vktCustomInstancesDevices.hpp"
34 #include "tcuTestLog.hpp"
35
36 namespace vkt
37 {
38 namespace sc
39 {
40
41 using namespace vk;
42
43 namespace
44 {
45
46 enum FHFaultValue
47 {
48 FHF_UNUSED = 0,
49 FHF_NULL,
50 FHF_ARRAY
51 };
52
53 struct TestParams
54 {
55 VkFaultQueryBehavior queryBehaviour;
56 FHFaultValue faultValue;
57 };
58
testGetFaultData(Context & context,TestParams testParams)59 tcu::TestStatus testGetFaultData(Context &context, TestParams testParams)
60 {
61 const DeviceInterface &vk = context.getDeviceInterface();
62 const VkDevice device = context.getDevice();
63
64 uint32_t maxQueryFaultCount = context.getDeviceVulkanSC10Properties().maxQueryFaultCount;
65
66 VkBool32 unrecordedFaults = VK_TRUE;
67 uint32_t faultCount = maxQueryFaultCount;
68 std::vector<VkFaultData> faults;
69 for (uint32_t i = 0; i < maxQueryFaultCount; ++i)
70 {
71 faults.push_back({
72 VK_STRUCTURE_TYPE_FAULT_DATA, // VkStructureType sType;
73 DE_NULL, // void* pNext;
74 VK_FAULT_LEVEL_UNASSIGNED, // VkFaultLevel faultLevel;
75 VK_FAULT_TYPE_UNASSIGNED, // VkFaultType faultType;
76 });
77 }
78 bool isOK = true;
79 bool faultsModified = false;
80 VkResult result;
81
82 switch (testParams.faultValue)
83 {
84 case FHF_NULL:
85 result = vk.getFaultData(device, testParams.queryBehaviour, &unrecordedFaults, &faultCount, DE_NULL);
86
87 if (result != VK_SUCCESS)
88 {
89 context.getTestContext().getLog()
90 << tcu::TestLog::Message << "Result is not VK_SUCCESS" << tcu::TestLog::EndMessage;
91 isOK = false;
92 }
93 if (unrecordedFaults != VK_FALSE)
94 {
95 context.getTestContext().getLog()
96 << tcu::TestLog::Message << "unrecordedFaults is not VK_FALSE" << tcu::TestLog::EndMessage;
97 isOK = false;
98 }
99 if (faultCount != 0u)
100 {
101 context.getTestContext().getLog()
102 << tcu::TestLog::Message << "faultCount is not 0" << tcu::TestLog::EndMessage;
103 isOK = false;
104 }
105 break;
106 case FHF_ARRAY:
107 result = vk.getFaultData(device, testParams.queryBehaviour, &unrecordedFaults, &faultCount, faults.data());
108
109 if (result != VK_SUCCESS)
110 {
111 context.getTestContext().getLog()
112 << tcu::TestLog::Message << "Result is not VK_SUCCESS" << tcu::TestLog::EndMessage;
113 isOK = false;
114 }
115 if (unrecordedFaults != VK_FALSE)
116 {
117 context.getTestContext().getLog()
118 << tcu::TestLog::Message << "unrecordedFaults is not VK_FALSE" << tcu::TestLog::EndMessage;
119 isOK = false;
120 }
121 if (faultCount != 0u)
122 {
123 context.getTestContext().getLog()
124 << tcu::TestLog::Message << "faultCount is not 0" << tcu::TestLog::EndMessage;
125 isOK = false;
126 }
127 for (uint32_t i = 0; i < maxQueryFaultCount; ++i)
128 if (faults[i].faultLevel != VK_FAULT_LEVEL_UNASSIGNED || faults[i].faultType != VK_FAULT_TYPE_UNASSIGNED)
129 faultsModified = true;
130 if (faultsModified)
131 {
132 context.getTestContext().getLog()
133 << tcu::TestLog::Message << "pFaults have been modified" << tcu::TestLog::EndMessage;
134 isOK = false;
135 }
136 break;
137 default:
138 TCU_THROW(InternalError, "Unrecognized fault type");
139 }
140
141 return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
142 }
143
testFaultCallback(VkBool32 incompleteFaultData,uint32_t faultCount,const VkFaultData * pFaultData)144 VKAPI_ATTR void VKAPI_CALL testFaultCallback(VkBool32 incompleteFaultData, uint32_t faultCount,
145 const VkFaultData *pFaultData)
146 {
147 DE_UNREF(incompleteFaultData);
148 DE_UNREF(faultCount);
149 DE_UNREF(pFaultData);
150 }
151
152 struct FaultCallbackInfoTestParams
153 {
154 bool allocateFaultData;
155 };
156
testCreateDeviceWithFaultCallbackInfo(Context & context,FaultCallbackInfoTestParams testParams)157 tcu::TestStatus testCreateDeviceWithFaultCallbackInfo(Context &context, FaultCallbackInfoTestParams testParams)
158 {
159 const CustomInstance instance(createCustomInstanceFromContext(context));
160 const InstanceDriver &instanceDriver(instance.getDriver());
161 const VkPhysicalDevice physicalDevice =
162 chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine());
163
164 void *pNext = DE_NULL;
165
166 VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ?
167 context.getResourceInterface()->getStatMax() :
168 resetDeviceObjectReservationCreateInfo();
169 memReservationInfo.pNext = pNext;
170 pNext = &memReservationInfo;
171
172 VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
173 sc10Features.pNext = pNext;
174 pNext = &sc10Features;
175
176 // create VkFaultCallbackInfo
177 uint32_t maxQueryFaultCount = context.getDeviceVulkanSC10Properties().maxQueryFaultCount;
178 std::vector<VkFaultData> faults;
179
180 if (testParams.allocateFaultData)
181 {
182 for (uint32_t i = 0; i < maxQueryFaultCount; ++i)
183 {
184 faults.push_back({
185 VK_STRUCTURE_TYPE_FAULT_DATA, // VkStructureType sType;
186 DE_NULL, // void* pNext;
187 VK_FAULT_LEVEL_UNASSIGNED, // VkFaultLevel faultLevel;
188 VK_FAULT_TYPE_UNASSIGNED, // VkFaultType faultType;
189 });
190 }
191 }
192
193 VkFaultCallbackInfo faultCallBackInfo = {
194 VK_STRUCTURE_TYPE_FAULT_CALLBACK_INFO, // VkStructureType sType;
195 DE_NULL, // void* pNext;
196 uint32_t(faults.size()), // uint32_t faultCount;
197 testParams.allocateFaultData ? faults.data() : nullptr, // VkFaultData* pFaults;
198 testFaultCallback // PFN_vkFaultCallbackFunction pfnFaultCallback;
199 };
200 faultCallBackInfo.pNext = pNext;
201 pNext = &faultCallBackInfo;
202
203 // create VkDeviceCreateInfo
204
205 const float queuePriority = 1.0f;
206
207 const VkDeviceQueueCreateInfo deviceQueueCI = {
208 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
209 DE_NULL, // pNext
210 (VkDeviceQueueCreateFlags)0u, // flags
211 0, //queueFamilyIndex;
212 1, //queueCount;
213 &queuePriority, //pQueuePriorities;
214 };
215
216 VkDeviceCreateInfo deviceCreateInfo = {
217 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType;
218 pNext, // pNext;
219 (VkDeviceCreateFlags)0u, // flags
220 1, // queueRecordCount;
221 &deviceQueueCI, // pRequestedQueues;
222 0, // layerCount;
223 DE_NULL, // ppEnabledLayerNames;
224 0, // extensionCount;
225 DE_NULL, // ppEnabledExtensionNames;
226 DE_NULL, // pEnabledFeatures;
227 };
228
229 Move<VkDevice> resultingDevice =
230 createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
231 context.getPlatformInterface(), instance, instanceDriver, physicalDevice, &deviceCreateInfo);
232
233 return tcu::TestStatus::pass("Pass");
234 }
235
236 } // namespace
237
createFaultHandlingTests(tcu::TestContext & testCtx)238 tcu::TestCaseGroup *createFaultHandlingTests(tcu::TestContext &testCtx)
239 {
240 // Tests verifying Vulkan SC fault handling
241 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "fault_handling"));
242
243 // add tests for vkGetFaultData function
244 {
245 // Testing vkGetFaultData results
246 de::MovePtr<tcu::TestCaseGroup> getFaultDataGroup(new tcu::TestCaseGroup(testCtx, "get_fault_data"));
247
248 const struct
249 {
250 VkFaultQueryBehavior queryBehaviour;
251 const char *name;
252 } behaviours[] = {
253 {VK_FAULT_QUERY_BEHAVIOR_GET_AND_CLEAR_ALL_FAULTS, "get_and_clear_all_faults"},
254 };
255
256 const struct
257 {
258 FHFaultValue faultValue;
259 const char *name;
260 } faults[] = {
261 {FHF_NULL, "null"},
262 {FHF_ARRAY, "array"},
263 };
264
265 for (int behaviourIdx = 0; behaviourIdx < DE_LENGTH_OF_ARRAY(behaviours); ++behaviourIdx)
266 {
267 de::MovePtr<tcu::TestCaseGroup> behaviourGroup(
268 new tcu::TestCaseGroup(testCtx, behaviours[behaviourIdx].name));
269
270 for (int faultIdx = 0; faultIdx < DE_LENGTH_OF_ARRAY(faults); ++faultIdx)
271 {
272 TestParams testParams{behaviours[behaviourIdx].queryBehaviour, faults[faultIdx].faultValue};
273
274 addFunctionCase(behaviourGroup.get(), faults[faultIdx].name, testGetFaultData, testParams);
275 }
276 getFaultDataGroup->addChild(behaviourGroup.release());
277 }
278 group->addChild(getFaultDataGroup.release());
279 }
280
281 // add tests for VkFaultCallbackInfo
282 {
283 de::MovePtr<tcu::TestCaseGroup> faultCallbackInfoGroup(new tcu::TestCaseGroup(testCtx, "fault_callback_info"));
284
285 {
286 FaultCallbackInfoTestParams testParams{true};
287 addFunctionCase(faultCallbackInfoGroup.get(), "create_device_with_callback_with_fault_data",
288 testCreateDeviceWithFaultCallbackInfo, testParams);
289 }
290 {
291 FaultCallbackInfoTestParams testParams{false};
292 addFunctionCase(faultCallbackInfoGroup.get(), "create_device_with_callback_without_fault_data",
293 testCreateDeviceWithFaultCallbackInfo, testParams);
294 }
295 group->addChild(faultCallbackInfoGroup.release());
296 }
297
298 return group.release();
299 }
300
301 } // namespace sc
302
303 } // namespace vkt
304