blob: 3ece9720c27434463033851569710d01e1c24935 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 The Khronos Group 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 Vulkan SC VkCommandPoolMemoryReservationCreateInfo tests
*//*--------------------------------------------------------------------*/
#include "vktCommandPoolMemoryReservationTests.hpp"
#include <set>
#include <vector>
#include <string>
#include "vkRefUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkSafetyCriticalUtil.hpp"
#include "tcuTestLog.hpp"
namespace vkt
{
namespace sc
{
using namespace vk;
namespace
{
typedef de::SharedPtr<vk::Unique<vk::VkEvent> > VkEventSp;
enum CommandPoolReservedSize
{
CPS_UNUSED = 0,
CPS_SMALL,
CPS_BIG
};
struct TestParams
{
CommandPoolReservedSize commandPoolReservedSize;
deUint32 commandBufferCount;
deUint32 iterations;
bool multipleRecording;
};
void beginCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer, VkCommandBufferUsageFlags flags)
{
const VkCommandBufferBeginInfo commandBufBeginParams =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
flags, // VkCommandBufferUsageFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
VK_CHECK(vk.beginCommandBuffer(commandBuffer, &commandBufBeginParams));
}
void endCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer)
{
VK_CHECK(vk.endCommandBuffer(commandBuffer));
}
// verify that VkCommandPoolMemoryReservationCreateInfo::commandPoolReservedSize == VkCommandPoolMemoryConsumption::commandPoolReservedSize
tcu::TestStatus verifyCommandPoolReservedSize (Context& context, TestParams testParams)
{
const VkDevice device = context.getDevice();
const DeviceInterface& vk = context.getDeviceInterface();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
if ( testParams.commandBufferCount > context.getDeviceVulkanSC10Properties().maxCommandPoolCommandBuffers )
TCU_THROW(NotSupportedError, "commandBufferCount is greater than maxCommandPoolCommandBuffers");
VkDeviceSize commandPoolReservedSize = 0u;
switch (testParams.commandPoolReservedSize)
{
case CPS_SMALL:
commandPoolReservedSize = de::max(VkDeviceSize(64u * context.getTestContext().getCommandLine().getCommandDefaultSize()), VkDeviceSize(context.getTestContext().getCommandLine().getCommandPoolMinSize()) );
break;
case CPS_BIG:
commandPoolReservedSize = de::max(VkDeviceSize(8192u * context.getTestContext().getCommandLine().getCommandDefaultSize()), VkDeviceSize(context.getTestContext().getCommandLine().getCommandPoolMinSize()));
break;
default:
TCU_THROW(InternalError, "Unsupported commandPoolReservedSize value");
}
commandPoolReservedSize = de::max(commandPoolReservedSize, VkDeviceSize(testParams.commandBufferCount * context.getTestContext().getCommandLine().getCommandBufferMinSize()));
// Create command pool with declared size
// By connecting our own VkCommandPoolMemoryReservationCreateInfo we avoid getting unknown data from DeviceDriverSC::createCommandPoolHandlerNorm()
VkCommandPoolMemoryReservationCreateInfo cpMemReservationCI =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_RESERVATION_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
commandPoolReservedSize, // VkDeviceSize commandPoolReservedSize
testParams.commandBufferCount // uint32_t commandPoolMaxCommandBuffers
};
const VkCommandPoolCreateInfo cmdPoolParams =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
(const void*)&cpMemReservationCI, // const void* pNext;
0u, // VkCommandPoolCreateFlags flags;
queueFamilyIndex, // deUint32 queueFamilyIndex;
};
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolParams));
// check if size collected by vkGetCommandPoolMemoryConsumption matches size from VkCommandPoolMemoryReservationCreateInfo
VkCommandPoolMemoryConsumption memConsumption =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_CONSUMPTION, // VkStructureType sType
DE_NULL, // void* pNext
0, // VkDeviceSize commandPoolAllocated
0, // VkDeviceSize commandPoolReservedSize
0, // VkDeviceSize commandBufferAllocated
};
vk.getCommandPoolMemoryConsumption(device, *cmdPool, DE_NULL, &memConsumption);
if (commandPoolReservedSize != memConsumption.commandPoolReservedSize)
return tcu::TestStatus::fail("Failed");
return tcu::TestStatus::pass("Pass");
}
// verify that VkCommandPoolMemoryReservationCreateInfo::commandPoolAllocated == sum of VkCommandPoolMemoryConsumption::commandBufferAllocated
tcu::TestStatus verifyCommandPoolAllocEqualsCommandBufferAlloc (Context& context, TestParams testParams)
{
const VkDevice device = context.getDevice();
const DeviceInterface& vk = context.getDeviceInterface();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
// fill command buffers
deUint32 eventCount = 0u;
switch (testParams.commandPoolReservedSize)
{
case CPS_SMALL:
eventCount = 1u;
break;
case CPS_BIG:
eventCount = 32u;
break;
default:
TCU_THROW(InternalError, "Unsupported commandPoolReservedSize value");
}
VkDeviceSize commandPoolReservedSize = de::max(VkDeviceSize(eventCount * context.getTestContext().getCommandLine().getCommandDefaultSize()), VkDeviceSize(context.getTestContext().getCommandLine().getCommandPoolMinSize()));
commandPoolReservedSize = de::max(commandPoolReservedSize, VkDeviceSize(testParams.commandBufferCount * context.getTestContext().getCommandLine().getCommandBufferMinSize()));
// Create command pool with declared size
// By connecting our own VkCommandPoolMemoryReservationCreateInfo we avoid getting unknown data from DeviceDriverSC::createCommandPoolHandlerNorm()
VkCommandPoolMemoryReservationCreateInfo cpMemReservationCI =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_RESERVATION_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
commandPoolReservedSize, // VkDeviceSize commandPoolReservedSize
testParams.commandBufferCount // uint32_t commandPoolMaxCommandBuffers
};
const VkCommandPoolCreateInfo cmdPoolParams =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
(const void*)&cpMemReservationCI, // const void* pNext;
0u, // VkCommandPoolCreateFlags flags;
queueFamilyIndex, // deUint32 queueFamilyIndex;
};
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolParams));
// Allocate command buffers
std::vector<VkCommandBuffer> commandBuffers (testParams.commandBufferCount);
const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*cmdPool, // VkCommandPool commandPool;
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
testParams.commandBufferCount // deUint32 commandBufferCount;
};
VK_CHECK(vk.allocateCommandBuffers(device, &cmdBufferAllocateInfo, commandBuffers.data()));
std::vector<VkEventSp> events;
for (deUint32 ndx = 0; ndx < eventCount; ++ndx)
events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, device))));
bool isOK = true;
for (deUint32 iter = 0; iter < 2 * testParams.iterations; ++iter)
{
// Build command buffers on even iteration
if (0 == iter % 2)
{
if (testParams.multipleRecording)
{
for (deUint32 i = 0; i < testParams.commandBufferCount; ++i)
beginCommandBuffer(vk, commandBuffers[i], 0u);
for (deUint32 i = 0; i < testParams.commandBufferCount; ++i)
for (deUint32 j = 0; j < eventCount; ++j)
vk.cmdSetEvent(commandBuffers[i], events[j]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
for (deUint32 i = 0; i < testParams.commandBufferCount; ++i)
endCommandBuffer(vk, commandBuffers[i]);
}
else
{
for (deUint32 i = 0; i < testParams.commandBufferCount; ++i)
{
beginCommandBuffer(vk, commandBuffers[i], 0u);
for (deUint32 j = 0; j < eventCount; ++j)
vk.cmdSetEvent(commandBuffers[i], events[j]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
endCommandBuffer(vk, commandBuffers[i]);
}
}
}
else // Reset command buffers on odd iteration
{
// leave loop when implementation is not able to perform vkResetCommandPool()
if (context.getDeviceVulkanSC10Properties().commandPoolResetCommandBuffer == VK_FALSE)
break;
vk.resetCommandPool(device, *cmdPool, VkCommandPoolResetFlags(0u));
}
// check if size collected by sum of command buffer allocs is equal to command pool alloc
VkDeviceSize cbAllocSum = 0u;
VkDeviceSize commandPoolAlloc = 0u;
for (deUint32 i = 0; i < testParams.commandBufferCount; ++i)
{
VkCommandPoolMemoryConsumption memConsumption =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_CONSUMPTION, // VkStructureType sType
DE_NULL, // void* pNext
0, // VkDeviceSize commandPoolAllocated
0, // VkDeviceSize commandPoolReservedSize
0, // VkDeviceSize commandBufferAllocated
};
vk.getCommandPoolMemoryConsumption(device, *cmdPool, commandBuffers[i], &memConsumption);
cbAllocSum += memConsumption.commandBufferAllocated;
commandPoolAlloc = memConsumption.commandPoolAllocated;
}
if (cbAllocSum != commandPoolAlloc)
isOK = false;
// if we just performed a vkResetCommandPool() then allocated commandPool memory should be equal to 0
if ( (1 == iter % 2 ) && commandPoolAlloc != 0u )
isOK = false;
}
return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Failed");
}
void checkSupport (Context& context, TestParams testParams)
{
if (testParams.iterations > 1 && context.getDeviceVulkanSC10Properties().commandPoolResetCommandBuffer == VK_FALSE)
TCU_THROW(NotSupportedError, "commandPoolResetCommandBuffer is not supported");
if (testParams.multipleRecording && context.getDeviceVulkanSC10Properties().commandPoolMultipleCommandBuffersRecording == VK_FALSE)
TCU_THROW(NotSupportedError, "commandPoolMultipleCommandBuffersRecording is not supported");
if (testParams.commandBufferCount > context.getDeviceVulkanSC10Properties().maxCommandPoolCommandBuffers)
TCU_THROW(NotSupportedError, "commandBufferCount is greater than maxCommandPoolCommandBuffers");
}
} // anonymous
tcu::TestCaseGroup* createCommandPoolMemoryReservationTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "command_pool_memory_reservation", "Tests verifying memory reservation for command pools in Vulkan SC"));
// add vkGetCommandPoolMemoryConsumption tests
const struct
{
deUint32 commandPoolMaxCommandBuffers;
const char* name;
} maxCommandBuffers[] =
{
{ 1, "cb_single" },
{ 4, "cb_few" },
{ 21, "cb_many" },
{ 256, "cb_min_limit" },
{ 1024, "cb_above_min_limit" },
};
const struct
{
CommandPoolReservedSize commandPoolReservedSize;
const char* name;
} reservedSizes[] =
{
{ CPS_SMALL, "size_small" },
{ CPS_BIG, "size_big" },
};
const struct
{
bool multipleRecording;
const char* name;
} recording[] =
{
{ false, "single_recording" },
{ true, "multiple_recording" },
};
const struct
{
deUint32 count;
const char* name;
} iterations[] =
{
{ 1u, "1" },
{ 2u, "2" },
{ 4u, "8" },
{ 8u, "16" },
};
{
de::MovePtr<tcu::TestCaseGroup> memConGroup(new tcu::TestCaseGroup(testCtx, "memory_consumption", "Testing vkGetCommandPoolMemoryConsumption"));
for (int cbIdx = 0; cbIdx < DE_LENGTH_OF_ARRAY(maxCommandBuffers); ++cbIdx)
{
de::MovePtr<tcu::TestCaseGroup> cbGroup(new tcu::TestCaseGroup(testCtx, maxCommandBuffers[cbIdx].name, ""));
for (int sizeIdx = 0; sizeIdx < DE_LENGTH_OF_ARRAY(reservedSizes); ++sizeIdx)
{
de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, reservedSizes[sizeIdx].name, ""));
for (int simIdx = 0; simIdx < DE_LENGTH_OF_ARRAY(recording); ++simIdx)
{
de::MovePtr<tcu::TestCaseGroup> simGroup(new tcu::TestCaseGroup(testCtx, recording[simIdx].name, ""));
if(!recording[simIdx].multipleRecording)
{
TestParams testParams =
{
reservedSizes[sizeIdx].commandPoolReservedSize,
maxCommandBuffers[cbIdx].commandPoolMaxCommandBuffers,
1u,
false
};
addFunctionCase(simGroup.get(), "reserved_size", "", verifyCommandPoolReservedSize, testParams);
}
for (int iterIdx = 0; iterIdx < DE_LENGTH_OF_ARRAY(iterations); ++iterIdx)
{
TestParams testParams =
{
reservedSizes[sizeIdx].commandPoolReservedSize,
maxCommandBuffers[cbIdx].commandPoolMaxCommandBuffers,
iterations[iterIdx].count,
recording[simIdx].multipleRecording
};
std::ostringstream testName;
testName << "allocated_size_" << iterations[iterIdx].name;
addFunctionCase(simGroup.get(), testName.str(), "", checkSupport, verifyCommandPoolAllocEqualsCommandBufferAlloc, testParams);
}
sizeGroup->addChild(simGroup.release());
}
cbGroup->addChild(sizeGroup.release());
}
memConGroup->addChild(cbGroup.release());
}
group->addChild(memConGroup.release());
}
return group.release();
}
} // sc
} // vkt