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 deUint32 commandBufferCount;
58 deUint32 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 {
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
endCommandBuffer(const DeviceInterface & vk,const VkCommandBuffer commandBuffer)74 void endCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer)
75 {
76 VK_CHECK(vk.endCommandBuffer(commandBuffer));
77 }
78
79
80 // verify that VkCommandPoolMemoryReservationCreateInfo::commandPoolReservedSize == VkCommandPoolMemoryConsumption::commandPoolReservedSize
verifyCommandPoolReservedSize(Context & context,TestParams testParams)81 tcu::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
verifyCommandPoolAllocEqualsCommandBufferAlloc(Context & context,TestParams testParams)142 tcu::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
checkSupport(Context & context,TestParams testParams)264 void 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
createCommandPoolMemoryReservationTests(tcu::TestContext & testCtx)277 tcu::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