• 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 	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