xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/api/vktApiMaintenance3Check.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Khronos Group
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 * \file
21 * \brief API Maintenance3 Check test - checks structs and function from VK_KHR_maintenance3
22 *//*--------------------------------------------------------------------*/
23 
24 #include "tcuTestLog.hpp"
25 
26 #include "vkQueryUtil.hpp"
27 
28 #include "vktApiMaintenance3Check.hpp"
29 #include "vktTestCase.hpp"
30 #include "vktTestCaseUtil.hpp"
31 
32 #include <sstream>
33 #include <limits>
34 #include <utility>
35 #include <algorithm>
36 #include <map>
37 #include <set>
38 
39 using namespace vk;
40 
41 namespace vkt
42 {
43 
44 namespace api
45 {
46 
47 namespace
48 {
49 using ::std::make_pair;
50 using ::std::map;
51 using ::std::ostringstream;
52 using ::std::set;
53 using ::std::string;
54 using ::std::vector;
55 
56 typedef vk::VkPhysicalDeviceProperties DevProp1;
57 typedef vk::VkPhysicalDeviceProperties2 DevProp2;
58 typedef vk::VkPhysicalDeviceMaintenance3Properties MaintDevProp3;
59 typedef vk::VkPhysicalDeviceFeatures2 DevFeat2;
60 #ifndef CTS_USES_VULKANSC
61 typedef vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT DevIubFeat;
62 typedef vk::VkPhysicalDeviceInlineUniformBlockPropertiesEXT DevIubProp;
63 #endif // CTS_USES_VULKANSC
64 
65 // These variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
66 constexpr uint32_t maxMemoryAllocationSize = 1073741824u;
67 constexpr uint32_t maxDescriptorsInSet     = 1024u;
68 #ifndef CTS_USES_VULKANSC
69 constexpr uint32_t maxReasonableInlineUniformBlocks = 64u;
70 #else
71 constexpr uint32_t maxReasonableBindingCounts = 1024u;
72 #endif // CTS_USES_VULKANSC
73 using TypeSet = set<vk::VkDescriptorType>;
74 
75 // Structure representing an implementation limit, like maxPerStageDescriptorSamplers. It has a maximum value
76 // obtained at runtime and a remaining number of descriptors, which starts with the same count and decreases
77 // as we assign descriptor counts to the different types. A limit is affected by (or itself affects) one or more
78 // descriptor types. Note a type may be involved in several limits, and a limit may affect several types.
79 struct Limit
80 {
Limitvkt::api::__anon278a8ca10111::Limit81     Limit(const string &name_, uint32_t maxValue_, const TypeSet &affectedTypes_)
82         : name(name_)
83         , maxValue(maxValue_)
84         , remaining(maxValue_)
85         , affectedTypes(affectedTypes_)
86     {
87     }
88 
89     const string name;
90     const uint32_t maxValue;
91     uint32_t remaining;
92     const TypeSet affectedTypes;
93 };
94 
95 // Structure representing how many descriptors have been assigned to the given type. The type is "alive" during
96 // descriptor count assignment if more descriptors can be added to the type without hitting any limit affected
97 // by the type. Once at least one of the limits is reached, no more descriptors can be assigned to the type and
98 // the type is no longer considered "alive".
99 struct TypeState
100 {
TypeStatevkt::api::__anon278a8ca10111::TypeState101     TypeState(vk::VkDescriptorType type_) : type(type_), alive(true), count(0u)
102     {
103     }
104 
105     const vk::VkDescriptorType type;
106     bool alive;
107     uint32_t count;
108 };
109 
110 using TypeCounts   = map<vk::VkDescriptorType, TypeState>;
111 using LimitsVector = vector<Limit>;
112 
113 // Get the subset of alive types from the given map.
getAliveTypes(const TypeCounts & typeCounts)114 TypeSet getAliveTypes(const TypeCounts &typeCounts)
115 {
116     TypeSet aliveTypes;
117     for (const auto &typeCount : typeCounts)
118     {
119         if (typeCount.second.alive)
120             aliveTypes.insert(typeCount.first);
121     }
122     return aliveTypes;
123 }
124 
125 // Get the subset of alive types for a specific limit, among the set of types affected by the limit.
getAliveTypesForLimit(const Limit & limit,const TypeSet & aliveTypes)126 TypeSet getAliveTypesForLimit(const Limit &limit, const TypeSet &aliveTypes)
127 {
128     TypeSet subset;
129     for (const auto &type : limit.affectedTypes)
130     {
131         if (aliveTypes.find(type) != aliveTypes.end())
132             subset.insert(type);
133     }
134     return subset;
135 }
136 
137 // Distribute descriptor counts as evenly as possible among the given set of types, taking into account the
138 // given limits.
distributeCounts(LimitsVector & limits,TypeCounts & typeCounts)139 void distributeCounts(LimitsVector &limits, TypeCounts &typeCounts)
140 {
141     using IncrementsMap = map<vk::VkDescriptorType, uint32_t>;
142     TypeSet aliveTypes;
143 
144     while ((aliveTypes = getAliveTypes(typeCounts)).size() > 0u)
145     {
146         // Calculate the maximum increment per alive descriptor type. This involves iterating over the limits and
147         // finding out how many more descriptors can be distributed among the affected types that are still alive
148         // for the limit. For each type, remember the lowest possible increment.
149         IncrementsMap increments;
150         for (const auto &type : aliveTypes)
151             increments[type] = std::numeric_limits<uint32_t>::max();
152 
153         TypeSet aliveTypesForLimit;
154 
155         for (const auto &limit : limits)
156         {
157             if (limit.remaining == 0u)
158                 continue;
159 
160             aliveTypesForLimit = getAliveTypesForLimit(limit, aliveTypes);
161             if (aliveTypesForLimit.empty())
162                 continue;
163 
164             // Distribute remaining count evenly among alive types.
165             uint32_t maxIncrement = limit.remaining / static_cast<uint32_t>(aliveTypesForLimit.size());
166             if (maxIncrement == 0u)
167             {
168                 // More types than remaining descriptors. Assign 1 to the first affected types and 0 to the rest.
169                 uint32_t remaining = limit.remaining;
170                 for (const auto &type : aliveTypesForLimit)
171                 {
172                     if (remaining > 0u && increments[type] > 0u)
173                     {
174                         increments[type] = 1u;
175                         --remaining;
176                     }
177                     else
178                     {
179                         increments[type] = 0u;
180                     }
181                 }
182             }
183             else
184             {
185                 // Find the lowest possible increment taking into account all limits.
186                 for (const auto &type : aliveTypesForLimit)
187                 {
188                     if (increments[type] > maxIncrement)
189                         increments[type] = maxIncrement;
190                 }
191             }
192         }
193 
194         // Apply the calculated increments per descriptor type, decreasing the remaining descriptors for each
195         // limit affected by the type, and switching types to the not-alive state when a limit is hit.
196         for (const auto &inc : increments)
197         {
198             const vk::VkDescriptorType &type = inc.first;
199             const uint32_t &increment        = inc.second;
200 
201             // Increase type count.
202             auto iter = typeCounts.find(type);
203             DE_ASSERT(iter != typeCounts.end());
204             iter->second.count += increment;
205 
206             for (auto &limit : limits)
207             {
208                 // Decrease remaining descriptors for affected limits.
209                 if (limit.affectedTypes.find(type) != limit.affectedTypes.end())
210                 {
211                     DE_ASSERT(increment <= limit.remaining);
212                     limit.remaining -= increment;
213                 }
214                 if (limit.remaining == 0u)
215                 {
216                     // Limit hit, switch affected types to not-alive.
217                     for (const auto &affectedType : limit.affectedTypes)
218                     {
219                         auto tc = typeCounts.find(affectedType);
220                         if (tc != typeCounts.end())
221                             tc->second.alive = false;
222                     }
223                 }
224             }
225         }
226     }
227 }
228 
229 // Create a limits vector based on runtime limit information for the device.
buildLimitsVector(const DevProp1 & prop1,const DevIubProp & iubProp,const MaintDevProp3 & maintProp3)230 LimitsVector buildLimitsVector(const DevProp1 &prop1,
231 #ifndef CTS_USES_VULKANSC
232                                const DevIubProp &iubProp,
233 #endif // CTS_USES_VULKANSC
234                                const MaintDevProp3 &maintProp3)
235 {
236     static const TypeSet samplerTypes = {vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLER};
237     static const TypeSet sampledImageTypes    = {vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
238                                                  vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
239                                                  vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER};
240     static const TypeSet uniformBufferTypes   = {vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
241                                                  vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC};
242     static const TypeSet storageBufferTypes   = {vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
243                                                  vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC};
244     static const TypeSet storageImageTypes    = {vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
245                                                  vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER};
246     static const TypeSet inputAttachmentTypes = {vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT};
247 #ifndef CTS_USES_VULKANSC
248     static const TypeSet inlineUniformBlockTypes = {vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT};
249 #endif // CTS_USES_VULKANSC
250     static const TypeSet dynamicUniformBuffer = {vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC};
251     static const TypeSet dynamicStorageBuffer = {vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC};
252     static const TypeSet allTypesButIUB       = {
253         vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
254         vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,          vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
255         vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,   vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
256         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,         vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
257         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
258     };
259     static const TypeSet allTypes = {
260         vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
261         vk::VK_DESCRIPTOR_TYPE_SAMPLER,
262         vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
263         vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
264         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
265         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
266         vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
267         vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
268         vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
269         vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
270         vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
271 #ifndef CTS_USES_VULKANSC
272         vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
273 #endif // CTS_USES_VULKANSC
274     };
275 
276     LimitsVector limits = {
277         {"maxPerStageDescriptorSamplers", prop1.limits.maxPerStageDescriptorSamplers, samplerTypes},
278         {"maxDescriptorSetSamplers", prop1.limits.maxDescriptorSetSamplers, samplerTypes},
279         {"maxPerStageDescriptorSampledImages", prop1.limits.maxPerStageDescriptorSampledImages, sampledImageTypes},
280         {"maxDescriptorSetSampledImages", prop1.limits.maxDescriptorSetSampledImages, sampledImageTypes},
281         {"maxPerStageDescriptorUniformBuffers", prop1.limits.maxPerStageDescriptorUniformBuffers, uniformBufferTypes},
282         {"maxDescriptorSetUniformBuffers", prop1.limits.maxDescriptorSetUniformBuffers, uniformBufferTypes},
283         {"maxPerStageDescriptorStorageBuffers", prop1.limits.maxPerStageDescriptorStorageBuffers, storageBufferTypes},
284         {"maxDescriptorSetStorageBuffers", prop1.limits.maxDescriptorSetStorageBuffers, storageBufferTypes},
285         {"maxPerStageDescriptorStorageImages", prop1.limits.maxPerStageDescriptorStorageImages, storageImageTypes},
286         {"maxDescriptorSetStorageImages", prop1.limits.maxDescriptorSetStorageImages, storageImageTypes},
287         {"maxPerStageDescriptorInputAttachments", prop1.limits.maxPerStageDescriptorInputAttachments,
288          inputAttachmentTypes},
289         {"maxDescriptorSetInputAttachments", prop1.limits.maxDescriptorSetInputAttachments, inputAttachmentTypes},
290         {"maxDescriptorSetUniformBuffersDynamic", prop1.limits.maxDescriptorSetUniformBuffersDynamic,
291          dynamicUniformBuffer},
292         {"maxDescriptorSetStorageBuffersDynamic", prop1.limits.maxDescriptorSetStorageBuffersDynamic,
293          dynamicStorageBuffer},
294 #ifndef CTS_USES_VULKANSC
295         // Removed from Vulkan SC test set: VK_EXT_inline_uniform_block extension removed from Vulkan SC
296         {"maxPerStageDescriptorInlineUniformBlocks", iubProp.maxPerStageDescriptorInlineUniformBlocks,
297          inlineUniformBlockTypes},
298         {"maxDescriptorSetInlineUniformBlocks", iubProp.maxDescriptorSetInlineUniformBlocks, inlineUniformBlockTypes},
299 #endif // CTS_USES_VULKANSC
300         {"maxPerStageResources", prop1.limits.maxPerStageResources, allTypesButIUB},
301         {"maxPerSetDescriptors", maintProp3.maxPerSetDescriptors, allTypes},
302     };
303 
304     return limits;
305 }
306 
307 // Create a vector of bindings by constructing the system limits and distributing descriptor counts.
calculateBindings(const DevProp1 & prop1,const DevIubProp & iubProp,const MaintDevProp3 & maintProp3,const vector<vk::VkDescriptorType> & types)308 vector<vk::VkDescriptorSetLayoutBinding> calculateBindings(const DevProp1 &prop1,
309 #ifndef CTS_USES_VULKANSC
310                                                            const DevIubProp &iubProp,
311 #endif // CTS_USES_VULKANSC
312                                                            const MaintDevProp3 &maintProp3,
313                                                            const vector<vk::VkDescriptorType> &types)
314 {
315     LimitsVector limits = buildLimitsVector(prop1,
316 #ifndef CTS_USES_VULKANSC
317                                             iubProp,
318 #endif // CTS_USES_VULKANSC
319                                             maintProp3);
320 
321     TypeCounts typeCounts;
322 
323     for (const auto &type : types)
324         typeCounts.emplace(make_pair(type, TypeState(type)));
325 
326     distributeCounts(limits, typeCounts);
327 
328 #ifdef CTS_USES_VULKANSC
329     // limit the number of binding counts, so that descriptorSetLayoutBindingRequestCount and descriptorSetLayoutBindingLimit won't be too big
330     for (auto &tc : typeCounts)
331         tc.second.count = de::min(tc.second.count, maxReasonableBindingCounts);
332 #endif // CTS_USES_VULKANSC
333 
334     uint32_t bindingNumber = 0u;
335     vector<vk::VkDescriptorSetLayoutBinding> bindings;
336     for (const auto &tc : typeCounts)
337     {
338 #ifndef CTS_USES_VULKANSC
339         if (tc.first != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
340 #else
341         if (true)
342 #endif // CTS_USES_VULKANSC
343         {
344             vk::VkDescriptorSetLayoutBinding b;
345             b.binding            = bindingNumber;
346             b.descriptorCount    = tc.second.count;
347             b.descriptorType     = tc.first;
348             b.pImmutableSamplers = DE_NULL;
349             b.stageFlags         = tc.first == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ? vk::VK_SHADER_STAGE_FRAGMENT_BIT :
350                                                                                      vk::VK_SHADER_STAGE_ALL;
351 
352             bindings.push_back(b);
353         }
354         else
355         {
356             // Inline uniform blocks are special because descriptorCount represents the size of that block.
357             // The only way of creating several blocks is by adding more structures to the list instead of creating an array.
358             size_t firstAdded = bindings.size();
359             bindings.resize(firstAdded + tc.second.count);
360             for (uint32_t i = 0u; i < tc.second.count; ++i)
361             {
362                 vk::VkDescriptorSetLayoutBinding &b = bindings[firstAdded + i];
363                 b.binding                           = bindingNumber + i;
364                 b.descriptorCount =
365                     4u; // For inline uniform blocks, this must be a multiple of 4 according to the spec.
366                 b.descriptorType     = tc.first;
367                 b.pImmutableSamplers = DE_NULL;
368                 b.stageFlags         = vk::VK_SHADER_STAGE_ALL;
369             }
370         }
371         bindingNumber += tc.second.count;
372     }
373 
374     return bindings;
375 }
376 
377 // Get a textual description with descriptor counts per type.
getBindingsDescription(const vector<VkDescriptorSetLayoutBinding> & bindings)378 string getBindingsDescription(const vector<VkDescriptorSetLayoutBinding> &bindings)
379 {
380     map<vk::VkDescriptorType, uint32_t> typeCount;
381     uint32_t totalCount = 0u;
382     uint32_t count;
383     for (const auto &b : bindings)
384     {
385         auto iter = typeCount.find(b.descriptorType);
386         if (iter == typeCount.end())
387             iter = typeCount.insert(make_pair(b.descriptorType, (uint32_t)0)).first;
388 #ifndef CTS_USES_VULKANSC
389         count = ((b.descriptorType == vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 1u : b.descriptorCount);
390 #else
391         count = b.descriptorCount;
392 #endif // CTS_USES_VULKANSC
393         iter->second += count;
394         totalCount += count;
395     }
396 
397     uint32_t i = 0;
398     ostringstream combStr;
399 
400     combStr << "{ Descriptors: " << totalCount << ", [";
401     for (const auto &tc : typeCount)
402         combStr << (i++ ? ", " : " ") << tc.first << ": " << tc.second;
403     combStr << " ] }";
404 
405     return combStr.str();
406 }
407 
408 class Maintenance3StructTestInstance : public TestInstance
409 {
410 public:
Maintenance3StructTestInstance(Context & ctx)411     Maintenance3StructTestInstance(Context &ctx) : TestInstance(ctx)
412     {
413     }
iterate(void)414     virtual tcu::TestStatus iterate(void)
415     {
416         tcu::TestLog &log = m_context.getTestContext().getLog();
417 
418         // set values to be a bit smaller than required minimum values
419         MaintDevProp3 maintProp3 = {
420             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
421             DE_NULL,                                                    //void* pNext;
422             maxDescriptorsInSet - 1u,                                   //uint32_t maxPerSetDescriptors;
423             maxMemoryAllocationSize - 1u                                //VkDeviceSize maxMemoryAllocationSize;
424         };
425 
426         DevProp2 prop2;
427         deMemset(&prop2, 0, sizeof(prop2)); // zero the structure
428         prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
429         prop2.pNext = &maintProp3;
430 
431         m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &prop2);
432 
433         if (maintProp3.maxMemoryAllocationSize < maxMemoryAllocationSize)
434             return tcu::TestStatus::fail("Fail");
435 
436         if (maintProp3.maxPerSetDescriptors < maxDescriptorsInSet)
437             return tcu::TestStatus::fail("Fail");
438 
439         log << tcu::TestLog::Message << "maxMemoryAllocationSize: " << maintProp3.maxMemoryAllocationSize
440             << tcu::TestLog::EndMessage;
441         log << tcu::TestLog::Message << "maxPerSetDescriptors: " << maintProp3.maxPerSetDescriptors
442             << tcu::TestLog::EndMessage;
443         return tcu::TestStatus::pass("Pass");
444     }
445 };
446 
447 class Maintenance3StructTestCase : public TestCase
448 {
449 public:
Maintenance3StructTestCase(tcu::TestContext & testCtx)450     Maintenance3StructTestCase(tcu::TestContext &testCtx) : TestCase(testCtx, "maintenance3_properties")
451     {
452     }
453 
~Maintenance3StructTestCase(void)454     virtual ~Maintenance3StructTestCase(void)
455     {
456     }
checkSupport(Context & ctx) const457     virtual void checkSupport(Context &ctx) const
458     {
459         ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
460     }
createInstance(Context & ctx) const461     virtual TestInstance *createInstance(Context &ctx) const
462     {
463         return new Maintenance3StructTestInstance(ctx);
464     }
465 
466 private:
467 };
468 
469 class Maintenance3DescriptorTestInstance : public TestInstance
470 {
471 public:
Maintenance3DescriptorTestInstance(Context & ctx)472     Maintenance3DescriptorTestInstance(Context &ctx) : TestInstance(ctx)
473     {
474     }
iterate(void)475     virtual tcu::TestStatus iterate(void)
476     {
477         const auto &vki            = m_context.getInstanceInterface();
478         const auto &vkd            = m_context.getDeviceInterface();
479         const auto &physicalDevice = m_context.getPhysicalDevice();
480         const auto &device         = m_context.getDevice();
481         auto &log                  = m_context.getTestContext().getLog();
482 
483 #ifndef CTS_USES_VULKANSC
484         bool iubSupported = false;
485 
486         if (m_context.isDeviceFunctionalitySupported("VK_EXT_inline_uniform_block"))
487         {
488             DevIubFeat iubFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT, DE_NULL, 0u,
489                                       0u};
490 
491             DevFeat2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &iubFeatures,
492                                   VkPhysicalDeviceFeatures()};
493 
494             vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
495             iubSupported = (iubFeatures.inlineUniformBlock == VK_TRUE);
496         }
497 
498         DevIubProp devIubProp = {
499             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, // VkStructureType sType;
500             DE_NULL,                                                               // void* pNext;
501             0u, // uint32_t maxInlineUniformBlockSize;
502             0u, // uint32_t maxPerStageDescriptorInlineUniformBlocks;
503             0u, // uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
504             0u, // uint32_t maxDescriptorSetInlineUniformBlocks;
505             0u  // uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
506         };
507 #endif // CTS_USES_VULKANSC
508 
509         MaintDevProp3 maintProp3 = {
510             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
511 #ifndef CTS_USES_VULKANSC
512             (iubSupported ? &devIubProp : DE_NULL), //void* pNext;
513 #else
514             DE_NULL, //void* pNext;
515 #endif                              // CTS_USES_VULKANSC
516             maxDescriptorsInSet,    //uint32_t maxPerSetDescriptors;
517             maxMemoryAllocationSize //VkDeviceSize maxMemoryAllocationSize;
518         };
519 
520         DevProp2 prop2 = {
521             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, //VkStructureType sType;
522             &maintProp3,                                    //void* pNext;
523             VkPhysicalDeviceProperties()                    //VkPhysicalDeviceProperties properties;
524         };
525 
526         vki.getPhysicalDeviceProperties2(physicalDevice, &prop2);
527 
528         vector<VkDescriptorType> descriptorTypes = {
529             VK_DESCRIPTOR_TYPE_SAMPLER,
530             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
531             VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
532             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
533             VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
534             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
535             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
536             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
537             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
538             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
539             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
540         };
541 #ifndef CTS_USES_VULKANSC
542         if (iubSupported)
543             descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
544 #endif // CTS_USES_VULKANSC
545 
546         // VkDescriptorSetLayoutCreateInfo setup
547         vk::VkDescriptorSetLayoutCreateInfo pCreateInfo = {
548             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, //VkStructureType sType;
549             DE_NULL,                                             //const void* pNext;
550             0u,                                                  //VkDescriptorSetLayoutCreateFlags flags;
551             0u,                                                  //uint32_t bindingCount;
552             DE_NULL                                              //const VkDescriptorSetLayoutBinding* pBindings;
553         };
554 
555         // VkDescriptorSetLayoutSupport setup
556         vk::VkDescriptorSetLayoutSupport pSupport = {
557             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, //VkStructureType sType;
558             DE_NULL,                                         //void* pNext;
559             VK_FALSE                                         //VkBool32 supported;
560         };
561 
562         // Check every combination maximizing descriptor counts.
563         for (size_t combSize = 1; combSize <= descriptorTypes.size(); ++combSize)
564         {
565             // Create a vector of selectors with combSize elements set to true.
566             vector<bool> selectors(descriptorTypes.size(), false);
567             std::fill(begin(selectors), begin(selectors) + combSize, true);
568 
569             // Iterate over every permutation of selectors for that combination size.
570             do
571             {
572                 vector<vk::VkDescriptorType> types;
573                 for (size_t i = 0; i < selectors.size(); ++i)
574                 {
575                     if (selectors[i])
576                         types.push_back(descriptorTypes[i]);
577                 }
578 
579 #ifndef CTS_USES_VULKANSC
580                 // Due to inline uniform blocks being unable to form arrays and each one of them needing its own
581                 // VkDescriptorSetLayoutBinding structure, we will limit when to test them.
582                 if (std::find(begin(types), end(types), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) != types.end() &&
583                     devIubProp.maxPerStageDescriptorInlineUniformBlocks > maxReasonableInlineUniformBlocks &&
584                     combSize > 1u && combSize < descriptorTypes.size())
585                 {
586                     continue;
587                 }
588 #endif // CTS_USES_VULKANSC
589 
590                 vector<vk::VkDescriptorSetLayoutBinding> bindings = calculateBindings(prop2.properties,
591 #ifndef CTS_USES_VULKANSC
592                                                                                       devIubProp,
593 #endif
594                                                                                       maintProp3, types);
595                 string description = getBindingsDescription(bindings);
596                 log << tcu::TestLog::Message << "Testing combination: " << description << tcu::TestLog::EndMessage;
597 
598                 pCreateInfo.bindingCount = static_cast<uint32_t>(bindings.size());
599                 pCreateInfo.pBindings    = bindings.data();
600 
601                 vkd.getDescriptorSetLayoutSupport(device, &pCreateInfo, &pSupport);
602                 if (pSupport.supported == VK_FALSE)
603                 {
604                     ostringstream msg;
605                     msg << "Failed to use the following descriptor type counts: " << description;
606                     return tcu::TestStatus::fail(msg.str());
607                 }
608             } while (std::prev_permutation(begin(selectors), end(selectors)));
609         }
610 
611         return tcu::TestStatus::pass("Pass");
612     }
613 };
614 
615 class Maintenance3DescriptorTestCase : public TestCase
616 {
617 
618 public:
Maintenance3DescriptorTestCase(tcu::TestContext & testCtx)619     Maintenance3DescriptorTestCase(tcu::TestContext &testCtx) : TestCase(testCtx, "descriptor_set")
620     {
621     }
~Maintenance3DescriptorTestCase(void)622     virtual ~Maintenance3DescriptorTestCase(void)
623     {
624     }
checkSupport(Context & ctx) const625     virtual void checkSupport(Context &ctx) const
626     {
627         ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
628     }
createInstance(Context & ctx) const629     virtual TestInstance *createInstance(Context &ctx) const
630     {
631         return new Maintenance3DescriptorTestInstance(ctx);
632     }
633 };
634 
635 struct CountLayoutSupportParams
636 {
637     const VkDescriptorType descriptorType;
638     const bool extraBindings;
639     const bool useVariableSize;
640 };
641 
checkSupportCountLayoutSupport(Context & context,CountLayoutSupportParams params)642 void checkSupportCountLayoutSupport(Context &context, CountLayoutSupportParams params)
643 {
644     context.requireDeviceFunctionality("VK_KHR_maintenance3");
645     context.requireDeviceFunctionality("VK_EXT_descriptor_indexing");
646 
647     if (params.useVariableSize)
648     {
649         const auto &indexingFeatures = context.getDescriptorIndexingFeatures();
650         if (!indexingFeatures.descriptorBindingVariableDescriptorCount)
651             TCU_THROW(NotSupportedError, "descriptorBindingVariableDescriptorCount not supported");
652     }
653 
654     if (params.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
655         context.requireDeviceFunctionality("VK_EXT_inline_uniform_block");
656 }
657 
658 struct SetLayoutSupportAndCount
659 {
660     const bool supported;
661     const uint32_t maxVariableDescriptorCount;
662 };
663 
getSetLayoutSupportAndCount(Context & context,const VkDescriptorSetLayoutCreateInfo * setLayoutCreateInfo)664 SetLayoutSupportAndCount getSetLayoutSupportAndCount(Context &context,
665                                                      const VkDescriptorSetLayoutCreateInfo *setLayoutCreateInfo)
666 {
667     VkDescriptorSetVariableDescriptorCountLayoutSupport countLayoutSupport = initVulkanStructure();
668     VkDescriptorSetLayoutSupport setLayoutSupport                          = initVulkanStructure(&countLayoutSupport);
669 
670     // Set a garbage value in the maxVariableDescriptorCount member, to verify it's not simply left untouched by the implementation.
671     countLayoutSupport.maxVariableDescriptorCount = std::numeric_limits<uint32_t>::max();
672     context.getDeviceInterface().getDescriptorSetLayoutSupport(context.getDevice(), setLayoutCreateInfo,
673                                                                &setLayoutSupport);
674     return SetLayoutSupportAndCount{(setLayoutSupport.supported == VK_TRUE),
675                                     countLayoutSupport.maxVariableDescriptorCount};
676 }
677 
testCountLayoutSupport(Context & context,CountLayoutSupportParams params)678 tcu::TestStatus testCountLayoutSupport(Context &context, CountLayoutSupportParams params)
679 {
680     VkShaderStageFlags stages = 0u;
681 
682     // The shader stages are probably not very relevant. This is an attempt at setting some varied but plausible stages anyway.
683     switch (params.descriptorType)
684     {
685     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
686     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
687     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
688     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
689         stages = VK_SHADER_STAGE_COMPUTE_BIT;
690         break;
691 
692     case VK_DESCRIPTOR_TYPE_SAMPLER:
693     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
694     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
695     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
696         stages = VK_SHADER_STAGE_FRAGMENT_BIT;
697         break;
698 
699     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
700     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
701     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
702     case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
703         stages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
704         break;
705 
706     default:
707         DE_ASSERT(false);
708         break;
709     };
710 
711     std::vector<VkDescriptorSetLayoutBinding> bindings;
712     std::vector<VkDescriptorBindingFlags> bindingFlags;
713 
714     if (params.extraBindings)
715     {
716         // Add a few uniform buffers to the mix.
717         const auto extraBindingCount = 3u;
718 
719         for (uint32_t i = 0u; i < extraBindingCount; ++i)
720         {
721             bindings.emplace_back(VkDescriptorSetLayoutBinding{
722                 de::sizeU32(bindings),             // uint32_t binding;
723                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType descriptorType;
724                 1u,                                // uint32_t descriptorCount;
725                 stages,                            // VkShaderStageFlags stageFlags;
726                 nullptr,                           // const VkSampler* pImmutableSamplers;
727             });
728             bindingFlags.push_back(0u);
729         }
730     }
731 
732     // VUID-VkDescriptorSetLayoutBinding-descriptorType-02209 mandates descriptorCount to be a multiple of 4 when using inline
733     // uniform blocks.
734     const auto descriptorCount = ((params.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ? 4u : 1u);
735 
736     bindings.emplace_back(VkDescriptorSetLayoutBinding{
737         de::sizeU32(bindings), // uint32_t binding;
738         params.descriptorType, // VkDescriptorType descriptorType;
739         descriptorCount,       // uint32_t descriptorCount;
740         stages,                // VkShaderStageFlags stageFlags;
741         nullptr,               // const VkSampler* pImmutableSamplers;
742     });
743     bindingFlags.push_back(params.useVariableSize ? static_cast<VkDescriptorBindingFlags>(
744                                                         VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) :
745                                                     0u);
746 
747     const VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo = {
748         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, // VkStructureType sType;
749         nullptr,                                                           // const void* pNext;
750         de::sizeU32(bindingFlags),                                         // uint32_t bindingCount;
751         de::dataOrNull(bindingFlags), // const VkDescriptorBindingFlags* pBindingFlags;
752     };
753 
754     const VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {
755         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType                        sType;
756         &bindingFlagsInfo,                                   // const void*                            pNext;
757         0u,                                                  // VkDescriptorSetLayoutCreateFlags       flags;
758         de::sizeU32(bindings),                               // uint32_t                               bindingCount;
759         de::dataOrNull(bindings),                            // const VkDescriptorSetLayoutBinding*    pBindings;
760     };
761 
762     // Check the layout is supported.
763     const auto normalValues = getSetLayoutSupportAndCount(context, &layoutCreateInfo);
764     if (!normalValues.supported)
765         TCU_THROW(NotSupportedError, "Set layout not supported");
766 
767     if (!params.useVariableSize)
768     {
769         if (normalValues.maxVariableDescriptorCount != 0u)
770             TCU_FAIL("Nonzero maxVariableDescriptorCount when using no variable descriptor counts");
771     }
772     else
773     {
774         // Verify if we switch from one to zero descriptors we get the same reply back.
775         bindings.back().descriptorCount = 0u;
776         const auto zeroDescriptorValues = getSetLayoutSupportAndCount(context, &layoutCreateInfo);
777 
778         if (!zeroDescriptorValues.supported)
779             TCU_FAIL("Implementation reports support with one descriptor and no support with zero descriptors");
780 
781         if (zeroDescriptorValues.maxVariableDescriptorCount != normalValues.maxVariableDescriptorCount)
782             TCU_FAIL("Mismatch in maxVariableDescriptorCount when using zero and one as descriptor counts");
783 
784         // Verify we can create a descriptor set with the promised amount of descriptors.
785         bindings.back().descriptorCount = normalValues.maxVariableDescriptorCount;
786         const auto maxDescriptorValues  = getSetLayoutSupportAndCount(context, &layoutCreateInfo);
787 
788         if (!maxDescriptorValues.supported)
789             TCU_FAIL("Implementation reports no support when using the maximum allowed size");
790 
791         if (maxDescriptorValues.maxVariableDescriptorCount != normalValues.maxVariableDescriptorCount)
792             TCU_FAIL("Mismatch in maxVariableDescriptorCount when using one and the maximum descriptor counts");
793     }
794 
795     return tcu::TestStatus::pass("Pass");
796 }
797 
getDescriptorTypeShortName(const VkDescriptorType descType)798 std::string getDescriptorTypeShortName(const VkDescriptorType descType)
799 {
800     static const auto prefixLen = strlen("VK_DESCRIPTOR_TYPE_");
801     std::string name            = getDescriptorTypeName(descType);
802 
803     name = name.substr(prefixLen);
804     return de::toLower(name);
805 }
806 
807 } // namespace
808 
createMaintenance3Tests(tcu::TestContext & testCtx)809 tcu::TestCaseGroup *createMaintenance3Tests(tcu::TestContext &testCtx)
810 {
811     de::MovePtr<tcu::TestCaseGroup> main3Tests(new tcu::TestCaseGroup(testCtx, "maintenance3_check"));
812     main3Tests->addChild(new Maintenance3StructTestCase(testCtx));
813     main3Tests->addChild(new Maintenance3DescriptorTestCase(testCtx));
814 
815     {
816         const VkDescriptorType descriptorTypes[] = {
817             VK_DESCRIPTOR_TYPE_SAMPLER,
818             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
819             VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
820             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
821             VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
822             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
823             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
824             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
825             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
826             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
827             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
828             VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK,
829         };
830 
831         for (const auto &descriptorType : descriptorTypes)
832             for (const auto &extraBindings : {false, true})
833                 for (const auto &useVariableSize : {false, true})
834                 {
835                     if (useVariableSize && (descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
836                                             descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC))
837                         continue;
838 
839                     const auto extraBindingsSuffix = (extraBindings ? "_extra_bindings" : "");
840                     const auto variableSizeSuffix  = (useVariableSize ? "" : "_no_variable_size");
841                     const auto caseName            = "support_count_" + getDescriptorTypeShortName(descriptorType) +
842                                           extraBindingsSuffix + variableSizeSuffix;
843                     const CountLayoutSupportParams params{descriptorType, extraBindings, useVariableSize};
844 
845                     addFunctionCase(main3Tests.get(), caseName.c_str(), checkSupportCountLayoutSupport,
846                                     testCountLayoutSupport, params);
847                 }
848     }
849 
850     return main3Tests.release();
851 }
852 
853 } // namespace api
854 } // namespace vkt
855