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