| /*------------------------------------------------------------------------- |
| * 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; |
| }; |
| |
| tcu::TestStatus resetDescriptorPoolTest (Context& context, const ResetDescriptorPoolTestParams params) |
| { |
| const deUint32 numDescriptorSetsPerIter = 2048; |
| 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<VkDescriptorPool> 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<Unique<VkDescriptorSetLayout> > DescriptorSetLayoutPtr; |
| |
| vector<DescriptorSetLayoutPtr> descriptorSetLayouts; |
| descriptorSetLayouts.reserve(numDescriptorSetsPerIter); |
| |
| for (deUint32 ndx = 0; ndx < numDescriptorSetsPerIter; ++ndx) |
| { |
| descriptorSetLayouts.push_back( |
| DescriptorSetLayoutPtr( |
| new Unique<VkDescriptorSetLayout>( |
| createDescriptorSetLayout(vkd, device, |
| &descriptorSetLayoutInfo)))); |
| } |
| |
| vector<VkDescriptorSetLayout> 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<VkDescriptorSet> testSets(numDescriptorSetsPerIter); |
| |
| for (deUint32 ndx = 0; ndx < params.m_numIterations; ++ndx) |
| { |
| // 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 = isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "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<VkDescriptorType>(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<VkDescriptorPool> descriptorPool(createDescriptorPool(vkd, device, &descriptorPoolCreateInfo)); |
| |
| const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding = |
| { |
| 0u, // uint32_t binding; |
| descriptorType, // VkDescriptorType descriptorType; |
| params.bindingDescriptorCount, // uint32_t descriptorCount; |
| VK_SHADER_STAGE_ALL, // VkShaderStageFlags stageFlags; |
| DE_NULL, // const VkSampler* pImmutableSamplers; |
| }; |
| |
| vector<VkDescriptorSetLayoutBinding> 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<deUint32>(descriptorSetLayoutBindings.size()), // uint32_t bindingCount; |
| &descriptorSetLayoutBindings[0], // const VkDescriptorSetLayoutBinding* pBindings; |
| }; |
| |
| const Unique<VkDescriptorSetLayout> descriptorSetLayout (createDescriptorSetLayout(vkd, device, &descriptorSetLayoutInfo)); |
| const vector<VkDescriptorSetLayout> rawSetLayouts (params.descriptorSetCount, *descriptorSetLayout); |
| vector<VkDescriptorSet> 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<deUint32>(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"); |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createDescriptorPoolTests (tcu::TestContext& testCtx) |
| { |
| const deUint32 numIterationsHigh = 4096; |
| |
| de::MovePtr<tcu::TestCaseGroup> 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)", |
| resetDescriptorPoolTest, ResetDescriptorPoolTestParams(2U)); |
| addFunctionCase(descriptorPoolTests.get(), |
| "repeated_reset_long", |
| "Test many cycles of vkAllocateDescriptorSets and vkResetDescriptorPool", |
| resetDescriptorPoolTest, ResetDescriptorPoolTestParams(numIterationsHigh)); |
| addFunctionCase(descriptorPoolTests.get(), |
| "repeated_free_reset_short", |
| "Test 2 cycles of vkAllocateDescriptorSets, vkFreeDescriptorSets and vkResetDescriptorPool (should pass)", |
| resetDescriptorPoolTest, ResetDescriptorPoolTestParams(2U, true)); |
| addFunctionCase(descriptorPoolTests.get(), |
| "repeated_free_reset_long", |
| "Test many cycles of vkAllocateDescriptorSets, vkFreeDescriptorSets and vkResetDescriptorPool", |
| 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); |
| |
| return descriptorPoolTests.release(); |
| } |
| |
| } // api |
| } // vkt |