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