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 55using namespace vk; 56using namespace std; 57 58namespace vkt 59{ 60 61namespace api 62{ 63 64namespace 65{ 66 67#include "vkExtensionFunctions.inl" 68#include "vkCoreFunctionalities.inl" 69 70class APIVersionTestInstance : public TestInstance 71{ 72public: 73 APIVersionTestInstance (Context& ctx) 74 : TestInstance (ctx) 75 {} 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 98class APIVersionTestCase : public TestCase 99{ 100public: 101 APIVersionTestCase (tcu::TestContext& testCtx) 102 : TestCase (testCtx, "version") 103 {} 104 105 virtual ~APIVersionTestCase (void) 106 {} 107 virtual TestInstance* createInstance (Context& ctx) const 108 { 109 return new APIVersionTestInstance(ctx); 110 } 111 112private: 113}; 114 115class APIEntryPointsTestInstance : public TestInstance 116{ 117public: 118 struct APIContext 119 { 120 VkInstance instance; 121 VkDevice device; 122 GetInstanceProcAddrFunc getInstanceProcAddr; 123 GetDeviceProcAddrFunc getDeviceProcAddr; 124 }; 125 126 APIEntryPointsTestInstance (Context& ctx) 127 : TestInstance (ctx) 128 { 129 } 130 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 268private: 269 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 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 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 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 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 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 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 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 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 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 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 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 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 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 541class APIEntryPointsTestCase : public TestCase 542{ 543public: 544 APIEntryPointsTestCase (tcu::TestContext& testCtx) 545 : TestCase (testCtx, "entry_points") 546 {} 547 548 virtual ~APIEntryPointsTestCase (void) 549 {} 550 virtual TestInstance* createInstance (Context& ctx) const 551 { 552 return new APIEntryPointsTestInstance(ctx); 553 } 554 555private: 556}; 557 558class APIUnavailableEntryPointsTestInstance : public TestInstance 559{ 560public: 561 APIUnavailableEntryPointsTestInstance(Context& ctx): TestInstance(ctx) 562 {} 563 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 681class APIUnavailableEntryPointsTestCase : public TestCase 682{ 683public: 684 // Check if vkGetDeviceProcAddr returns NULL for functions beyond app version. 685 APIUnavailableEntryPointsTestCase(tcu::TestContext& testCtx) 686 : TestCase(testCtx, "unavailable_entry_points") 687 {} 688 689 virtual void checkSupport(Context& context) const 690 { 691 context.requireDeviceFunctionality("VK_KHR_maintenance5"); 692 } 693 694 virtual TestInstance* createInstance(Context& ctx) const 695 { 696 return new APIUnavailableEntryPointsTestInstance(ctx); 697 } 698}; 699 700} // anonymous 701 702tcu::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