• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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