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