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 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "command_pool_memory_reservation", "Tests verifying memory reservation for command pools in Vulkan SC"));
280
281 // add vkGetCommandPoolMemoryConsumption tests
282 const struct
283 {
284 deUint32 commandPoolMaxCommandBuffers;
285 const char* name;
286 } maxCommandBuffers[] =
287 {
288 { 1, "cb_single" },
289 { 4, "cb_few" },
290 { 21, "cb_many" },
291 { 256, "cb_min_limit" },
292 { 1024, "cb_above_min_limit" },
293 };
294
295 const struct
296 {
297 CommandPoolReservedSize commandPoolReservedSize;
298 const char* name;
299 } reservedSizes[] =
300 {
301 { CPS_SMALL, "size_small" },
302 { CPS_BIG, "size_big" },
303 };
304
305 const struct
306 {
307 bool multipleRecording;
308 const char* name;
309 } recording[] =
310 {
311 { false, "single_recording" },
312 { true, "multiple_recording" },
313 };
314
315 const struct
316 {
317 deUint32 count;
318 const char* name;
319 } iterations[] =
320 {
321 { 1u, "1" },
322 { 2u, "2" },
323 { 4u, "8" },
324 { 8u, "16" },
325 };
326
327 {
328 de::MovePtr<tcu::TestCaseGroup> memConGroup(new tcu::TestCaseGroup(testCtx, "memory_consumption", "Testing vkGetCommandPoolMemoryConsumption"));
329
330 for (int cbIdx = 0; cbIdx < DE_LENGTH_OF_ARRAY(maxCommandBuffers); ++cbIdx)
331 {
332 de::MovePtr<tcu::TestCaseGroup> cbGroup(new tcu::TestCaseGroup(testCtx, maxCommandBuffers[cbIdx].name, ""));
333
334 for (int sizeIdx = 0; sizeIdx < DE_LENGTH_OF_ARRAY(reservedSizes); ++sizeIdx)
335 {
336 de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, reservedSizes[sizeIdx].name, ""));
337
338 for (int simIdx = 0; simIdx < DE_LENGTH_OF_ARRAY(recording); ++simIdx)
339 {
340 de::MovePtr<tcu::TestCaseGroup> simGroup(new tcu::TestCaseGroup(testCtx, recording[simIdx].name, ""));
341
342 if(!recording[simIdx].multipleRecording)
343 {
344 TestParams testParams =
345 {
346 reservedSizes[sizeIdx].commandPoolReservedSize,
347 maxCommandBuffers[cbIdx].commandPoolMaxCommandBuffers,
348 1u,
349 false
350 };
351 addFunctionCase(simGroup.get(), "reserved_size", "", verifyCommandPoolReservedSize, testParams);
352 }
353
354 for (int iterIdx = 0; iterIdx < DE_LENGTH_OF_ARRAY(iterations); ++iterIdx)
355 {
356 TestParams testParams =
357 {
358 reservedSizes[sizeIdx].commandPoolReservedSize,
359 maxCommandBuffers[cbIdx].commandPoolMaxCommandBuffers,
360 iterations[iterIdx].count,
361 recording[simIdx].multipleRecording
362 };
363 std::ostringstream testName;
364 testName << "allocated_size_" << iterations[iterIdx].name;
365 addFunctionCase(simGroup.get(), testName.str(), "", checkSupport, verifyCommandPoolAllocEqualsCommandBufferAlloc, testParams);
366 }
367
368 sizeGroup->addChild(simGroup.release());
369 }
370 cbGroup->addChild(sizeGroup.release());
371 }
372 memConGroup->addChild(cbGroup.release());
373 }
374 group->addChild(memConGroup.release());
375 }
376
377 return group.release();
378 }
379
380 } // sc
381
382 } // vkt
383