xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/api/vktApiExtensionDuplicatesTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \brief Extension duplicates tests
21  *//*--------------------------------------------------------------------*/
22 
23 #include "vktTestCase.hpp"
24 #include "vktTestCaseUtil.hpp"
25 #include "vktTestGroupUtil.hpp"
26 #include "vktCustomInstancesDevices.hpp"
27 #include "vkPlatform.hpp"
28 #include "vkCmdUtil.hpp"
29 #include "tcuCommandLine.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vktApiExtensionDuplicatesTests.hpp"
35 #include "vkSafetyCriticalUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 
38 #include <set>
39 #include <sstream>
40 #include <string>
41 #include <type_traits>
42 #include <vector>
43 #include <iostream>
44 
45 namespace vkt
46 {
47 namespace api
48 {
49 namespace
50 {
51 using namespace vk;
52 
53 namespace ut
54 {
distinct(const std::vector<const char * > & src)55 std::set<const char *> distinct(const std::vector<const char *> &src)
56 {
57     std::set<const char *> result;
58     for (const char *const p : src)
59     {
60         result.insert(p);
61     }
62     return result;
63 }
64 
65 struct StringDuplicator
66 {
StringDuplicatorvkt::api::__anonebe1f38b0111::ut::StringDuplicator67     StringDuplicator(const std::vector<const char *> &src) : m_source(distinct(src)), m_strings()
68     {
69     }
70     auto duplicatePointers() -> std::vector<const char *>;
71     // NOTE: Use carefully, realtime counterparts for returned pointers are held in m_strings
72     auto duplicateStrings() -> std::vector<const char *>;
getInputCountvkt::api::__anonebe1f38b0111::ut::StringDuplicator73     auto getInputCount() const -> typename std::vector<const char *>::size_type
74     {
75         return m_source.size();
76     }
77 
78 private:
79     const std::set<const char *> m_source;
80     std::vector<std::string> m_strings;
81 };
82 
duplicatePointers()83 std::vector<const char *> StringDuplicator::duplicatePointers()
84 {
85     uint32_t i{};
86     std::vector<const char *> r{};
87 
88     for (const char *const p : m_source)
89     {
90         if ((i % 2) == 0)
91         {
92             r.push_back(p);
93             r.push_back(p);
94         }
95         else if ((i % 3) == 0)
96         {
97             r.push_back(p);
98             r.push_back(p);
99             r.push_back(p);
100         }
101         else
102         {
103             r.push_back(p);
104             r.push_back(p);
105             r.push_back(p);
106             r.push_back(p);
107         }
108 
109         i = i + 1u;
110     }
111 
112     return r;
113 }
duplicateStrings()114 std::vector<const char *> StringDuplicator::duplicateStrings()
115 {
116     uint32_t i{};
117     std::vector<const char *> r{};
118 
119     m_strings.clear();
120 
121     for (const char *p : m_source)
122     {
123         if ((i % 2) == 0)
124         {
125             m_strings.push_back(std::string(p));
126             m_strings.push_back(std::string(p));
127         }
128         else if ((i % 3) == 0)
129         {
130             m_strings.push_back(std::string(p));
131             m_strings.push_back(std::string(p));
132             m_strings.push_back(std::string(p));
133         }
134         else
135         {
136             m_strings.push_back(std::string(p));
137             m_strings.push_back(std::string(p));
138             m_strings.push_back(std::string(p));
139             m_strings.push_back(std::string(p));
140         }
141 
142         i = i + 1u;
143     }
144 
145     for (std::string &s : m_strings)
146     {
147         r.push_back(s.c_str());
148     }
149 
150     return r;
151 }
152 } // namespace ut
153 
154 class InstanceExtensionDuplicatesInstance : public TestInstance
155 {
156 public:
InstanceExtensionDuplicatesInstance(Context & ctx,bool byPointersOrNames)157     InstanceExtensionDuplicatesInstance(Context &ctx, bool byPointersOrNames)
158         : TestInstance(ctx)
159         , m_byPointersOrNames(byPointersOrNames)
160     {
161     }
162     virtual tcu::TestStatus iterate(void) override;
163 
164 private:
165     const bool m_byPointersOrNames;
166 };
167 
168 class DeviceExtensionDuplicatesInstance : public TestInstance
169 {
170 public:
DeviceExtensionDuplicatesInstance(Context & ctx,bool byPointersOrNames)171     DeviceExtensionDuplicatesInstance(Context &ctx, bool byPointersOrNames)
172         : TestInstance(ctx)
173         , m_byPointersOrNames(byPointersOrNames)
174     {
175     }
176     virtual tcu::TestStatus iterate(void) override;
177 
178 private:
179     const bool m_byPointersOrNames;
180 };
181 
182 class ExtensionDuplicatesCase : public TestCase
183 {
184 public:
ExtensionDuplicatesCase(tcu::TestContext & testCtx,const std::string & name,bool instanceOrDevice,bool byPointersOrNames)185     ExtensionDuplicatesCase(tcu::TestContext &testCtx, const std::string &name, bool instanceOrDevice,
186                             bool byPointersOrNames)
187         : TestCase(testCtx, name)
188         , m_instanceOrDevice(instanceOrDevice)
189         , m_byPointersOrNames(byPointersOrNames)
190     {
191     }
createInstance(Context & ctx) const192     virtual TestInstance *createInstance(Context &ctx) const override
193     {
194         if (m_instanceOrDevice)
195             return new InstanceExtensionDuplicatesInstance(ctx, m_byPointersOrNames);
196         return new DeviceExtensionDuplicatesInstance(ctx, m_byPointersOrNames);
197     }
198 
199 private:
200     const bool m_instanceOrDevice;
201     const bool m_byPointersOrNames;
202 };
203 
iterate(void)204 tcu::TestStatus InstanceExtensionDuplicatesInstance::iterate(void)
205 {
206     const vk::PlatformInterface &vkp                             = m_context.getPlatformInterface();
207     const tcu::CommandLine &cmd                                  = m_context.getTestContext().getCommandLine();
208     const std::vector<VkExtensionProperties> availableExtensions = enumerateInstanceExtensionProperties(vkp, nullptr);
209 
210     if (0u == availableExtensions.size())
211     {
212         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
213                                "Unable to perform test due to empty instance extension list");
214     }
215 
216     std::vector<std::string> availableExtensionNames(availableExtensions.size());
217     std::vector<const char *> enabledExtensions(availableExtensions.size());
218 
219     std::transform(availableExtensions.begin(), availableExtensions.end(), availableExtensionNames.begin(),
220                    [](const VkExtensionProperties &props) { return std::string(props.extensionName); });
221     std::transform(availableExtensionNames.begin(), availableExtensionNames.end(), enabledExtensions.begin(),
222                    [](const std::string &ext) { return ext.c_str(); });
223 
224     ut::StringDuplicator duplicator(enabledExtensions);
225     const std::vector<const char *> duplicatedExtensions =
226         m_byPointersOrNames ? duplicator.duplicatePointers() : duplicator.duplicateStrings();
227     const uint32_t duplicatedExtensionCnt = static_cast<uint32_t>(duplicatedExtensions.size());
228 
229     const VkApplicationInfo applicationInfo{
230         VK_STRUCTURE_TYPE_APPLICATION_INFO,     // VkStructureType sType;
231         nullptr,                                // const void* pNext;
232         "extension_duplicates_instance",        // const char* pApplicationName;
233         VK_API_VERSION_1_0,                     // uint32_t applicationVersion;
234         "extension_duplicates_instance_engine", // const char* pEngineName;
235         VK_API_VERSION_1_0,                     // uint32_t engineVersion;
236         m_context.getUsedApiVersion()           // uint32_t apiVersion;
237     };
238 
239     const VkInstanceCreateInfo instanceCreateInfo{
240         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType;
241         nullptr,                                // const void* pNext;
242         VkInstanceCreateFlags(0),               // VkInstanceCreateFlags flags;
243         &applicationInfo,                       // const VkApplicationInfo* pApplicationInfo;
244         0u,                                     // uint32_t enabledLayerCount;
245         nullptr,                                // const char* const* ppEnabledLayerNames;
246         duplicatedExtensionCnt,                 // uint32_t enabledExtensionCount;
247         duplicatedExtensions.data()             // const char* const* ppEnabledExtensionNames;
248     };
249 
250     UncheckedInstance uncheckedInstance;
251     const VkResult res =
252         createUncheckedInstance(m_context, &instanceCreateInfo, nullptr, &uncheckedInstance, cmd.isValidationEnabled());
253 
254     auto failMessage = [&]() -> std::string
255     {
256         std::ostringstream os;
257         os << "vkCreateInstance returned " << getResultName(res);
258         os.flush();
259         return os.str();
260     };
261 
262     auto passMessage = [&]() -> std::string
263     {
264         std::ostringstream os;
265         os << "Created " << duplicatedExtensionCnt << " duplicates of " << duplicator.getInputCount() << " extensions";
266         os.flush();
267         return os.str();
268     };
269 
270     return (VK_SUCCESS == res) ? tcu::TestStatus::pass(passMessage()) : tcu::TestStatus::fail(failMessage());
271 }
272 
iterate(void)273 tcu::TestStatus DeviceExtensionDuplicatesInstance::iterate(void)
274 {
275 #ifdef CTS_USES_VULKANSC
276     CustomInstance customInstance    = createCustomInstanceFromContext(m_context);
277     const vk::InstanceInterface &vki = customInstance.getDriver();
278     const VkPhysicalDevice phd       = chooseDevice(vki, customInstance, m_context.getTestContext().getCommandLine());
279 #else
280     const vk::InstanceInterface &vki = m_context.getInstanceInterface();
281     const VkPhysicalDevice phd       = m_context.getPhysicalDevice();
282 #endif // CTS_USES_VULKANSC
283     const DeviceInterface &vkd  = m_context.getDeviceInterface();
284     const uint32_t idx          = m_context.getUniversalQueueFamilyIndex();
285     const tcu::CommandLine &cmd = m_context.getTestContext().getCommandLine();
286     const float qpr             = 1.0f;
287     ut::StringDuplicator sd(m_context.getDeviceCreationExtensions());
288 
289     const std::vector<const char *> dup = m_byPointersOrNames ? sd.duplicatePointers() : sd.duplicateStrings();
290     const uint32_t cnt                  = static_cast<uint32_t>(dup.size());
291     if (0u == cnt)
292     {
293         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
294                                "Unable to perform test due to empty device extension list");
295     }
296 
297     const VkDeviceQueueCreateInfo queueCreateInfo{
298         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
299         nullptr,                                    // const void* pNext;
300         VkDeviceQueueCreateFlags(0),                // VkDeviceQueueCreateFlags flags;
301         idx,                                        // uint32_t queueFamilyIndex;
302         1u,                                         // uint32_t queueCount;
303         &qpr                                        // const float* pQueuePriorities;
304     };
305 
306     void *pNext = DE_NULL;
307 #ifdef CTS_USES_VULKANSC
308     VkDeviceObjectReservationCreateInfo memReservationInfo =
309         m_context.getTestContext().getCommandLine().isSubProcess() ? m_context.getResourceInterface()->getStatMax() :
310                                                                      resetDeviceObjectReservationCreateInfo();
311     memReservationInfo.pNext = pNext;
312     pNext                    = &memReservationInfo;
313 
314     VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
315     sc10Features.pNext                              = pNext;
316     pNext                                           = &sc10Features;
317 #endif // CTS_USES_VULKANSC
318 
319     const VkDeviceCreateInfo deviceCreateInfo{
320         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
321         pNext,                                // const void* pNext;
322         VkDeviceCreateFlags(0),               // VkDeviceCreateFlags flags;
323         1u,                                   // uint32_t queueCreateInfoCount;
324         &queueCreateInfo,                     // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
325         0u,                                   // uint32_t enabledLayerCount;
326         nullptr,                              // const char* const* ppEnabledLayerNames;
327         cnt,                                  // uint32_t enabledExtensionCount;
328         dup.data(),                           // const char* const* ppEnabledExtensionNames;
329         nullptr                               // const VkPhysicalDeviceFeatures* pEnabledFeatures;
330 
331     };
332 
333     VkDevice device = VK_NULL_HANDLE;
334     const VkResult res =
335         createUncheckedDevice(cmd.isValidationEnabled(), vki, phd, &deviceCreateInfo, nullptr, &device);
336     if (VK_SUCCESS == res && VK_NULL_HANDLE != device)
337     {
338         vkd.destroyDevice(device, nullptr);
339     }
340 
341     auto failMessage = [&]() -> std::string
342     {
343         std::ostringstream os;
344         os << "vkCreateDevice returned " << getResultName(res);
345         os.flush();
346         return os.str();
347     };
348 
349     auto passMessage = [&]() -> std::string
350     {
351         std::ostringstream os;
352         os << "Created " << cnt << " duplicates of " << sd.getInputCount() << " extensions";
353         os.flush();
354         return os.str();
355     };
356 
357     return (VK_SUCCESS == res) ? tcu::TestStatus::pass(passMessage()) : tcu::TestStatus::fail(failMessage());
358 }
359 
360 } // unnamed namespace
361 
createExtensionDuplicatesTests(tcu::TestContext & testCtx)362 tcu::TestCaseGroup *createExtensionDuplicatesTests(tcu::TestContext &testCtx)
363 {
364     typedef std::pair<const char *, bool> item_t;
365     item_t const types[]{{"instance", true}, {"device", false}};
366 
367     item_t const methods[]{{"by_pointers", true}, {"by_names", false}};
368 
369     // Verifies that we can create a device or an instance with duplicate extensions
370     de::MovePtr<tcu::TestCaseGroup> rootGroup(new tcu::TestCaseGroup(testCtx, "extension_duplicates"));
371     for (const item_t &type : types)
372     {
373         de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, type.first));
374         for (const item_t &meth : methods)
375         {
376             typeGroup->addChild(new ExtensionDuplicatesCase(testCtx, meth.first, type.second, meth.second));
377         }
378         rootGroup->addChild(typeGroup.release());
379     }
380 
381     return rootGroup.release();
382 }
383 
384 } // namespace api
385 } // namespace vkt
386