Make sure vkGetDescriptorSetLayoutSupport limits are tested
authorRicardo Garcia <rgarcia@igalia.com>
Wed, 10 Jul 2019 13:23:30 +0000 (15:23 +0200)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Sat, 21 Sep 2019 15:48:00 +0000 (11:48 -0400)
The dEQP-VK.api.maintenance3_check.descriptor_set test tried several
descriptor set types and count combinations and checked if they falled
within acceptable limits. If they did not, no check was performed for
that combination. The test may have ended up passing with no check being
done because of that.

This commit makes the test combinatorial in nature and adds support for
inline uniform blocks in reasonable cases.

Affected tests:
dEQP-VK.api.maintenance3_check.descriptor_set

Components: Vulkan
VK-GL-CTS issue: 1879

Change-Id: Id641b53968b69b991af881a696918490fa4822be

external/vulkancts/modules/vulkan/api/vktApiMaintenance3Check.cpp

index 9cccad0..88d5a5c 100644 (file)
 #include "vktApiMaintenance3Check.hpp"
 #include "vktTestCase.hpp"
 
-#define VK_DESCRIPTOR_TYPE_LAST (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT + 1)
+#include <sstream>
+#include <limits>
+#include <utility>
+#include <algorithm>
+#include <map>
+#include <set>
 
 using namespace vk;
 
@@ -42,10 +47,384 @@ namespace
 {
 using ::std::string;
 using ::std::vector;
+using ::std::map;
+using ::std::set;
+using ::std::ostringstream;
+using ::std::make_pair;
+
+typedef vk::VkPhysicalDeviceProperties                                         DevProp1;
+typedef vk::VkPhysicalDeviceProperties2                                                DevProp2;
+typedef vk::VkPhysicalDeviceMaintenance3Properties                     MaintDevProp3;
+typedef vk::VkPhysicalDeviceFeatures2                                          DevFeat2;
+typedef vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT      DevIubFeat;
+typedef vk::VkPhysicalDeviceInlineUniformBlockPropertiesEXT    DevIubProp;
+
+// These variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
+constexpr deUint32 maxMemoryAllocationSize                     = 1073741824u;
+constexpr deUint32 maxDescriptorsInSet                         = 1024u;
+constexpr deUint32 maxReasonableInlineUniformBlocks    = 64u;
+
+using TypeSet          = set<vk::VkDescriptorType>;
+
+// Structure representing an implementation limit, like maxPerStageDescriptorSamplers. It has a maximum value
+// obtained at runtime and a remaining number of descriptors, which starts with the same count and decreases
+// as we assign descriptor counts to the different types. A limit is affected by (or itself affects) one or more
+// descriptor types. Note a type may be involved in several limits, and a limit may affect several types.
+struct Limit
+{
+       Limit(const string& name_, deUint32 maxValue_, const TypeSet& affectedTypes_)
+               : name(name_), maxValue(maxValue_), remaining(maxValue_), affectedTypes(affectedTypes_)
+               {}
+
+       const string    name;
+       const deUint32  maxValue;
+       deUint32                remaining;
+       const TypeSet   affectedTypes;
+};
+
+// Structure representing how many descriptors have been assigned to the given type. The type is "alive" during
+// descriptor count assignment if more descriptors can be added to the type without hitting any limit affected
+// by the type. Once at least one of the limits is reached, no more descriptors can be assigned to the type and
+// the type is no longer considered "alive".
+struct TypeState
+{
+       TypeState(vk::VkDescriptorType type_)
+               : type(type_), alive(true), count(0u)
+               {}
+
+       const vk::VkDescriptorType      type;
+       bool                                            alive;
+       deUint32                                        count;
+};
+
+using TypeCounts       = map<vk::VkDescriptorType, TypeState>;
+using LimitsVector     = vector<Limit>;
+
+// Get the subset of alive types from the given map.
+TypeSet getAliveTypes (const TypeCounts& typeCounts)
+{
+       TypeSet aliveTypes;
+       for (const auto& typeCount : typeCounts)
+       {
+               if (typeCount.second.alive)
+                       aliveTypes.insert(typeCount.first);
+       }
+       return aliveTypes;
+}
+
+// Get the subset of alive types for a specific limit, among the set of types affected by the limit.
+TypeSet getAliveTypesForLimit (const Limit& limit, const TypeSet& aliveTypes)
+{
+       TypeSet subset;
+       for (const auto& type : limit.affectedTypes)
+       {
+               if (aliveTypes.find(type) != aliveTypes.end())
+                       subset.insert(type);
+       }
+       return subset;
+}
+
+// Distribute descriptor counts as evenly as possible among the given set of types, taking into account the
+// given limits.
+void distributeCounts (LimitsVector& limits, TypeCounts& typeCounts)
+{
+       using IncrementsMap = map<vk::VkDescriptorType, deUint32>;
+       TypeSet aliveTypes;
+
+       while ((aliveTypes = getAliveTypes(typeCounts)).size() > 0u)
+       {
+               // Calculate the maximum increment per alive descriptor type. This involves iterating over the limits and
+               // finding out how many more descriptors can be distributed among the affected types that are still alive
+               // for the limit. For each type, remember the lowest possible increment.
+               IncrementsMap increments;
+               for (const auto& type : aliveTypes)
+                       increments[type] = std::numeric_limits<deUint32>::max();
+
+               TypeSet aliveTypesForLimit;
+
+               for (const auto& limit : limits)
+               {
+                       if (limit.remaining == 0u)
+                               continue;
+
+                       aliveTypesForLimit = getAliveTypesForLimit(limit, aliveTypes);
+                       if (aliveTypesForLimit.empty())
+                               continue;
+
+                       // Distribute remaining count evenly among alive types.
+                       deUint32 maxIncrement = limit.remaining / static_cast<deUint32>(aliveTypesForLimit.size());
+                       if (maxIncrement == 0u)
+                       {
+                               // More types than remaining descriptors. Assign 1 to the first affected types and 0 to the rest.
+                               deUint32 remaining = limit.remaining;
+                               for (const auto& type : aliveTypesForLimit)
+                               {
+                                       if (remaining > 0u && increments[type] > 0u)
+                                       {
+                                               increments[type] = 1u;
+                                               --remaining;
+                                       }
+                                       else
+                                       {
+                                               increments[type] = 0u;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               // Find the lowest possible increment taking into account all limits.
+                               for (const auto& type : aliveTypesForLimit)
+                               {
+                                       if (increments[type] > maxIncrement)
+                                               increments[type] = maxIncrement;
+                               }
+                       }
+               }
+
+               // Apply the calculated increments per descriptor type, decreasing the remaining descriptors for each
+               // limit affected by the type, and switching types to the not-alive state when a limit is hit.
+               for (const auto& inc : increments)
+               {
+                       const vk::VkDescriptorType& type = inc.first;
+                       const deUint32& increment = inc.second;
+
+                       // Increase type count.
+                       auto iter = typeCounts.find(type);
+                       DE_ASSERT(iter != typeCounts.end());
+                       iter->second.count += increment;
+
+                       for (auto& limit : limits)
+                       {
+                               // Decrease remaining descriptors for affected limits.
+                               if (limit.affectedTypes.find(type) != limit.affectedTypes.end())
+                               {
+                                       DE_ASSERT(increment <= limit.remaining);
+                                       limit.remaining -= increment;
+                               }
+                               if (limit.remaining == 0u)
+                               {
+                                       // Limit hit, switch affected types to not-alive.
+                                       for (const auto& affectedType : limit.affectedTypes)
+                                       {
+                                               auto tc = typeCounts.find(affectedType);
+                                               if (tc != typeCounts.end())
+                                                       tc->second.alive = false;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+// Create a limits vector based on runtime limit information for the device.
+LimitsVector buildLimitsVector (const DevProp1& prop1, const DevIubProp& iubProp, const MaintDevProp3& maintProp3)
+{
+       static const TypeSet samplerTypes                               = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLER };
+       static const TypeSet sampledImageTypes                  = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER };
+       static const TypeSet uniformBufferTypes                 = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
+       static const TypeSet storageBufferTypes                 = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
+       static const TypeSet storageImageTypes                  = { vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER };
+       static const TypeSet inputAttachmentTypes               = { vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT };
+       static const TypeSet inlineUniformBlockTypes    = { vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT };
+       static const TypeSet dynamicUniformBuffer               = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
+       static const TypeSet dynamicStorageBuffer               = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
+       static const TypeSet allTypesButIUB                             = {
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+                                                                                                       };
+       static const TypeSet allTypes                                   = {
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_SAMPLER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+                                                                                                               vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
+                                                                                                       };
+
+       LimitsVector limits = {
+               {
+                       "maxPerStageDescriptorSamplers",
+                       prop1.limits.maxPerStageDescriptorSamplers,
+                       samplerTypes
+               },
+               {
+                       "maxDescriptorSetSamplers",
+                       prop1.limits.maxDescriptorSetSamplers,
+                       samplerTypes
+               },
+               {
+                       "maxPerStageDescriptorSampledImages",
+                       prop1.limits.maxPerStageDescriptorSampledImages,
+                       sampledImageTypes
+               },
+               {
+                       "maxDescriptorSetSampledImages",
+                       prop1.limits.maxDescriptorSetSampledImages,
+                       sampledImageTypes
+               },
+               {
+                       "maxPerStageDescriptorUniformBuffers",
+                       prop1.limits.maxPerStageDescriptorUniformBuffers,
+                       uniformBufferTypes
+               },
+               {
+                       "maxDescriptorSetUniformBuffers",
+                       prop1.limits.maxDescriptorSetUniformBuffers,
+                       uniformBufferTypes
+               },
+               {
+                       "maxPerStageDescriptorStorageBuffers",
+                       prop1.limits.maxPerStageDescriptorStorageBuffers,
+                       storageBufferTypes
+               },
+               {
+                       "maxDescriptorSetStorageBuffers",
+                       prop1.limits.maxDescriptorSetStorageBuffers,
+                       storageBufferTypes
+               },
+               {
+                       "maxPerStageDescriptorStorageImages",
+                       prop1.limits.maxPerStageDescriptorStorageImages,
+                       storageImageTypes
+               },
+               {
+                       "maxDescriptorSetStorageImages",
+                       prop1.limits.maxDescriptorSetStorageImages,
+                       storageImageTypes
+               },
+               {
+                       "maxPerStageDescriptorInputAttachments",
+                       prop1.limits.maxPerStageDescriptorInputAttachments,
+                       inputAttachmentTypes
+               },
+               {
+                       "maxDescriptorSetInputAttachments",
+                       prop1.limits.maxDescriptorSetInputAttachments,
+                       inputAttachmentTypes
+               },
+               {
+                       "maxDescriptorSetUniformBuffersDynamic",
+                       prop1.limits.maxDescriptorSetUniformBuffersDynamic,
+                       dynamicUniformBuffer
+               },
+               {
+                       "maxDescriptorSetStorageBuffersDynamic",
+                       prop1.limits.maxDescriptorSetStorageBuffersDynamic,
+                       dynamicStorageBuffer
+               },
+               {
+                       "maxPerStageDescriptorInlineUniformBlocks",
+                       iubProp.maxPerStageDescriptorInlineUniformBlocks,
+                       inlineUniformBlockTypes
+               },
+               {
+                       "maxDescriptorSetInlineUniformBlocks",
+                       iubProp.maxDescriptorSetInlineUniformBlocks,
+                       inlineUniformBlockTypes
+               },
+               {
+                       "maxPerStageResources",
+                       prop1.limits.maxPerStageResources,
+                       allTypesButIUB
+               },
+               {
+                       "maxPerSetDescriptors",
+                       maintProp3.maxPerSetDescriptors,
+                       allTypes
+               },
+       };
+
+       return limits;
+}
 
-typedef vk::VkPhysicalDeviceProperties DevProp1;
-typedef vk::VkPhysicalDeviceProperties2  DevProp2;
-typedef vk::VkPhysicalDeviceMaintenance3Properties MainDevProp3;
+// Create a vector of bindings by constructing the system limits and distributing descriptor counts.
+vector<vk::VkDescriptorSetLayoutBinding> calculateBindings(const DevProp1& prop1, const DevIubProp& iubProp, const MaintDevProp3& maintProp3, const vector<vk::VkDescriptorType> &types)
+{
+       LimitsVector limits = buildLimitsVector(prop1, iubProp, maintProp3);
+       TypeCounts typeCounts;
+
+       for (const auto& type : types)
+               typeCounts.emplace(make_pair(type, TypeState(type)));
+
+       distributeCounts(limits, typeCounts);
+
+       deUint32 bindingNumber = 0u;
+       vector<vk::VkDescriptorSetLayoutBinding> bindings;
+       for (const auto& tc : typeCounts)
+       {
+               if (tc.first != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
+               {
+                       vk::VkDescriptorSetLayoutBinding b;
+                       b.binding = bindingNumber;
+                       b.descriptorCount = tc.second.count;
+                       b.descriptorType = tc.first;
+                       b.pImmutableSamplers = DE_NULL;
+                       b.stageFlags = vk::VK_SHADER_STAGE_ALL;
+
+                       bindings.push_back(b);
+               }
+               else
+               {
+                       // Inline uniform blocks are special because descriptorCount represents the size of that block.
+                       // The only way of creating several blocks is by adding more structures to the list instead of creating an array.
+                       size_t firstAdded = bindings.size();
+                       bindings.resize(firstAdded + tc.second.count);
+                       for (deUint32 i = 0u; i < tc.second.count; ++i)
+                       {
+                               vk::VkDescriptorSetLayoutBinding& b = bindings[firstAdded + i];
+                               b.binding = bindingNumber + i;
+                               b.descriptorCount = 4u; // For inline uniform blocks, this must be a multiple of 4 according to the spec.
+                               b.descriptorType = tc.first;
+                               b.pImmutableSamplers = DE_NULL;
+                               b.stageFlags = vk::VK_SHADER_STAGE_ALL;
+                       }
+               }
+               bindingNumber += tc.second.count;
+       }
+
+       return bindings;
+}
+
+// Get a textual description with descriptor counts per type.
+string getBindingsDescription (const vector<VkDescriptorSetLayoutBinding>& bindings)
+{
+       map<vk::VkDescriptorType, deUint32> typeCount;
+       deUint32 totalCount = 0u;
+       deUint32 count;
+       for (const auto& b : bindings)
+       {
+               auto iter = typeCount.find(b.descriptorType);
+               if (iter == typeCount.end())
+                       iter = typeCount.insert(make_pair(b.descriptorType, (deUint32)0)).first;
+               count = ((b.descriptorType == vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 1u : b.descriptorCount);
+               iter->second += count;
+               totalCount += count;
+       }
+
+       deUint32 i = 0;
+       ostringstream combStr;
+
+       combStr << "{ Descriptors: " << totalCount << ", [";
+       for (const auto& tc : typeCount)
+               combStr << (i++ ? ", " : " ") << tc.first << ": " << tc.second;
+       combStr << " ] }";
+
+       return combStr.str();
+}
 
 class Maintenance3StructTestInstance : public TestInstance
 {
@@ -57,12 +436,8 @@ public:
        {
                tcu::TestLog&                                           log                                                                             = m_context.getTestContext().getLog();
 
-               // these variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
-               const deUint32                                          maxMemoryAllocationSize                                 = 1073741824u;
-               const deUint32                                          maxDescriptorsInSet                                             = 1024u;
-
                // set values to be a bit smaller than required minimum values
-               MainDevProp3 mainProp3 =
+               MaintDevProp3 maintProp3 =
                {
                        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES,                             //VkStructureType                                               sType;
                        DE_NULL,                                                                                                                                //void*                                                                 pNext;
@@ -73,18 +448,18 @@ public:
                DevProp2 prop2;
                deMemset(&prop2, 0, sizeof(prop2)); // zero the structure
                prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-               prop2.pNext = &mainProp3;
+               prop2.pNext = &maintProp3;
 
                m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &prop2);
 
-               if (mainProp3.maxMemoryAllocationSize < maxMemoryAllocationSize)
+               if (maintProp3.maxMemoryAllocationSize < maxMemoryAllocationSize)
                        return tcu::TestStatus::fail("Fail");
 
-               if (mainProp3.maxPerSetDescriptors < maxDescriptorsInSet)
+               if (maintProp3.maxPerSetDescriptors < maxDescriptorsInSet)
                        return tcu::TestStatus::fail("Fail");
 
-               log << tcu::TestLog::Message << "maxMemoryAllocationSize: "     << mainProp3.maxMemoryAllocationSize    << tcu::TestLog::EndMessage;
-               log << tcu::TestLog::Message << "maxPerSetDescriptors: "        << mainProp3.maxPerSetDescriptors               << tcu::TestLog::EndMessage;
+               log << tcu::TestLog::Message << "maxMemoryAllocationSize: "     << maintProp3.maxMemoryAllocationSize   << tcu::TestLog::EndMessage;
+               log << tcu::TestLog::Message << "maxPerSetDescriptors: "        << maintProp3.maxPerSetDescriptors              << tcu::TestLog::EndMessage;
                return tcu::TestStatus::pass("Pass");
        }
 };
@@ -118,14 +493,50 @@ public:
        {}
        virtual tcu::TestStatus                                 iterate                                                                 (void)
        {
-               // these variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
-               const deUint32                                          maxMemoryAllocationSize                                 = 1073741824u;
-               const deUint32                                          maxDescriptorsInSet                                             = 1024u;
+               const auto& vki                         = m_context.getInstanceInterface();
+               const auto& vkd                         = m_context.getDeviceInterface();
+               const auto& physicalDevice      = m_context.getPhysicalDevice();
+               const auto&     device                  = m_context.getDevice();
+               auto&           log                             = m_context.getTestContext().getLog();
+               bool            iubSupported    = false;
+               bool            iubExtSupported = isDeviceExtensionSupported(m_context.getUsedApiVersion(), m_context.getDeviceExtensions(), "VK_EXT_inline_uniform_block");
+
+               if (iubExtSupported)
+               {
+                       DevIubFeat      iubFeatures     =
+                       {
+                               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
+                               DE_NULL,
+                               0u,
+                               0u
+                       };
+
+                       DevFeat2        features2       =
+                       {
+                               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
+                               &iubFeatures,
+                               VkPhysicalDeviceFeatures()
+                       };
+
+                       vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
+                       iubSupported = (iubFeatures.inlineUniformBlock == VK_TRUE);
+               }
+
+               DevIubProp                                                      devIubProp                                                              =
+               {
+                       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT,  // VkStructureType      sType;
+                       DE_NULL,                                                                                                                                // void*                        pNext;
+                       0u,                                                                                                                                             // deUint32                     maxInlineUniformBlockSize;
+                       0u,                                                                                                                                             // deUint32                     maxPerStageDescriptorInlineUniformBlocks;
+                       0u,                                                                                                                                             // deUint32                     maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
+                       0u,                                                                                                                                             // deUint32                     maxDescriptorSetInlineUniformBlocks;
+                       0u                                                                                                                                              // deUint32                     maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
+               };
 
-               MainDevProp3                                            mainProp3                                                               =
+               MaintDevProp3                                           maintProp3                                                              =
                {
                        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES,                             //VkStructureType                                               sType;
-                       DE_NULL,                                                                                                                                //void*                                                                 pNext;
+                       (iubSupported ? &devIubProp : DE_NULL),                                                                 //void*                                                                 pNext;
                        maxDescriptorsInSet,                                                                                                    //deUint32                                                              maxPerSetDescriptors;
                        maxMemoryAllocationSize                                                                                                 //VkDeviceSize                                                  maxMemoryAllocationSize;
                };
@@ -133,26 +544,27 @@ public:
                DevProp2                                                        prop2                                                                   =
                {
                        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,                                                 //VkStructureType                                               sType;
-                       &mainProp3,                                                                                                                             //void*                                                                 pNext;
+                       &maintProp3,                                                                                                                    //void*                                                                 pNext;
                        VkPhysicalDeviceProperties()                                                                                    //VkPhysicalDeviceProperties                    properties;
                };
 
-               DevProp1                                                        prop1;
-
-               m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &prop1);
-               m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &prop2);
-
-               // setup for descriptors sets
-               VkDescriptorSetLayoutBinding            descriptorSetLayoutBinding[VK_DESCRIPTOR_TYPE_LAST];
-
-               for (deUint32 ndx = 0u; ndx < VK_DESCRIPTOR_TYPE_LAST; ++ndx)
-               {
-                       descriptorSetLayoutBinding[ndx].binding                                                                 = ndx;
-                       descriptorSetLayoutBinding[ndx].descriptorType                                                  = static_cast<VkDescriptorType>(ndx);
-                       descriptorSetLayoutBinding[ndx].descriptorCount                                                 = mainProp3.maxPerSetDescriptors;
-                       descriptorSetLayoutBinding[ndx].stageFlags                                                              = VK_SHADER_STAGE_ALL;
-                       descriptorSetLayoutBinding[ndx].pImmutableSamplers                                              = DE_NULL;
-               }
+               vki.getPhysicalDeviceProperties2(physicalDevice, &prop2);
+
+               vector<VkDescriptorType> descriptorTypes = {
+                       VK_DESCRIPTOR_TYPE_SAMPLER,
+                       VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                       VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+                       VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+                       VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+                       VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+                       VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+                       VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+                       VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+               };
+               if (iubSupported)
+                       descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
 
                // VkDescriptorSetLayoutCreateInfo setup
                vk::VkDescriptorSetLayoutCreateInfo     pCreateInfo                                                             =
@@ -160,7 +572,7 @@ public:
                        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,                                    //VkStructureType                                               sType;
                        DE_NULL,                                                                                                                                //const void*                                                   pNext;
                        0u,                                                                                                                                             //VkDescriptorSetLayoutCreateFlags              flags;
-                       1u,                                                                                                                                             //deUint32                                                              bindingCount;
+                       0u,                                                                                                                                             //deUint32                                                              bindingCount;
                        DE_NULL                                                                                                                                 //const VkDescriptorSetLayoutBinding*   pBindings;
                };
 
@@ -172,94 +584,53 @@ public:
                        VK_FALSE                                                                                                                                //VkBool32                                                              supported;
                };
 
-               // check for single descriptors
-               for (deUint32 ndx = 0u; ndx < VK_DESCRIPTOR_TYPE_LAST; ++ndx)
+               // Check every combination maximizing descriptor counts.
+               for (size_t combSize = 1; combSize <= descriptorTypes.size(); ++combSize)
                {
-                       pCreateInfo.pBindings = &descriptorSetLayoutBinding[ndx];
-                       m_context.getDeviceInterface().getDescriptorSetLayoutSupport(m_context.getDevice(), &pCreateInfo, &pSupport);
+                       // Create a vector of selectors with combSize elements set to true.
+                       vector<bool> selectors(descriptorTypes.size(), false);
+                       std::fill(begin(selectors), begin(selectors) + combSize, true);
 
-                       if(extraLimitCheck(descriptorSetLayoutBinding, ndx, pCreateInfo.bindingCount, prop1))
+                       // Iterate over every permutation of selectors for that combination size.
+                       do
                        {
+                               vector<vk::VkDescriptorType> types;
+                               for (size_t i = 0; i < selectors.size(); ++i)
+                               {
+                                       if (selectors[i])
+                                               types.push_back(descriptorTypes[i]);
+                               }
+
+                               // Due to inline uniform blocks being unable to form arrays and each one of them needing its own
+                               // VkDescriptorSetLayoutBinding structure, we will limit when to test them.
+                               if (std::find(begin(types), end(types), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) != types.end() &&
+                                       devIubProp.maxPerStageDescriptorInlineUniformBlocks > maxReasonableInlineUniformBlocks &&
+                                       combSize > 1u && combSize < descriptorTypes.size())
+                               {
+                                       continue;
+                               }
+
+                               vector<vk::VkDescriptorSetLayoutBinding> bindings = calculateBindings(prop2.properties, devIubProp, maintProp3, types);
+
+                               string description = getBindingsDescription(bindings);
+                               log << tcu::TestLog::Message << "Testing combination: " << description << tcu::TestLog::EndMessage;
+
+                               pCreateInfo.bindingCount = static_cast<deUint32>(bindings.size());
+                               pCreateInfo.pBindings = bindings.data();
+
+                               vkd.getDescriptorSetLayoutSupport(device, &pCreateInfo, &pSupport);
                                if (pSupport.supported == VK_FALSE)
-                                       return tcu::TestStatus::fail("fail");
-                       }
-               }
-
-               // check for accumulated descriptors (all eleven types)
-
-               pCreateInfo.pBindings = &descriptorSetLayoutBinding[0u];
-               pCreateInfo.bindingCount = static_cast<deUint32>(VK_DESCRIPTOR_TYPE_LAST);
-
-               deUint32 fraction = mainProp3.maxPerSetDescriptors / static_cast<deUint32>(VK_DESCRIPTOR_TYPE_LAST);
-               deUint32 rest = mainProp3.maxPerSetDescriptors % static_cast<deUint32>(VK_DESCRIPTOR_TYPE_LAST);
-
-               for (deUint32 ndx = 0u; ndx < VK_DESCRIPTOR_TYPE_LAST; ++ndx)
-                       descriptorSetLayoutBinding[ndx].descriptorCount = fraction;
-               descriptorSetLayoutBinding[0u].descriptorCount += rest;
-
-               m_context.getDeviceInterface().getDescriptorSetLayoutSupport(m_context.getDevice(), &pCreateInfo, &pSupport);
-
-               if (extraLimitCheck(descriptorSetLayoutBinding, 0u, pCreateInfo.bindingCount, prop1))
-               {
-                       if (pSupport.supported == VK_FALSE)
-                               return tcu::TestStatus::fail("fail");
+                               {
+                                       ostringstream msg;
+                                       msg << "Failed to use the following descriptor type counts: " << description;
+                                       return tcu::TestStatus::fail(msg.str());
+                               }
+                       } while (std::prev_permutation(begin(selectors), end(selectors)));
                }
 
                return tcu::TestStatus::pass("Pass");
        }
 
-private:
-       bool                                                                    extraLimitCheck                                                 (const VkDescriptorSetLayoutBinding* descriptorSetLayoutBinding, const deUint32& curNdx, const deUint32& size, const DevProp1& prop1)
-       {
-               deUint32                                                        maxPerStageDescriptorSamplers                   = 0u;
-               deUint32                                                        maxPerStageDescriptorUniformBuffers             = 0u;
-               deUint32                                                        maxPerStageDescriptorStorageBuffers             = 0u;
-               deUint32                                                        maxPerStageDescriptorSampledImages              = 0u;
-               deUint32                                                        maxPerStageDescriptorStorageImages              = 0u;
-               deUint32                                                        maxPerStageDescriptorInputAttachments   = 0u;
-
-               for(deUint32 ndx = curNdx; ndx < curNdx + size; ++ndx)
-               {
-                       if ((descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
-                               (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
-                               maxPerStageDescriptorSamplers += descriptorSetLayoutBinding->descriptorCount;
-
-                       if ((descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
-                                       (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC))
-                               maxPerStageDescriptorUniformBuffers += descriptorSetLayoutBinding->descriptorCount;
-
-                       if ((descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
-                                       (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC))
-                               maxPerStageDescriptorStorageBuffers += descriptorSetLayoutBinding->descriptorCount;
-
-                       if ((descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)       ||
-                                       (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)            ||
-                                       (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER))
-                               maxPerStageDescriptorSampledImages += descriptorSetLayoutBinding->descriptorCount;
-
-                       if ((descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
-                                       (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER))
-                               maxPerStageDescriptorStorageImages += descriptorSetLayoutBinding->descriptorCount;
-
-                       if (descriptorSetLayoutBinding[ndx].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
-                               maxPerStageDescriptorInputAttachments += descriptorSetLayoutBinding->descriptorCount;
-               }
-
-               if (prop1.limits.maxPerStageDescriptorSamplers < maxPerStageDescriptorSamplers)
-                       return false;
-               if (prop1.limits.maxPerStageDescriptorUniformBuffers < maxPerStageDescriptorUniformBuffers)
-                       return false;
-               if (prop1.limits.maxPerStageDescriptorStorageBuffers < maxPerStageDescriptorStorageBuffers)
-                       return false;
-               if (prop1.limits.maxPerStageDescriptorSampledImages < maxPerStageDescriptorSampledImages)
-                       return false;
-               if (prop1.limits.maxPerStageDescriptorStorageImages < maxPerStageDescriptorStorageImages)
-                       return false;
-               if (prop1.limits.maxPerStageDescriptorInputAttachments < maxPerStageDescriptorInputAttachments)
-                       return false;
-
-               return true;
-       }
 };
 
 class Maintenance3DescriptorTestCase : public TestCase
@@ -279,13 +650,11 @@ public:
        {
                return new Maintenance3DescriptorTestInstance(ctx);
        }
-
-private:
 };
 
 } // anonymous
 
-       tcu::TestCaseGroup*                                             createMaintenance3Tests                                 (tcu::TestContext&      testCtx)
+tcu::TestCaseGroup*                                                    createMaintenance3Tests                                 (tcu::TestContext&      testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> main3Tests(new tcu::TestCaseGroup(testCtx, "maintenance3_check", "Maintenance3 Tests"));
        main3Tests->addChild(new Maintenance3StructTestCase(testCtx));