1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2021 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Vulkan SC VkCommandPoolMemoryReservationCreateInfo tests 22*//*--------------------------------------------------------------------*/ 23 24#include "vktCommandPoolMemoryReservationTests.hpp" 25 26#include <set> 27#include <vector> 28#include <string> 29 30#include "vkRefUtil.hpp" 31#include "vktTestCaseUtil.hpp" 32#include "vkSafetyCriticalUtil.hpp" 33#include "tcuTestLog.hpp" 34 35namespace vkt 36{ 37namespace sc 38{ 39 40using namespace vk; 41 42namespace 43{ 44 45typedef de::SharedPtr<vk::Unique<vk::VkEvent> > VkEventSp; 46 47enum CommandPoolReservedSize 48{ 49 CPS_UNUSED = 0, 50 CPS_SMALL, 51 CPS_BIG 52}; 53 54struct TestParams 55{ 56 CommandPoolReservedSize commandPoolReservedSize; 57 deUint32 commandBufferCount; 58 deUint32 iterations; 59 bool multipleRecording; 60}; 61 62void beginCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer, VkCommandBufferUsageFlags flags) 63{ 64 const VkCommandBufferBeginInfo commandBufBeginParams = 65 { 66 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; 67 DE_NULL, // const void* pNext; 68 flags, // VkCommandBufferUsageFlags flags; 69 (const VkCommandBufferInheritanceInfo*)DE_NULL, 70 }; 71 VK_CHECK(vk.beginCommandBuffer(commandBuffer, &commandBufBeginParams)); 72} 73 74void endCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer) 75{ 76 VK_CHECK(vk.endCommandBuffer(commandBuffer)); 77} 78 79 80// verify that VkCommandPoolMemoryReservationCreateInfo::commandPoolReservedSize == VkCommandPoolMemoryConsumption::commandPoolReservedSize 81tcu::TestStatus verifyCommandPoolReservedSize (Context& context, TestParams testParams) 82{ 83 const VkDevice device = context.getDevice(); 84 const DeviceInterface& vk = context.getDeviceInterface(); 85 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 86 87 if ( testParams.commandBufferCount > context.getDeviceVulkanSC10Properties().maxCommandPoolCommandBuffers ) 88 TCU_THROW(NotSupportedError, "commandBufferCount is greater than maxCommandPoolCommandBuffers"); 89 90 VkDeviceSize commandPoolReservedSize = 0u; 91 switch (testParams.commandPoolReservedSize) 92 { 93 case CPS_SMALL: 94 commandPoolReservedSize = de::max(VkDeviceSize(64u * context.getTestContext().getCommandLine().getCommandDefaultSize()), VkDeviceSize(context.getTestContext().getCommandLine().getCommandPoolMinSize()) ); 95 break; 96 case CPS_BIG: 97 commandPoolReservedSize = de::max(VkDeviceSize(8192u * context.getTestContext().getCommandLine().getCommandDefaultSize()), VkDeviceSize(context.getTestContext().getCommandLine().getCommandPoolMinSize())); 98 break; 99 default: 100 TCU_THROW(InternalError, "Unsupported commandPoolReservedSize value"); 101 } 102 commandPoolReservedSize = de::max(commandPoolReservedSize, VkDeviceSize(testParams.commandBufferCount * context.getTestContext().getCommandLine().getCommandBufferMinSize())); 103 104 // Create command pool with declared size 105 // By connecting our own VkCommandPoolMemoryReservationCreateInfo we avoid getting unknown data from DeviceDriverSC::createCommandPoolHandlerNorm() 106 VkCommandPoolMemoryReservationCreateInfo cpMemReservationCI = 107 { 108 VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_RESERVATION_CREATE_INFO, // VkStructureType sType 109 DE_NULL, // const void* pNext 110 commandPoolReservedSize, // VkDeviceSize commandPoolReservedSize 111 testParams.commandBufferCount // uint32_t commandPoolMaxCommandBuffers 112 }; 113 114 const VkCommandPoolCreateInfo cmdPoolParams = 115 { 116 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; 117 (const void*)&cpMemReservationCI, // const void* pNext; 118 0u, // VkCommandPoolCreateFlags flags; 119 queueFamilyIndex, // deUint32 queueFamilyIndex; 120 }; 121 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolParams)); 122 123 // check if size collected by vkGetCommandPoolMemoryConsumption matches size from VkCommandPoolMemoryReservationCreateInfo 124 125 VkCommandPoolMemoryConsumption memConsumption = 126 { 127 VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_CONSUMPTION, // VkStructureType sType 128 DE_NULL, // void* pNext 129 0, // VkDeviceSize commandPoolAllocated 130 0, // VkDeviceSize commandPoolReservedSize 131 0, // VkDeviceSize commandBufferAllocated 132 }; 133 134 vk.getCommandPoolMemoryConsumption(device, *cmdPool, DE_NULL, &memConsumption); 135 136 if (commandPoolReservedSize != memConsumption.commandPoolReservedSize) 137 return tcu::TestStatus::fail("Failed"); 138 return tcu::TestStatus::pass("Pass"); 139} 140 141// verify that VkCommandPoolMemoryReservationCreateInfo::commandPoolAllocated == sum of VkCommandPoolMemoryConsumption::commandBufferAllocated 142tcu::TestStatus verifyCommandPoolAllocEqualsCommandBufferAlloc (Context& context, TestParams testParams) 143{ 144 const VkDevice device = context.getDevice(); 145 const DeviceInterface& vk = context.getDeviceInterface(); 146 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 147 148 // fill command buffers 149 deUint32 eventCount = 0u; 150 switch (testParams.commandPoolReservedSize) 151 { 152 case CPS_SMALL: 153 eventCount = 1u; 154 break; 155 case CPS_BIG: 156 eventCount = 32u; 157 break; 158 default: 159 TCU_THROW(InternalError, "Unsupported commandPoolReservedSize value"); 160 } 161 VkDeviceSize commandPoolReservedSize = de::max(VkDeviceSize(eventCount * context.getTestContext().getCommandLine().getCommandDefaultSize()), VkDeviceSize(context.getTestContext().getCommandLine().getCommandPoolMinSize())); 162 commandPoolReservedSize = de::max(commandPoolReservedSize, VkDeviceSize(testParams.commandBufferCount * context.getTestContext().getCommandLine().getCommandBufferMinSize())); 163 164 // Create command pool with declared size 165 // By connecting our own VkCommandPoolMemoryReservationCreateInfo we avoid getting unknown data from DeviceDriverSC::createCommandPoolHandlerNorm() 166 VkCommandPoolMemoryReservationCreateInfo cpMemReservationCI = 167 { 168 VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_RESERVATION_CREATE_INFO, // VkStructureType sType 169 DE_NULL, // const void* pNext 170 commandPoolReservedSize, // VkDeviceSize commandPoolReservedSize 171 testParams.commandBufferCount // uint32_t commandPoolMaxCommandBuffers 172 }; 173 174 const VkCommandPoolCreateInfo cmdPoolParams = 175 { 176 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; 177 (const void*)&cpMemReservationCI, // const void* pNext; 178 0u, // VkCommandPoolCreateFlags flags; 179 queueFamilyIndex, // deUint32 queueFamilyIndex; 180 }; 181 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolParams)); 182 183 // Allocate command buffers 184 std::vector<Move<VkCommandBuffer>> commandBuffers (testParams.commandBufferCount); 185 const VkCommandBufferAllocateInfo cmdBufferAllocateInfo = 186 { 187 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; 188 DE_NULL, // const void* pNext; 189 *cmdPool, // VkCommandPool commandPool; 190 VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level; 191 testParams.commandBufferCount // deUint32 commandBufferCount; 192 }; 193 allocateCommandBuffers(vk, device, &cmdBufferAllocateInfo, commandBuffers.data()); 194 195 std::vector<VkEventSp> events; 196 for (deUint32 ndx = 0; ndx < eventCount; ++ndx) 197 events.push_back(VkEventSp(new vk::Unique<VkEvent>(createEvent(vk, device)))); 198 199 bool isOK = true; 200 for (deUint32 iter = 0; iter < 2 * testParams.iterations; ++iter) 201 { 202 // Build command buffers on even iteration 203 if (0 == iter % 2) 204 { 205 if (testParams.multipleRecording) 206 { 207 for (deUint32 i = 0; i < testParams.commandBufferCount; ++i) 208 beginCommandBuffer(vk, commandBuffers[i].get(), 0u); 209 210 for (deUint32 i = 0; i < testParams.commandBufferCount; ++i) 211 for (deUint32 j = 0; j < eventCount; ++j) 212 vk.cmdSetEvent(commandBuffers[i].get(), events[j]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); 213 214 for (deUint32 i = 0; i < testParams.commandBufferCount; ++i) 215 endCommandBuffer(vk, commandBuffers[i].get()); 216 } 217 else 218 { 219 for (deUint32 i = 0; i < testParams.commandBufferCount; ++i) 220 { 221 beginCommandBuffer(vk, commandBuffers[i].get(), 0u); 222 223 for (deUint32 j = 0; j < eventCount; ++j) 224 vk.cmdSetEvent(commandBuffers[i].get(), events[j]->get(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); 225 226 endCommandBuffer(vk, commandBuffers[i].get()); 227 } 228 } 229 } 230 else // Reset command buffers on odd iteration 231 { 232 // leave loop when implementation is not able to perform vkResetCommandPool() 233 if (context.getDeviceVulkanSC10Properties().commandPoolResetCommandBuffer == VK_FALSE) 234 break; 235 vk.resetCommandPool(device, *cmdPool, VkCommandPoolResetFlags(0u)); 236 } 237 238 // check if size collected by sum of command buffer allocs is equal to command pool alloc 239 VkDeviceSize cbAllocSum = 0u; 240 VkDeviceSize commandPoolAlloc = 0u; 241 for (deUint32 i = 0; i < testParams.commandBufferCount; ++i) 242 { 243 VkCommandPoolMemoryConsumption memConsumption = 244 { 245 VK_STRUCTURE_TYPE_COMMAND_POOL_MEMORY_CONSUMPTION, // VkStructureType sType 246 DE_NULL, // void* pNext 247 0, // VkDeviceSize commandPoolAllocated 248 0, // VkDeviceSize commandPoolReservedSize 249 0, // VkDeviceSize commandBufferAllocated 250 }; 251 vk.getCommandPoolMemoryConsumption(device, *cmdPool, commandBuffers[i].get(), &memConsumption); 252 cbAllocSum += memConsumption.commandBufferAllocated; 253 commandPoolAlloc = memConsumption.commandPoolAllocated; 254 } 255 if (cbAllocSum != commandPoolAlloc) 256 isOK = false; 257 // if we just performed a vkResetCommandPool() then allocated commandPool memory should be equal to 0 258 if ( (1 == iter % 2 ) && commandPoolAlloc != 0u ) 259 isOK = false; 260 } 261 return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Failed"); 262} 263 264void checkSupport (Context& context, TestParams testParams) 265{ 266 if (testParams.iterations > 1 && context.getDeviceVulkanSC10Properties().commandPoolResetCommandBuffer == VK_FALSE) 267 TCU_THROW(NotSupportedError, "commandPoolResetCommandBuffer is not supported"); 268 if (testParams.multipleRecording && context.getDeviceVulkanSC10Properties().commandPoolMultipleCommandBuffersRecording == VK_FALSE) 269 TCU_THROW(NotSupportedError, "commandPoolMultipleCommandBuffersRecording is not supported"); 270 if (testParams.commandBufferCount > context.getDeviceVulkanSC10Properties().maxCommandPoolCommandBuffers) 271 TCU_THROW(NotSupportedError, "commandBufferCount is greater than maxCommandPoolCommandBuffers"); 272 273} 274 275} // anonymous 276 277tcu::TestCaseGroup* createCommandPoolMemoryReservationTests (tcu::TestContext& testCtx) 278{ 279 // Tests verifying memory reservation for command pools in Vulkan SC 280 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "command_pool_memory_reservation")); 281 282 // add vkGetCommandPoolMemoryConsumption tests 283 const struct 284 { 285 deUint32 commandPoolMaxCommandBuffers; 286 const char* name; 287 } maxCommandBuffers[] = 288 { 289 { 1, "cb_single" }, 290 { 4, "cb_few" }, 291 { 21, "cb_many" }, 292 { 256, "cb_min_limit" }, 293 { 1024, "cb_above_min_limit" }, 294 }; 295 296 const struct 297 { 298 CommandPoolReservedSize commandPoolReservedSize; 299 const char* name; 300 } reservedSizes[] = 301 { 302 { CPS_SMALL, "size_small" }, 303 { CPS_BIG, "size_big" }, 304 }; 305 306 const struct 307 { 308 bool multipleRecording; 309 const char* name; 310 } recording[] = 311 { 312 { false, "single_recording" }, 313 { true, "multiple_recording" }, 314 }; 315 316 const struct 317 { 318 deUint32 count; 319 const char* name; 320 } iterations[] = 321 { 322 { 1u, "1" }, 323 { 2u, "2" }, 324 { 4u, "8" }, 325 { 8u, "16" }, 326 }; 327 328 { 329 de::MovePtr<tcu::TestCaseGroup> memConGroup(new tcu::TestCaseGroup(testCtx, "memory_consumption", "Testing vkGetCommandPoolMemoryConsumption")); 330 331 for (int cbIdx = 0; cbIdx < DE_LENGTH_OF_ARRAY(maxCommandBuffers); ++cbIdx) 332 { 333 de::MovePtr<tcu::TestCaseGroup> cbGroup(new tcu::TestCaseGroup(testCtx, maxCommandBuffers[cbIdx].name)); 334 335 for (int sizeIdx = 0; sizeIdx < DE_LENGTH_OF_ARRAY(reservedSizes); ++sizeIdx) 336 { 337 de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, reservedSizes[sizeIdx].name)); 338 339 for (int simIdx = 0; simIdx < DE_LENGTH_OF_ARRAY(recording); ++simIdx) 340 { 341 de::MovePtr<tcu::TestCaseGroup> simGroup(new tcu::TestCaseGroup(testCtx, recording[simIdx].name)); 342 343 if(!recording[simIdx].multipleRecording) 344 { 345 TestParams testParams = 346 { 347 reservedSizes[sizeIdx].commandPoolReservedSize, 348 maxCommandBuffers[cbIdx].commandPoolMaxCommandBuffers, 349 1u, 350 false 351 }; 352 addFunctionCase(simGroup.get(), "reserved_size", verifyCommandPoolReservedSize, testParams); 353 } 354 355 for (int iterIdx = 0; iterIdx < DE_LENGTH_OF_ARRAY(iterations); ++iterIdx) 356 { 357 TestParams testParams = 358 { 359 reservedSizes[sizeIdx].commandPoolReservedSize, 360 maxCommandBuffers[cbIdx].commandPoolMaxCommandBuffers, 361 iterations[iterIdx].count, 362 recording[simIdx].multipleRecording 363 }; 364 std::ostringstream testName; 365 testName << "allocated_size_" << iterations[iterIdx].name; 366 addFunctionCase(simGroup.get(), testName.str(), checkSupport, verifyCommandPoolAllocEqualsCommandBufferAlloc, testParams); 367 } 368 369 sizeGroup->addChild(simGroup.release()); 370 } 371 cbGroup->addChild(sizeGroup.release()); 372 } 373 memConGroup->addChild(cbGroup.release()); 374 } 375 group->addChild(memConGroup.release()); 376 } 377 378 return group.release(); 379} 380 381} // sc 382 383} // vkt 384