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) : TestInstance(ctx)
74 {
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(".") +
82 de::toString(instanceVersion.minorNum) + ::std::string(".") +
83 de::toString(instanceVersion.patchNum);
84 const vk::ApiVersion deviceVersion = vk::unpackVersion(m_context.getDeviceVersion());
85 const ::std::string deviceVersionString = de::toString(deviceVersion.majorNum) + ::std::string(".") +
86 de::toString(deviceVersion.minorNum) + ::std::string(".") +
87 de::toString(deviceVersion.patchNum);
88 const vk::ApiVersion usedApiVersion = vk::unpackVersion(m_context.getUsedApiVersion());
89 const ::std::string usedApiVersionString = de::toString(usedApiVersion.majorNum) + ::std::string(".") +
90 de::toString(usedApiVersion.minorNum) + ::std::string(".") +
91 de::toString(usedApiVersion.patchNum);
92
93 log << tcu::TestLog::Message << "availableInstanceVersion: " << instanceVersion << tcu::TestLog::EndMessage;
94 log << tcu::TestLog::Message << "deviceVersion: " << deviceVersion << tcu::TestLog::EndMessage;
95 log << tcu::TestLog::Message << "usedApiVersion: " << usedApiVersion << tcu::TestLog::EndMessage;
96
97 if (deviceVersion.majorNum > maxVulkanVersion.majorNum || deviceVersion.minorNum > maxVulkanVersion.minorNum)
98 return tcu::TestStatus::fail(de::toString("This version of CTS does not support Vulkan device version ") +
99 deviceVersionString);
100 else
101 return tcu::TestStatus::pass(usedApiVersionString);
102 }
103 };
104
105 class APIVersionTestCase : public TestCase
106 {
107 public:
APIVersionTestCase(tcu::TestContext & testCtx)108 APIVersionTestCase(tcu::TestContext &testCtx) : TestCase(testCtx, "version")
109 {
110 }
111
~APIVersionTestCase(void)112 virtual ~APIVersionTestCase(void)
113 {
114 }
createInstance(Context & ctx) const115 virtual TestInstance *createInstance(Context &ctx) const
116 {
117 return new APIVersionTestInstance(ctx);
118 }
119
120 private:
121 };
122
123 class APIEntryPointsTestInstance : public TestInstance
124 {
125 public:
126 struct APIContext
127 {
128 VkInstance instance;
129 VkDevice device;
130 GetInstanceProcAddrFunc getInstanceProcAddr;
131 GetDeviceProcAddrFunc getDeviceProcAddr;
132 };
133
APIEntryPointsTestInstance(Context & ctx)134 APIEntryPointsTestInstance(Context &ctx) : TestInstance(ctx)
135 {
136 }
137
iterate(void)138 virtual tcu::TestStatus iterate(void)
139 {
140 tcu::TestLog &log = m_context.getTestContext().getLog();
141 const uint32_t instanceApiVersion = m_context.getAvailableInstanceVersion();
142 const uint32_t deviceApiVersion = m_context.getUsedApiVersion();
143 const vk::Platform &platform = m_context.getTestContext().getPlatform().getVulkanPlatform();
144 #ifdef DE_PLATFORM_USE_LIBRARY_TYPE
145 de::MovePtr<vk::Library> vkLibrary = de::MovePtr<vk::Library>(
146 platform.createLibrary(vk::Platform::LibraryType::LIBRARY_TYPE_VULKAN,
147 m_context.getTestContext().getCommandLine().getVkLibraryPath()));
148 #else
149 de::MovePtr<vk::Library> vkLibrary = de::MovePtr<vk::Library>(
150 platform.createLibrary(m_context.getTestContext().getCommandLine().getVkLibraryPath()));
151 #endif
152 const tcu::FunctionLibrary &funcLibrary = vkLibrary->getFunctionLibrary();
153 uint32_t failsQuantity = 0u;
154
155 // Tests with default instance and device without extensions
156 {
157 CustomInstance instance = createCustomInstanceFromContext(m_context, nullptr, false);
158 Move<VkDevice> device = createTestDevice(m_context, instance, vector<string>(), false);
159 GetInstanceProcAddrFunc getInstanceProcAddr =
160 reinterpret_cast<GetInstanceProcAddrFunc>(funcLibrary.getFunction("vkGetInstanceProcAddr"));
161 GetDeviceProcAddrFunc getDeviceProcAddr =
162 reinterpret_cast<GetDeviceProcAddrFunc>(getInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
163 APIContext ctx = {instance, *device, getInstanceProcAddr, getDeviceProcAddr};
164
165 // Check entry points of core functions
166 {
167 ApisMap functions;
168 initApisMap(functions);
169
170 #if defined(CTS_USES_VULKAN)
171 // For vulkan 1.4+ we may need to test optionaly promoted VK_EXT_host_image_copy
172 if (m_context.getDeviceVulkan14Features().hostImageCopy)
173 {
174 const char *hostImageCopyFunctions[]{"vkCopyMemoryToImage", "vkCopyImageToMemory",
175 "vkCopyImageToImage", "vkTransitionImageLayout",
176 "vkGetImageSubresourceLayout2"};
177 auto &vk14Functions = functions[VK_API_VERSION_1_4];
178 for (const auto fun : hostImageCopyFunctions)
179 vk14Functions.emplace_back(fun, FUNCTIONORIGIN_DEVICE);
180 }
181 #endif
182
183 ApisMap::const_iterator lastGoodVersion = functions.begin();
184 const ApisMap::const_iterator versionsEnd = functions.end();
185 for (ApisMap::const_iterator it = lastGoodVersion; it != versionsEnd; ++it)
186 {
187 if (it->first <= m_context.getUsedApiVersion())
188 lastGoodVersion = it;
189 }
190
191 log << tcu::TestLog::Message
192 << "Regular check - tries to get core functions from proper vkGet*ProcAddr."
193 << tcu::TestLog::EndMessage;
194 const char *const regularResult =
195 regularCheck(ctx, log, failsQuantity, lastGoodVersion->second) ? "Passed" : "Failed";
196 log << tcu::TestLog::Message << regularResult << tcu::TestLog::EndMessage;
197
198 log << tcu::TestLog::Message
199 << "Cross check - tries to get core functions from improper vkGet*ProcAddr."
200 << tcu::TestLog::EndMessage;
201 const char *const mixupResult =
202 mixupAddressProcCheck(ctx, log, failsQuantity, lastGoodVersion->second) ? "Passed" : "Failed";
203 log << tcu::TestLog::Message << mixupResult << tcu::TestLog::EndMessage;
204 }
205
206 // Check function entry points of disabled extensions
207 {
208 FunctionInfosList extFunctions = {
209 {"vkTrimCommandPoolKHR", FUNCTIONORIGIN_DEVICE},
210 {"vkCmdPushDescriptorSetKHR", FUNCTIONORIGIN_DEVICE},
211 {"vkCreateSamplerYcbcrConversionKHR", FUNCTIONORIGIN_DEVICE},
212 {"vkCreateSwapchainKHR", FUNCTIONORIGIN_DEVICE},
213 {"vkGetImageSparseMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE},
214 {"vkBindBufferMemory2KHR", FUNCTIONORIGIN_DEVICE},
215 {"vkImportFenceWin32HandleKHR", FUNCTIONORIGIN_DEVICE},
216 {"vkGetBufferMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE},
217 {"vkGetImageMemoryRequirements2KHR", FUNCTIONORIGIN_DEVICE},
218 };
219
220 log << tcu::TestLog::Message
221 << "Disabled extensions check - tries to get functions of disabled extensions from proper "
222 "vkGet*ProcAddr."
223 << tcu::TestLog::EndMessage;
224 const char *const result =
225 specialCasesCheck(ctx, log, failsQuantity, extFunctions) ? "Passed" : "Failed";
226 log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
227 }
228
229 // Check special cases
230 {
231 FunctionInfosList nonexistingFunctions;
232 for (uint32_t i = 0; i <= FUNCTIONORIGIN_DEVICE; ++i)
233 {
234 const FunctionOrigin origin = static_cast<FunctionOrigin>(i);
235 nonexistingFunctions.emplace_back("vkSomeName", origin);
236 nonexistingFunctions.emplace_back("vkNonexistingKHR", origin);
237 nonexistingFunctions.emplace_back("", origin);
238 }
239
240 log << tcu::TestLog::Message
241 << "Special check - tries to get some nonexisting functions from various vkGet*ProcAddr."
242 << tcu::TestLog::EndMessage;
243 const char *const result =
244 specialCasesCheck(ctx, log, failsQuantity, nonexistingFunctions) ? "Passed" : "Failed";
245 log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
246 }
247 }
248
249 // Tests with instance and device with extensions
250 {
251 const vector<string> supportedInstanceExtensions = getSupportedInstanceExtensions(instanceApiVersion);
252 CustomInstance instance =
253 createCustomInstanceWithExtensions(m_context, supportedInstanceExtensions, nullptr, false);
254 const vector<string> supportedDeviceExtensions = getSupportedDeviceExtensions(deviceApiVersion);
255 Move<VkDevice> device = createTestDevice(m_context, instance, supportedDeviceExtensions, false);
256 GetInstanceProcAddrFunc getInstanceProcAddr =
257 reinterpret_cast<GetInstanceProcAddrFunc>(funcLibrary.getFunction("vkGetInstanceProcAddr"));
258 GetDeviceProcAddrFunc getDeviceProcAddr =
259 reinterpret_cast<GetDeviceProcAddrFunc>(getInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
260 APIContext ctx = {instance, *device, getInstanceProcAddr, getDeviceProcAddr};
261
262 // Check function entry points of enabled extensions
263 {
264 vector<FunctionInfo> extFunctions;
265
266 // Add supported instance extension functions
267 for (auto instanceExtensionName : instanceExtensionNames)
268 {
269 vector<const char *> instanceExtFunctions;
270 vector<const char *> deviceExtFunctions;
271
272 if (isSupportedInstanceExt(instanceExtensionName, instanceApiVersion))
273 {
274 getInstanceExtensionFunctions(instanceApiVersion, supportedInstanceExtensions,
275 supportedDeviceExtensions, instanceExtensionName,
276 instanceExtFunctions);
277 }
278 if (isSupportedInstanceExt(instanceExtensionName, deviceApiVersion))
279 {
280 getDeviceExtensionFunctions(deviceApiVersion, supportedInstanceExtensions,
281 supportedDeviceExtensions, instanceExtensionName,
282 deviceExtFunctions);
283 }
284
285 for (auto instanceFunc : instanceExtFunctions)
286 extFunctions.emplace_back(instanceFunc, FUNCTIONORIGIN_INSTANCE);
287
288 for (auto deviceFunc : deviceExtFunctions)
289 extFunctions.emplace_back(deviceFunc, FUNCTIONORIGIN_DEVICE);
290 }
291
292 // Add supported device extension functions
293 for (const auto &deviceExtensionName : deviceExtensionNames)
294 {
295 vector<const char *> deviceExtFunctions;
296
297 if (isSupportedDeviceExt(deviceExtensionName, deviceApiVersion))
298 getDeviceExtensionFunctions(deviceApiVersion, supportedInstanceExtensions,
299 supportedDeviceExtensions, deviceExtensionName, deviceExtFunctions);
300
301 for (auto deviceFunc : deviceExtFunctions)
302 extFunctions.emplace_back(deviceFunc, FUNCTIONORIGIN_DEVICE);
303 }
304
305 log << tcu::TestLog::Message
306 << "Enabled extensions check - tries to get functions of supported extensions from proper "
307 "vkGet*ProcAddr."
308 << tcu::TestLog::EndMessage;
309 const char *const result = regularCheck(ctx, log, failsQuantity, extFunctions) ? "Passed" : "Failed";
310 log << tcu::TestLog::Message << result << tcu::TestLog::EndMessage;
311 }
312 }
313
314 if (failsQuantity > 0u)
315 return tcu::TestStatus::fail("Fail");
316
317 return tcu::TestStatus::pass("Pass");
318 }
319
320 private:
findQueueFamilyIndex(const InstanceInterface & vkInstance,VkPhysicalDevice physicalDevice,VkQueueFlags requiredCaps)321 uint32_t findQueueFamilyIndex(const InstanceInterface &vkInstance, VkPhysicalDevice physicalDevice,
322 VkQueueFlags requiredCaps)
323 {
324 uint32_t numQueues = 0;
325 vkInstance.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, nullptr);
326 if (numQueues > 0)
327 {
328 vector<VkQueueFamilyProperties> properties(numQueues);
329 vkInstance.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, &properties[0]);
330 if (numQueues != static_cast<uint32_t>(properties.size()))
331 TCU_FAIL("Returned queue family count changes between queries.");
332 for (uint32_t queueNdx = 0u; queueNdx < numQueues; queueNdx++)
333 if ((properties[queueNdx].queueFlags & requiredCaps) == requiredCaps)
334 return queueNdx;
335 }
336 TCU_FAIL("Returned queue family count was 0.");
337 return 0u;
338 }
339
filterMultiAuthorExtensions(vector<VkExtensionProperties> extProperties)340 vector<string> filterMultiAuthorExtensions(vector<VkExtensionProperties> extProperties)
341 {
342 vector<string> multiAuthorExtensions;
343 const char *extensionGroups[] = {"VK_KHR_", "VK_EXT_"};
344
345 for (size_t extNdx = 0; extNdx < extProperties.size(); extNdx++)
346 {
347 for (int extGroupNdx = 0; extGroupNdx < DE_LENGTH_OF_ARRAY(extensionGroups); extGroupNdx++)
348 {
349 if (deStringBeginsWith(extProperties[extNdx].extensionName, extensionGroups[extGroupNdx]))
350 multiAuthorExtensions.push_back(extProperties[extNdx].extensionName);
351 }
352 }
353
354 return multiAuthorExtensions;
355 }
356
getSupportedInstanceExtensions(const uint32_t apiVersion)357 vector<string> getSupportedInstanceExtensions(const uint32_t apiVersion)
358 {
359 vector<VkExtensionProperties> enumeratedExtensions(
360 enumerateInstanceExtensionProperties(m_context.getPlatformInterface(), nullptr));
361 vector<VkExtensionProperties> supportedExtensions;
362
363 for (size_t extNdx = 0; extNdx < enumeratedExtensions.size(); extNdx++)
364 {
365 if (!isCoreInstanceExtension(apiVersion, enumeratedExtensions[extNdx].extensionName))
366 supportedExtensions.push_back(enumeratedExtensions[extNdx]);
367 }
368
369 return filterMultiAuthorExtensions(supportedExtensions);
370 }
371
getSupportedDeviceExtensions(const uint32_t apiVersion)372 vector<string> getSupportedDeviceExtensions(const uint32_t apiVersion)
373 {
374 vector<VkExtensionProperties> enumeratedExtensions(enumerateDeviceExtensionProperties(
375 m_context.getInstanceInterface(), m_context.getPhysicalDevice(), nullptr));
376 vector<VkExtensionProperties> supportedExtensions;
377
378 for (size_t extNdx = 0; extNdx < enumeratedExtensions.size(); extNdx++)
379 {
380 if (!isCoreDeviceExtension(apiVersion, enumeratedExtensions[extNdx].extensionName))
381 supportedExtensions.push_back(enumeratedExtensions[extNdx]);
382 }
383
384 return filterMultiAuthorExtensions(supportedExtensions);
385 }
386
createTestDevice(const Context & context,VkInstance instance,vector<string> extensions=vector<string> (),bool allowLayers=true)387 Move<VkDevice> createTestDevice(const Context &context, VkInstance instance,
388 vector<string> extensions = vector<string>(), bool allowLayers = true)
389 {
390 auto &cmdLine = context.getTestContext().getCommandLine();
391 const PlatformInterface &vkp = context.getPlatformInterface();
392 const InstanceInterface &vki = context.getInstanceInterface();
393 VkPhysicalDevice physicalDevice = chooseDevice(context.getInstanceInterface(), instance, cmdLine);
394 vector<const char *> extensionPtrs;
395 const float queuePriority = 1.0f;
396 const uint32_t queueIndex = findQueueFamilyIndex(
397 vki, physicalDevice,
398 cmdLine.isComputeOnly() ? VK_QUEUE_COMPUTE_BIT : VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
399
400 for (size_t i = 0; i < extensions.size(); i++)
401 extensionPtrs.push_back(extensions[i].c_str());
402
403 VkDeviceQueueCreateInfo queueInfo = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
404 nullptr,
405 static_cast<VkDeviceQueueCreateFlags>(0u),
406 queueIndex,
407 1u,
408 &queuePriority};
409
410 void *pNext = nullptr;
411 #ifdef CTS_USES_VULKANSC
412 VkDeviceObjectReservationCreateInfo memReservationInfo =
413 context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() :
414 resetDeviceObjectReservationCreateInfo();
415 memReservationInfo.pNext = pNext;
416 pNext = &memReservationInfo;
417
418 VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
419 sc10Features.pNext = pNext;
420 pNext = &sc10Features;
421
422 VkPipelineCacheCreateInfo pcCI;
423 std::vector<VkPipelinePoolSize> poolSizes;
424 if (context.getTestContext().getCommandLine().isSubProcess())
425 {
426 if (context.getResourceInterface()->getCacheDataSize() > 0)
427 {
428 pcCI = {
429 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
430 nullptr, // const void* pNext;
431 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
432 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
433 context.getResourceInterface()->getCacheDataSize(), // uintptr_t initialDataSize;
434 context.getResourceInterface()->getCacheData() // const void* pInitialData;
435 };
436 memReservationInfo.pipelineCacheCreateInfoCount = 1;
437 memReservationInfo.pPipelineCacheCreateInfos = &pcCI;
438 }
439
440 poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
441 if (!poolSizes.empty())
442 {
443 memReservationInfo.pipelinePoolSizeCount = uint32_t(poolSizes.size());
444 memReservationInfo.pPipelinePoolSizes = poolSizes.data();
445 }
446 }
447 #endif // CTS_USES_VULKANSC
448
449 const VkDeviceCreateInfo deviceInfo = {
450 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
451 pNext,
452 static_cast<VkDeviceCreateFlags>(0u),
453 1u,
454 &queueInfo,
455 0u,
456 nullptr,
457 (uint32_t)extensions.size(),
458 extensions.size() ? &extensionPtrs[0] : nullptr,
459 nullptr,
460 };
461
462 const bool validationEnabled = (cmdLine.isValidationEnabled() && allowLayers);
463 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceInfo);
464 }
465
reportFail(tcu::TestLog & log,const char * const functionName,const char * const firstParamName,const char * const secondParamName,bool shouldBeNonNull,uint32_t & failsQuantity)466 void reportFail(tcu::TestLog &log, const char *const functionName, const char *const firstParamName,
467 const char *const secondParamName, bool shouldBeNonNull, uint32_t &failsQuantity)
468 {
469 log << tcu::TestLog::Message << "[" << failsQuantity << "] " << functionName << '(' << firstParamName << ", \""
470 << secondParamName << "\") "
471 << "returned " << (shouldBeNonNull ? "nullptr" : "non-null") << ". Should return "
472 << (shouldBeNonNull ? "valid function address." : "nullptr.") << tcu::TestLog::EndMessage;
473 ++failsQuantity;
474 }
475
checkPlatformFunction(const APIContext & ctx,tcu::TestLog & log,const char * const name,bool shouldBeNonNull,uint32_t & failsQuantity)476 void checkPlatformFunction(const APIContext &ctx, tcu::TestLog &log, const char *const name, bool shouldBeNonNull,
477 uint32_t &failsQuantity)
478 {
479 if ((ctx.getInstanceProcAddr(nullptr, name) == nullptr) == shouldBeNonNull)
480 reportFail(log, "vkGetInstanceProcAddr", "nullptr", name, shouldBeNonNull, failsQuantity);
481 }
482
checkInstanceFunction(const APIContext & ctx,tcu::TestLog & log,const char * const name,bool shouldBeNonNull,uint32_t & failsQuantity)483 void checkInstanceFunction(const APIContext &ctx, tcu::TestLog &log, const char *const name, bool shouldBeNonNull,
484 uint32_t &failsQuantity)
485 {
486 if ((ctx.getInstanceProcAddr(ctx.instance, name) == nullptr) == shouldBeNonNull)
487 reportFail(log, "vkGetInstanceProcAddr", "instance", name, shouldBeNonNull, failsQuantity);
488 }
489
checkDeviceFunction(const APIContext & ctx,tcu::TestLog & log,const char * const name,bool shouldBeNonNull,uint32_t & failsQuantity)490 void checkDeviceFunction(const APIContext &ctx, tcu::TestLog &log, const char *const name, bool shouldBeNonNull,
491 uint32_t &failsQuantity)
492 {
493 if ((ctx.getDeviceProcAddr(ctx.device, name) == nullptr) == shouldBeNonNull)
494 reportFail(log, "vkGetDeviceProcAddr", "device", name, shouldBeNonNull, failsQuantity);
495 }
496
isSupportedInstanceExt(const string extName,const uint32_t apiVersion)497 bool isSupportedInstanceExt(const string extName, const uint32_t apiVersion)
498 {
499 const vector<string> supportedInstanceExtensions(getSupportedInstanceExtensions(apiVersion));
500
501 return de::contains(supportedInstanceExtensions.begin(), supportedInstanceExtensions.end(), extName);
502 }
503
isSupportedDeviceExt(const string extName,const uint32_t apiVersion)504 bool isSupportedDeviceExt(const string extName, const uint32_t apiVersion)
505 {
506 const vector<string> supportedDeviceExtensions(getSupportedDeviceExtensions(apiVersion));
507
508 return de::contains(supportedDeviceExtensions.begin(), supportedDeviceExtensions.end(), extName);
509 }
510
mixupAddressProcCheck(const APIContext & ctx,tcu::TestLog & log,uint32_t & failsQuantity,const vector<pair<const char *,FunctionOrigin>> & testsArr)511 bool mixupAddressProcCheck(const APIContext &ctx, tcu::TestLog &log, uint32_t &failsQuantity,
512 const vector<pair<const char *, FunctionOrigin>> &testsArr)
513 {
514 const uint32_t startingQuantity = failsQuantity;
515 for (uint32_t ndx = 0u; ndx < testsArr.size(); ++ndx)
516 {
517 if (strcmp(testsArr[ndx].first, "vkGetInstanceProcAddr") == 0 ||
518 strcmp(testsArr[ndx].first, "vkEnumerateInstanceVersion") == 0)
519 continue;
520
521 const char *functionName = testsArr[ndx].first;
522 const uint32_t functionType = testsArr[ndx].second;
523 if (functionType == FUNCTIONORIGIN_INSTANCE)
524 {
525 checkPlatformFunction(ctx, log, functionName, false, failsQuantity);
526 checkDeviceFunction(ctx, log, functionName, false, failsQuantity);
527 }
528 else if (functionType == FUNCTIONORIGIN_DEVICE)
529 checkPlatformFunction(ctx, log, functionName, false, failsQuantity);
530 }
531 return startingQuantity == failsQuantity;
532 }
533
specialCasesCheck(const APIContext & ctx,tcu::TestLog & log,uint32_t & failsQuantity,const vector<pair<const char *,FunctionOrigin>> & testsArr)534 bool specialCasesCheck(const APIContext &ctx, tcu::TestLog &log, uint32_t &failsQuantity,
535 const vector<pair<const char *, FunctionOrigin>> &testsArr)
536 {
537 const uint32_t startingQuantity = failsQuantity;
538 for (uint32_t ndx = 0u; ndx < testsArr.size(); ++ndx)
539 {
540 const uint32_t functionType = testsArr[ndx].second;
541 if (functionType == FUNCTIONORIGIN_PLATFORM)
542 checkPlatformFunction(ctx, log, testsArr[ndx].first, false, failsQuantity);
543 else if (functionType == FUNCTIONORIGIN_INSTANCE)
544 checkInstanceFunction(ctx, log, testsArr[ndx].first, false, failsQuantity);
545 else if (functionType == FUNCTIONORIGIN_DEVICE)
546 checkDeviceFunction(ctx, log, testsArr[ndx].first, false, failsQuantity);
547 }
548 return startingQuantity == failsQuantity;
549 }
550
regularCheck(const APIContext & ctx,tcu::TestLog & log,uint32_t & failsQuantity,const vector<pair<const char *,FunctionOrigin>> & testsArr)551 bool regularCheck(const APIContext &ctx, tcu::TestLog &log, uint32_t &failsQuantity,
552 const vector<pair<const char *, FunctionOrigin>> &testsArr)
553 {
554 const uint32_t startingQuantity = failsQuantity;
555
556 for (uint32_t ndx = 0u; ndx < testsArr.size(); ++ndx)
557 {
558 const auto &funcName = testsArr[ndx].first;
559 const auto &funcType = testsArr[ndx].second;
560 const auto apiVersion = m_context.getUsedApiVersion();
561
562 if (strcmp(funcName, "vkGetInstanceProcAddr") == 0 && apiVersion < VK_API_VERSION_1_2)
563 continue;
564
565 // VK_KHR_draw_indirect_count was promoted to core in Vulkan 1.2, but these entrypoints are not mandatory unless the
566 // device supports the extension. In that case, the drawIndirectCount feature bit will also be true. Any of the two
567 // checks is valid. We use the extension name for convenience here.
568 if ((strcmp(funcName, "vkCmdDrawIndirectCount") == 0 ||
569 strcmp(funcName, "vkCmdDrawIndexedIndirectCount") == 0) &&
570 !isSupportedDeviceExt("VK_KHR_draw_indirect_count", apiVersion))
571 continue;
572
573 // vkCmdPushDescriptorSetWithTemplateKHR is available if:
574 // - VK_KHR_push_descriptor is supported AND
575 // - API >= VK_VERSION_1_1 OR
576 // - VK_KHR_descriptor_update_template is supported
577 if (strcmp(funcName, "vkCmdPushDescriptorSetWithTemplateKHR") == 0 &&
578 (!isSupportedDeviceExt("VK_KHR_push_descriptor", apiVersion) ||
579 (apiVersion < VK_API_VERSION_1_1 &&
580 !isSupportedDeviceExt("VK_KHR_descriptor_update_template", apiVersion))))
581 continue;
582
583 if (funcType == FUNCTIONORIGIN_PLATFORM)
584 {
585 checkPlatformFunction(ctx, log, funcName, true, failsQuantity);
586 }
587 else if (funcType == FUNCTIONORIGIN_INSTANCE)
588 {
589 checkInstanceFunction(ctx, log, funcName, true, failsQuantity);
590 checkDeviceFunction(ctx, log, funcName, false, failsQuantity);
591 }
592 else if (funcType == FUNCTIONORIGIN_DEVICE)
593 {
594 checkInstanceFunction(ctx, log, funcName, true, failsQuantity);
595 checkDeviceFunction(ctx, log, funcName, true, failsQuantity);
596 }
597 }
598
599 return startingQuantity == failsQuantity;
600 }
601 };
602
603 class APIEntryPointsTestCase : public TestCase
604 {
605 public:
APIEntryPointsTestCase(tcu::TestContext & testCtx)606 APIEntryPointsTestCase(tcu::TestContext &testCtx) : TestCase(testCtx, "entry_points")
607 {
608 }
609
~APIEntryPointsTestCase(void)610 virtual ~APIEntryPointsTestCase(void)
611 {
612 }
createInstance(Context & ctx) const613 virtual TestInstance *createInstance(Context &ctx) const
614 {
615 return new APIEntryPointsTestInstance(ctx);
616 }
617
618 private:
619 };
620
621 class APIUnavailableEntryPointsTestInstance : public TestInstance
622 {
623 public:
APIUnavailableEntryPointsTestInstance(Context & ctx)624 APIUnavailableEntryPointsTestInstance(Context &ctx) : TestInstance(ctx)
625 {
626 }
627
iterate(void)628 virtual tcu::TestStatus iterate(void)
629 {
630 const vk::PlatformInterface &vkp = m_context.getPlatformInterface();
631 tcu::TestLog &log = m_context.getTestContext().getLog();
632 const auto supportedApiVersion = m_context.getUsedApiVersion();
633 bool testPassed = true;
634
635 ApisMap functionsPerVersion;
636 initApisMap(functionsPerVersion);
637
638 // create custom instance for each api version
639 for (const auto &testedApiVersion : functionsPerVersion)
640 {
641 // VK_KHR_maintenance5 requires at least Vulkan 1.1
642 if (testedApiVersion.first == VK_API_VERSION_1_0)
643 continue;
644
645 // we cant test api versions that are higher then api version support by this device
646 if (testedApiVersion.first > supportedApiVersion)
647 break;
648
649 // there is no api version above the last api version
650 if (testedApiVersion.first == functionsPerVersion.rbegin()->first)
651 break;
652
653 VkApplicationInfo appInfo = initVulkanStructure();
654 appInfo.pApplicationName = "a";
655 appInfo.pEngineName = "b";
656 appInfo.apiVersion = testedApiVersion.first;
657 VkInstanceCreateInfo instanceCreateInfo = initVulkanStructure();
658 instanceCreateInfo.pApplicationInfo = &appInfo;
659
660 #ifndef CTS_USES_VULKANSC
661 char const *requiredExtensionForVk10 = "VK_KHR_get_physical_device_properties2";
662 if (appInfo.apiVersion == VK_API_VERSION_1_0)
663 {
664 instanceCreateInfo.enabledExtensionCount = 1U;
665 instanceCreateInfo.ppEnabledExtensionNames = &requiredExtensionForVk10;
666 }
667 #endif // CTS_USES_VULKANSC
668
669 // create instance for currentluy tested vulkan version
670 Move<VkInstance> customInstance(vk::createInstance(vkp, &instanceCreateInfo, nullptr));
671 std::unique_ptr<vk::InstanceDriver> instanceDriver(new InstanceDriver(vkp, *customInstance));
672 const VkPhysicalDevice physicalDevice =
673 chooseDevice(*instanceDriver, *customInstance, m_context.getTestContext().getCommandLine());
674 const auto queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(*instanceDriver, physicalDevice);
675
676 const float queuePriority = 1.0f;
677 VkDeviceQueueCreateInfo deviceQueueCreateInfo = initVulkanStructure();
678 deviceQueueCreateInfo.queueCount = 1;
679 deviceQueueCreateInfo.pQueuePriorities = &queuePriority;
680
681 VkDeviceCreateInfo deviceCreateInfo = initVulkanStructure();
682 deviceCreateInfo.queueCreateInfoCount = 1u;
683 deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
684
685 #ifndef CTS_USES_VULKANSC
686 std::vector<const char *> extensions = {"VK_KHR_maintenance5", "VK_KHR_dynamic_rendering"};
687 if (testedApiVersion.first < VK_API_VERSION_1_2)
688 {
689 extensions.push_back("VK_KHR_depth_stencil_resolve");
690 extensions.push_back("VK_KHR_create_renderpass2");
691 }
692 deviceCreateInfo.enabledExtensionCount = (uint32_t)extensions.size();
693 deviceCreateInfo.ppEnabledExtensionNames = extensions.data();
694
695 vk::VkPhysicalDeviceMaintenance5FeaturesKHR maint5 = initVulkanStructure();
696 vk::VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&maint5);
697 instanceDriver->getPhysicalDeviceFeatures2(physicalDevice, &features2);
698 deviceCreateInfo.pNext = &features2;
699 #endif // CTS_USES_VULKANSC
700
701 // create custom device
702 const Unique<VkDevice> device(
703 createCustomDevice(false, vkp, *customInstance, *instanceDriver, physicalDevice, &deviceCreateInfo));
704 const DeviceDriver deviceDriver(vkp, *customInstance, *device, supportedApiVersion,
705 m_context.getTestContext().getCommandLine());
706
707 log << tcu::TestLog::Message << "Checking apiVersion(" << VK_API_VERSION_MAJOR(testedApiVersion.first)
708 << ", " << VK_API_VERSION_MINOR(testedApiVersion.first) << ")" << tcu::TestLog::EndMessage;
709
710 // iterate over api versions that are above tested api version
711 auto &previousVersionFunctions = functionsPerVersion[VK_API_VERSION_1_0];
712 for (const auto &versionFunctions : functionsPerVersion)
713 {
714 // skip api versions that are not above tested api version
715 if (versionFunctions.first <= testedApiVersion.first)
716 {
717 previousVersionFunctions = versionFunctions.second;
718 continue;
719 }
720
721 // iterate over all functions
722 for (const auto &function : versionFunctions.second)
723 {
724 // we are interested only in device functions
725 if (function.second != FUNCTIONORIGIN_DEVICE)
726 continue;
727
728 // skip functions that are present in previous version;
729 // functionsPerVersion contains all functions that are
730 // available in vulkan version, not only ones that were added
731 const auto &funcName = function.first;
732 const auto isMatch = [&funcName](const FunctionInfo &fi) { return !strcmp(funcName, fi.first); };
733 auto matchIt =
734 std::find_if(begin(previousVersionFunctions), end(previousVersionFunctions), isMatch);
735 if (matchIt != previousVersionFunctions.end())
736 continue;
737
738 // check if returned function pointer is NULL
739 if (deviceDriver.getDeviceProcAddr(*device, funcName) != nullptr)
740 {
741 log << tcu::TestLog::Message << "getDeviceProcAddr(" << funcName
742 << ") returned non-null pointer, expected NULL" << tcu::TestLog::EndMessage;
743 testPassed = false;
744 }
745 }
746
747 previousVersionFunctions = versionFunctions.second;
748 }
749 }
750
751 if (testPassed)
752 return tcu::TestStatus::pass("Pass");
753 return tcu::TestStatus::fail("Fail");
754 }
755 };
756
757 class APIUnavailableEntryPointsTestCase : public TestCase
758 {
759 public:
760 // Check if vkGetDeviceProcAddr returns NULL for functions beyond app version.
APIUnavailableEntryPointsTestCase(tcu::TestContext & testCtx)761 APIUnavailableEntryPointsTestCase(tcu::TestContext &testCtx) : TestCase(testCtx, "unavailable_entry_points")
762 {
763 }
764
checkSupport(Context & context) const765 virtual void checkSupport(Context &context) const
766 {
767 context.requireDeviceFunctionality("VK_KHR_maintenance5");
768 }
769
createInstance(Context & ctx) const770 virtual TestInstance *createInstance(Context &ctx) const
771 {
772 return new APIUnavailableEntryPointsTestInstance(ctx);
773 }
774 };
775
776 } // namespace
777
createVersionSanityCheckTests(tcu::TestContext & testCtx)778 tcu::TestCaseGroup *createVersionSanityCheckTests(tcu::TestContext &testCtx)
779 {
780 de::MovePtr<tcu::TestCaseGroup> versionTests(new tcu::TestCaseGroup(testCtx, "version_check"));
781 versionTests->addChild(new APIVersionTestCase(testCtx));
782 versionTests->addChild(new APIEntryPointsTestCase(testCtx));
783
784 #ifndef CTS_USES_VULKANSC
785 versionTests->addChild(new APIUnavailableEntryPointsTestCase(testCtx));
786 #endif
787
788 return versionTests.release();
789 }
790
791 } // namespace api
792
793 } // namespace vkt
794