From: Ricardo Garcia Date: Wed, 10 Jul 2019 13:23:30 +0000 (+0200) Subject: Make sure vkGetDescriptorSetLayoutSupport limits are tested X-Git-Tag: upstream/1.3.5~1862 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=47475d56f212a569ea1bc7b626feff593a0649ec;p=platform%2Fupstream%2FVK-GL-CTS.git Make sure vkGetDescriptorSetLayoutSupport limits are tested 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 --- diff --git a/external/vulkancts/modules/vulkan/api/vktApiMaintenance3Check.cpp b/external/vulkancts/modules/vulkan/api/vktApiMaintenance3Check.cpp index 9cccad0..88d5a5c 100644 --- a/external/vulkancts/modules/vulkan/api/vktApiMaintenance3Check.cpp +++ b/external/vulkancts/modules/vulkan/api/vktApiMaintenance3Check.cpp @@ -28,7 +28,12 @@ #include "vktApiMaintenance3Check.hpp" #include "vktTestCase.hpp" -#define VK_DESCRIPTOR_TYPE_LAST (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT + 1) +#include +#include +#include +#include +#include +#include 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; + +// 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; +using LimitsVector = vector; + +// 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; + 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::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(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 calculateBindings(const DevProp1& prop1, const DevIubProp& iubProp, const MaintDevProp3& maintProp3, const vector &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 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& bindings) +{ + map 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(ndx); - descriptorSetLayoutBinding[ndx].descriptorCount = mainProp3.maxPerSetDescriptors; - descriptorSetLayoutBinding[ndx].stageFlags = VK_SHADER_STAGE_ALL; - descriptorSetLayoutBinding[ndx].pImmutableSamplers = DE_NULL; - } + vki.getPhysicalDeviceProperties2(physicalDevice, &prop2); + + vector 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 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 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 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(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(VK_DESCRIPTOR_TYPE_LAST); - - deUint32 fraction = mainProp3.maxPerSetDescriptors / static_cast(VK_DESCRIPTOR_TYPE_LAST); - deUint32 rest = mainProp3.maxPerSetDescriptors % static_cast(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 main3Tests(new tcu::TestCaseGroup(testCtx, "maintenance3_check", "Maintenance3 Tests")); main3Tests->addChild(new Maintenance3StructTestCase(testCtx));