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