/*------------------------------------------------------------------------- * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2016 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Descriptor pool tests *//*--------------------------------------------------------------------*/ #include "vktApiDescriptorPoolTests.hpp" #include "vktTestCaseUtil.hpp" #include "vkDefs.hpp" #include "vkRef.hpp" #include "vkRefUtil.hpp" #include "vkPlatform.hpp" #include "vkDeviceUtil.hpp" #include "vkQueryUtil.hpp" #include "tcuCommandLine.hpp" #include "tcuTestLog.hpp" #include "tcuPlatform.hpp" #include "deUniquePtr.hpp" #include "deSharedPtr.hpp" #include "deInt32.h" #include "deSTLUtil.hpp" #define VK_DESCRIPTOR_TYPE_LAST (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT + 1) namespace vkt { namespace api { namespace { using namespace std; using namespace vk; struct ResetDescriptorPoolTestParams { ResetDescriptorPoolTestParams (deUint32 numIterations, bool freeDescriptorSets = false) : m_numIterations (numIterations) , m_freeDescriptorSets (freeDescriptorSets) {} deUint32 m_numIterations; bool m_freeDescriptorSets; }; void checkSupportFreeDescriptorSets (Context& context, const ResetDescriptorPoolTestParams params) { #ifdef CTS_USES_VULKANSC if(params.m_freeDescriptorSets && context.getDeviceVulkanSC10Properties().recycleDescriptorSetMemory == VK_FALSE ) TCU_THROW(NotSupportedError, "vkFreeDescriptorSets not supported"); #else DE_UNREF(context); DE_UNREF(params); #endif // CTS_USES_VULKANSC } tcu::TestStatus resetDescriptorPoolTest (Context& context, const ResetDescriptorPoolTestParams params) { #ifndef CTS_USES_VULKANSC const deUint32 numDescriptorSetsPerIter = 2048; #else const deUint32 numDescriptorSetsPerIter = 100; #endif // CTS_USES_VULKANSC const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const VkDescriptorPoolSize descriptorPoolSize = { VK_DESCRIPTOR_TYPE_SAMPLER, // type numDescriptorSetsPerIter // descriptorCount }; const VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // sType NULL, // pNext (params.m_freeDescriptorSets) ? (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT : 0u, // flags numDescriptorSetsPerIter, // maxSets 1, // poolSizeCount &descriptorPoolSize // pPoolSizes }; { const Unique descriptorPool( createDescriptorPool(vkd, device, &descriptorPoolInfo)); const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding = { 0, // binding VK_DESCRIPTOR_TYPE_SAMPLER, // descriptorType 1, // descriptorCount VK_SHADER_STAGE_ALL, // stageFlags NULL // pImmutableSamplers }; const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType NULL, // pNext 0, // flags 1, // bindingCount &descriptorSetLayoutBinding // pBindings }; { typedef de::SharedPtr > DescriptorSetLayoutPtr; vector descriptorSetLayouts; descriptorSetLayouts.reserve(numDescriptorSetsPerIter); for (deUint32 ndx = 0; ndx < numDescriptorSetsPerIter; ++ndx) { descriptorSetLayouts.push_back( DescriptorSetLayoutPtr( new Unique( createDescriptorSetLayout(vkd, device, &descriptorSetLayoutInfo)))); } vector descriptorSetLayoutsRaw(numDescriptorSetsPerIter); for (deUint32 ndx = 0; ndx < numDescriptorSetsPerIter; ++ndx) { descriptorSetLayoutsRaw[ndx] = **descriptorSetLayouts[ndx]; } const VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType NULL, // pNext *descriptorPool, // descriptorPool numDescriptorSetsPerIter, // descriptorSetCount &descriptorSetLayoutsRaw[0] // pSetLayouts }; vector testSets(numDescriptorSetsPerIter); for (deUint32 ndx = 0; ndx < params.m_numIterations; ++ndx) { if (ndx % 1024 == 0) context.getTestContext().touchWatchdog(); // The test should crash in this loop at some point if there is a memory leak VK_CHECK(vkd.allocateDescriptorSets(device, &descriptorSetInfo, &testSets[0])); if (params.m_freeDescriptorSets) VK_CHECK(vkd.freeDescriptorSets(device, *descriptorPool, 1, &testSets[0])); VK_CHECK(vkd.resetDescriptorPool(device, *descriptorPool, 0)); } } } // If it didn't crash, pass return tcu::TestStatus::pass("Pass"); } tcu::TestStatus outOfPoolMemoryTest (Context& context) { const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const bool expectOutOfPoolMemoryError = context.isDeviceFunctionalitySupported("VK_KHR_maintenance1"); deUint32 numErrorsReturned = 0; const struct FailureCase { deUint32 poolDescriptorCount; //!< total number of descriptors (of a given type) in the descriptor pool deUint32 poolMaxSets; //!< max number of descriptor sets that can be allocated from the pool deUint32 bindingCount; //!< number of bindings per descriptor set layout deUint32 bindingDescriptorCount; //!< number of descriptors in a binding (array size) (in all bindings) deUint32 descriptorSetCount; //!< number of descriptor sets to allocate string description; //!< the log message for this failure condition } failureCases[] = { // pool pool binding binding alloc set // descr. count max sets count array size count { 4u, 2u, 1u, 1u, 3u, "Out of descriptor sets", }, { 3u, 4u, 1u, 1u, 4u, "Out of descriptors (due to the number of sets)", }, { 2u, 1u, 3u, 1u, 1u, "Out of descriptors (due to the number of bindings)", }, { 3u, 2u, 1u, 2u, 2u, "Out of descriptors (due to descriptor array size)", }, { 5u, 1u, 2u, 3u, 1u, "Out of descriptors (due to descriptor array size in all bindings)",}, }; context.getTestContext().getLog() << tcu::TestLog::Message << "Creating a descriptor pool with insufficient resources. Descriptor set allocation is likely to fail." << tcu::TestLog::EndMessage; for (deUint32 failureCaseNdx = 0u; failureCaseNdx < DE_LENGTH_OF_ARRAY(failureCases); ++failureCaseNdx) { const FailureCase& params = failureCases[failureCaseNdx]; context.getTestContext().getLog() << tcu::TestLog::Message << "Checking: " << params.description << tcu::TestLog::EndMessage; for (VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptorType < VK_DESCRIPTOR_TYPE_LAST; descriptorType = static_cast(descriptorType + 1)) { context.getTestContext().getLog() << tcu::TestLog::Message << "- " << getDescriptorTypeName(descriptorType) << tcu::TestLog::EndMessage; const VkDescriptorPoolSize descriptorPoolSize = { descriptorType, // type params.poolDescriptorCount, // descriptorCount }; const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkDescriptorPoolCreateFlags)0, // VkDescriptorPoolCreateFlags flags; params.poolMaxSets, // uint32_t maxSets; 1u, // uint32_t poolSizeCount; &descriptorPoolSize, // const VkDescriptorPoolSize* pPoolSizes; }; const Unique descriptorPool(createDescriptorPool(vkd, device, &descriptorPoolCreateInfo)); VkShaderStageFlags stageFlags = (descriptorType != VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ? VK_SHADER_STAGE_ALL : VK_SHADER_STAGE_FRAGMENT_BIT; const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding = { 0u, // uint32_t binding; descriptorType, // VkDescriptorType descriptorType; params.bindingDescriptorCount, // uint32_t descriptorCount; stageFlags, // VkShaderStageFlags stageFlags; DE_NULL, // const VkSampler* pImmutableSamplers; }; vector descriptorSetLayoutBindings (params.bindingCount, descriptorSetLayoutBinding); for (deUint32 binding = 0; binding < deUint32(descriptorSetLayoutBindings.size()); ++binding) { descriptorSetLayoutBindings[binding].binding = binding; } const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkDescriptorSetLayoutCreateFlags)0, // VkDescriptorSetLayoutCreateFlags flags; static_cast(descriptorSetLayoutBindings.size()), // uint32_t bindingCount; &descriptorSetLayoutBindings[0], // const VkDescriptorSetLayoutBinding* pBindings; }; const Unique descriptorSetLayout (createDescriptorSetLayout(vkd, device, &descriptorSetLayoutInfo)); const vector rawSetLayouts (params.descriptorSetCount, *descriptorSetLayout); vector rawDescriptorSets (params.descriptorSetCount, DE_NULL); const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; *descriptorPool, // VkDescriptorPool descriptorPool; static_cast(rawSetLayouts.size()), // uint32_t descriptorSetCount; &rawSetLayouts[0], // const VkDescriptorSetLayout* pSetLayouts; }; const VkResult result = vkd.allocateDescriptorSets(device, &descriptorSetAllocateInfo, &rawDescriptorSets[0]); if (result != VK_SUCCESS) { ++numErrorsReturned; if (expectOutOfPoolMemoryError && result != VK_ERROR_OUT_OF_POOL_MEMORY) return tcu::TestStatus::fail("Expected VK_ERROR_OUT_OF_POOL_MEMORY but got " + string(getResultName(result)) + " instead"); } else context.getTestContext().getLog() << tcu::TestLog::Message << " Allocation was successful anyway" << tcu::TestLog::EndMessage; } } if (numErrorsReturned == 0u) return tcu::TestStatus::pass("Not validated"); else return tcu::TestStatus::pass("Pass"); } tcu::TestStatus zeroPoolSizeCount(Context& context) { const DeviceInterface& vkd = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // VkDescriptorPoolCreateFlags flags; 1u, // uint32_t maxSets; 0u, // uint32_t poolSizeCount; DE_NULL, // const VkDescriptorPoolSize* pPoolSizes; }; // Test a pool can be created for empty descriptor sets. const Unique descriptorPool(createDescriptorPool(vkd, device, &descriptorPoolCreateInfo)); const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkDescriptorSetLayoutCreateFlags)0, // VkDescriptorSetLayoutCreateFlags flags; 0u, // uint32_t bindingCount; DE_NULL, // const VkDescriptorSetLayoutBinding* pBindings; }; const Unique descriptorSetLayout(createDescriptorSetLayout(vkd, device, &descriptorSetLayoutInfo)); const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; *descriptorPool, // VkDescriptorPool descriptorPool; 1u, // uint32_t descriptorSetCount; &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts; }; // Create an empty descriptor set from the pool. VkDescriptorSet descriptorSet; VkResult result = vkd.allocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet); if (result != VK_SUCCESS) return tcu::TestStatus::fail("Expected vkAllocateDescriptorSets to return VK_SUCCESS but got " + string(getResultName(result)) + " instead"); // Free the empty descriptor set back to the pool. result = vkd.freeDescriptorSets(device, *descriptorPool, 1, &descriptorSet); if (result != VK_SUCCESS) return tcu::TestStatus::fail("Expected vkFreeDescriptorSets to return VK_SUCCESS but got " + string(getResultName(result)) + " instead"); return tcu::TestStatus::pass("Pass"); } } // anonymous tcu::TestCaseGroup* createDescriptorPoolTests (tcu::TestContext& testCtx) { const deUint32 numIterationsHigh = 4096; de::MovePtr descriptorPoolTests( new tcu::TestCaseGroup(testCtx, "descriptor_pool", "Descriptor Pool Tests")); addFunctionCase(descriptorPoolTests.get(), "repeated_reset_short", "Test 2 cycles of vkAllocateDescriptorSets and vkResetDescriptorPool (should pass)", checkSupportFreeDescriptorSets, resetDescriptorPoolTest, ResetDescriptorPoolTestParams(2U)); addFunctionCase(descriptorPoolTests.get(), "repeated_reset_long", "Test many cycles of vkAllocateDescriptorSets and vkResetDescriptorPool", checkSupportFreeDescriptorSets, resetDescriptorPoolTest, ResetDescriptorPoolTestParams(numIterationsHigh)); addFunctionCase(descriptorPoolTests.get(), "repeated_free_reset_short", "Test 2 cycles of vkAllocateDescriptorSets, vkFreeDescriptorSets and vkResetDescriptorPool (should pass)", checkSupportFreeDescriptorSets, resetDescriptorPoolTest, ResetDescriptorPoolTestParams(2U, true)); addFunctionCase(descriptorPoolTests.get(), "repeated_free_reset_long", "Test many cycles of vkAllocateDescriptorSets, vkFreeDescriptorSets and vkResetDescriptorPool", checkSupportFreeDescriptorSets, resetDescriptorPoolTest, ResetDescriptorPoolTestParams(numIterationsHigh, true)); addFunctionCase(descriptorPoolTests.get(), "out_of_pool_memory", "Test that when we run out of descriptors a correct error code is returned", outOfPoolMemoryTest); addFunctionCase(descriptorPoolTests.get(), "zero_pool_size_count", "Test a descriptor pool object can be created with zero pools without error or crash", zeroPoolSizeCount); return descriptorPoolTests.release(); } } // api } // vkt