• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  *  Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Vulkan Buffers Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktApiBufferTests.hpp"
26 
27 #include "deStringUtil.hpp"
28 #include "gluVarType.hpp"
29 #include "tcuTestLog.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vktTestCase.hpp"
35 
36 namespace vkt
37 {
38 namespace api
39 {
40 namespace
41 {
42 using namespace vk;
43 
44 struct BufferCaseParameters
45 {
46 	VkBufferUsageFlags	usage;
47 	VkBufferCreateFlags	flags;
48 	VkSharingMode		sharingMode;
49 };
50 
51 class BufferTestInstance : public TestInstance
52 {
53 public:
BufferTestInstance(Context & ctx,BufferCaseParameters testCase)54 								BufferTestInstance			(Context&				ctx,
55 															 BufferCaseParameters	testCase)
56 									: TestInstance		(ctx)
57 									, m_testCase		(testCase)
58 									, m_sparseContext	(createSparseContext())
59 								{}
60 	virtual tcu::TestStatus		iterate						(void);
61 	tcu::TestStatus				bufferCreateAndAllocTest	(VkDeviceSize		size);
62 
63 private:
64 	BufferCaseParameters		m_testCase;
65 
66 private:
67 	// Custom context for sparse cases
68 	struct SparseContext
69 	{
SparseContextvkt::api::__anon95a962c30111::BufferTestInstance::SparseContext70 		SparseContext (Move<VkDevice>& device, const deUint32 queueFamilyIndex, const InstanceInterface& interface)
71 		: m_device				(device)
72 		, m_queueFamilyIndex	(queueFamilyIndex)
73 		, m_deviceInterface		(interface, *m_device)
74 		{}
75 
76 		Unique<VkDevice>	m_device;
77 		const deUint32		m_queueFamilyIndex;
78 		DeviceDriver		m_deviceInterface;
79 	};
80 
81 	de::UniquePtr<SparseContext>	m_sparseContext;
82 
83 	// Wrapper functions around m_context calls to support sparse cases.
getPhysicalDevice(void) const84 	VkPhysicalDevice				getPhysicalDevice (void) const
85 	{
86 		// Same in sparse and regular case
87 		return m_context.getPhysicalDevice();
88 	}
89 
getDevice(void) const90 	VkDevice						getDevice (void) const
91 	{
92 		if (m_sparseContext)
93 			return *(m_sparseContext->m_device);
94 
95 		return m_context.getDevice();
96 	}
97 
getInstanceInterface(void) const98 	const InstanceInterface&		getInstanceInterface (void) const
99 	{
100 		// Same in sparse and regular case
101 		return m_context.getInstanceInterface();
102 	}
103 
getDeviceInterface(void) const104 	const DeviceInterface&			getDeviceInterface (void) const
105 	{
106 		if (m_sparseContext)
107 			return m_sparseContext->m_deviceInterface;
108 
109 		return m_context.getDeviceInterface();
110 	}
111 
getUniversalQueueFamilyIndex(void) const112 	deUint32						getUniversalQueueFamilyIndex (void) const
113 	{
114 		if (m_sparseContext)
115 			return m_sparseContext->m_queueFamilyIndex;
116 
117 		return m_context.getUniversalQueueFamilyIndex();
118 	}
119 
findQueueFamilyIndexWithCaps(const InstanceInterface & vkInstance,VkPhysicalDevice physicalDevice,VkQueueFlags requiredCaps)120 	static deUint32					findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
121 	{
122 		const std::vector<VkQueueFamilyProperties>	queueProps	= getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
123 
124 		for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
125 		{
126 			if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
127 				return (deUint32)queueNdx;
128 		}
129 
130 		TCU_THROW(NotSupportedError, "No matching queue found");
131 	}
132 
133 	// Create the sparseContext
createSparseContext(void) const134 	SparseContext*					createSparseContext	(void) const
135 	{
136 		if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
137 			(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
138 			(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
139 		{
140 			const InstanceInterface&		vk				= getInstanceInterface();
141 			const VkPhysicalDevice			physicalDevice	= getPhysicalDevice();
142 			const VkPhysicalDeviceFeatures	deviceFeatures	= getPhysicalDeviceFeatures(vk, physicalDevice);
143 
144 			const deUint32 queueIndex = findQueueFamilyIndexWithCaps(vk, physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT);
145 
146 			VkDeviceQueueCreateInfo			queueInfo;
147 			VkDeviceCreateInfo				deviceInfo;
148 			const float						queuePriority	= 1.0f;
149 
150 			deMemset(&queueInfo,	0, sizeof(queueInfo));
151 			deMemset(&deviceInfo,	0, sizeof(deviceInfo));
152 
153 			queueInfo.sType							= VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
154 			queueInfo.pNext							= DE_NULL;
155 			queueInfo.flags							= (VkDeviceQueueCreateFlags)0u;
156 			queueInfo.queueFamilyIndex				= queueIndex;
157 			queueInfo.queueCount					= 1u;
158 			queueInfo.pQueuePriorities				= &queuePriority;
159 
160 			deviceInfo.sType						= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
161 			deviceInfo.pNext						= DE_NULL;
162 			deviceInfo.queueCreateInfoCount			= 1u;
163 			deviceInfo.pQueueCreateInfos			= &queueInfo;
164 			deviceInfo.enabledExtensionCount		= 0u;
165 			deviceInfo.ppEnabledExtensionNames		= DE_NULL;
166 			deviceInfo.enabledLayerCount			= 0u;
167 			deviceInfo.ppEnabledLayerNames			= DE_NULL;
168 			deviceInfo.pEnabledFeatures				= &deviceFeatures;
169 
170 			Move<VkDevice>	device = createDevice(vk, physicalDevice, &deviceInfo);
171 
172 			return new SparseContext(device, queueIndex, vk);
173 		}
174 
175 		return DE_NULL;
176 	}
177 };
178 
179 class BuffersTestCase : public TestCase
180 {
181 public:
BuffersTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferCaseParameters testCase)182 							BuffersTestCase		(tcu::TestContext&		testCtx,
183 												 const std::string&		name,
184 												 const std::string&		description,
185 												 BufferCaseParameters	testCase)
186 								: TestCase(testCtx, name, description)
187 								, m_testCase(testCase)
188 							{}
189 
~BuffersTestCase(void)190 	virtual					~BuffersTestCase	(void) {}
createInstance(Context & ctx) const191 	virtual TestInstance*	createInstance		(Context&				ctx) const
192 							{
193 								tcu::TestLog& log	= m_testCtx.getLog();
194 								log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
195 								return new BufferTestInstance(ctx, m_testCase);
196 							}
197 
198 private:
199 	BufferCaseParameters		m_testCase;
200 };
201 
alignDeviceSize(VkDeviceSize val,VkDeviceSize align)202 inline VkDeviceSize alignDeviceSize (VkDeviceSize val, VkDeviceSize align)
203 {
204 	DE_ASSERT(deIsPowerOfTwo64(align));
205 	DE_ASSERT(val + align >= val);				// crash on overflow
206 	return (val + align - 1) & ~(align - 1);
207 }
208 
bufferCreateAndAllocTest(VkDeviceSize size)209 tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
210 {
211 	const VkPhysicalDevice					vkPhysicalDevice	= getPhysicalDevice();
212 	const InstanceInterface&				vkInstance			= getInstanceInterface();
213 	const VkDevice							vkDevice			= getDevice();
214 	const DeviceInterface&					vk					= getDeviceInterface();
215 	const deUint32							queueFamilyIndex	= getUniversalQueueFamilyIndex();
216 	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
217 	const VkPhysicalDeviceLimits			limits				= getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits;
218 	Move<VkBuffer>							buffer;
219 	Move<VkDeviceMemory>					memory;
220 	VkMemoryRequirements					memReqs;
221 
222 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
223 		size = std::min(size, limits.sparseAddressSpaceSize);
224 
225 	// Create the test buffer and a memory allocation for it
226 	{
227 		// Create a minimal buffer first to get the supported memory types
228 		VkBufferCreateInfo bufferParams =
229 		{
230 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType        sType;
231 			DE_NULL,								// const void*            pNext;
232 			m_testCase.flags,						// VkBufferCreateFlags    flags;
233 			1u,										// VkDeviceSize           size;
234 			m_testCase.usage,						// VkBufferUsageFlags     usage;
235 			m_testCase.sharingMode,					// VkSharingMode          sharingMode;
236 			1u,										// uint32_t               queueFamilyIndexCount;
237 			&queueFamilyIndex,						// const uint32_t*        pQueueFamilyIndices;
238 		};
239 
240 		buffer = createBuffer(vk, vkDevice, &bufferParams);
241 		vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);
242 
243 		const deUint32		heapTypeIndex	= (deUint32)deCtz32(memReqs.memoryTypeBits);
244 		const VkMemoryType	memoryType		= memoryProperties.memoryTypes[heapTypeIndex];
245 		const VkMemoryHeap	memoryHeap		= memoryProperties.memoryHeaps[memoryType.heapIndex];
246 		const VkDeviceSize	maxBufferSize	= alignDeviceSize(memoryHeap.size >> 1, memReqs.alignment);
247 		const deUint32		shrinkBits		= 4;	// number of bits to shift when reducing the size with each iteration
248 
249 		size = std::min(size, maxBufferSize);
250 
251 		while (*memory == DE_NULL)
252 		{
253 			// Create the buffer
254 			{
255 				VkResult result		= VK_ERROR_OUT_OF_HOST_MEMORY;
256 				VkBuffer rawBuffer	= DE_NULL;
257 
258 				bufferParams.size	= size;
259 				buffer				= Move<VkBuffer>();		// free the previous buffer, if any
260 				result				= vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer);
261 
262 				if (result != VK_SUCCESS)
263 				{
264 					size = alignDeviceSize(size >> shrinkBits, memReqs.alignment);
265 
266 					if (size == 0 || bufferParams.size == memReqs.alignment)
267 						return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")");
268 
269 					continue;	// didn't work, try with a smaller buffer
270 				}
271 
272 				buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL));
273 			}
274 
275 			vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);	// get the proper size requirement
276 
277 			if (size > memReqs.size)
278 			{
279 				std::ostringstream errorMsg;
280 				errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
281 				return tcu::TestStatus::fail(errorMsg.str());
282 			}
283 
284 			// Allocate the memory
285 			{
286 				VkResult		result			= VK_ERROR_OUT_OF_HOST_MEMORY;
287 				VkDeviceMemory	rawMemory		= DE_NULL;
288 
289 				const VkMemoryAllocateInfo memAlloc =
290 				{
291 					VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,		// VkStructureType    sType;
292 					NULL,										// const void*        pNext;
293 					memReqs.size,								// VkDeviceSize       allocationSize;
294 					heapTypeIndex,								// uint32_t           memoryTypeIndex;
295 				};
296 
297 				result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
298 
299 				if (result != VK_SUCCESS)
300 				{
301 					size = alignDeviceSize(size >> shrinkBits, memReqs.alignment);
302 
303 					if (size == 0 || memReqs.size == memReqs.alignment)
304 						return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory");
305 
306 					continue;	// didn't work, try with a smaller allocation (and a smaller buffer)
307 				}
308 
309 				memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
310 			}
311 		} // while
312 	}
313 
314 	// Bind the memory
315 	if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0)
316 	{
317 		VkQueue								queue					= DE_NULL;
318 
319 		vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue);
320 
321 		const VkSparseMemoryBind			sparseMemoryBind		=
322 		{
323 			0,										// VkDeviceSize								resourceOffset;
324 			memReqs.size,							// VkDeviceSize								size;
325 			*memory,								// VkDeviceMemory							memory;
326 			0,										// VkDeviceSize								memoryOffset;
327 			0										// VkSparseMemoryBindFlags					flags;
328 		};
329 
330 		const VkSparseBufferMemoryBindInfo	sparseBufferMemoryBindInfo	=
331 		{
332 			*buffer,							// VkBuffer									buffer;
333 			1u,										// deUint32									bindCount;
334 			&sparseMemoryBind						// const VkSparseMemoryBind*				pBinds;
335 		};
336 
337 		const VkBindSparseInfo				bindSparseInfo			=
338 		{
339 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,		// VkStructureType							sType;
340 			DE_NULL,								// const void*								pNext;
341 			0,										// deUint32									waitSemaphoreCount;
342 			DE_NULL,								// const VkSemaphore*						pWaitSemaphores;
343 			1u,										// deUint32									bufferBindCount;
344 			&sparseBufferMemoryBindInfo,			// const VkSparseBufferMemoryBindInfo*		pBufferBinds;
345 			0,										// deUint32									imageOpaqueBindCount;
346 			DE_NULL,								// const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
347 			0,										// deUint32									imageBindCount;
348 			DE_NULL,								// const VkSparseImageMemoryBindInfo*		pImageBinds;
349 			0,										// deUint32									signalSemaphoreCount;
350 			DE_NULL,								// const VkSemaphore*						pSignalSemaphores;
351 		};
352 
353 		const VkFenceCreateInfo fenceParams =
354 		{
355 			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
356 			DE_NULL,								// const void*			pNext;
357 			0u										// VkFenceCreateFlags	flags;
358 		};
359 
360 		const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams));
361 
362 		if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
363 			return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
364 
365 		VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
366 	}
367 	else
368 	{
369 		if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
370 			return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
371 	}
372 
373 	return tcu::TestStatus::pass("Pass");
374 }
375 
iterate(void)376 tcu::TestStatus BufferTestInstance::iterate (void)
377 {
378 	const VkPhysicalDeviceFeatures&	physicalDeviceFeatures	= getPhysicalDeviceFeatures(getInstanceInterface(), getPhysicalDevice());
379 
380 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding)
381 		TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
382 
383 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer)
384 		TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
385 
386 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased)
387 		TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
388 
389 	const VkDeviceSize testSizes[] =
390 	{
391 		1,
392 		1181,
393 		15991,
394 		16384,
395 		~0ull,		// try to exercise a very large buffer too (will be clamped to a sensible size later)
396 	};
397 
398 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i)
399 	{
400 		const tcu::TestStatus testStatus = bufferCreateAndAllocTest(testSizes[i]);
401 
402 		if (testStatus.getCode() != QP_TEST_RESULT_PASS)
403 			return testStatus;
404 	}
405 
406 	return tcu::TestStatus::pass("Pass");
407 }
408 
409 } // anonymous
410 
createBufferTests(tcu::TestContext & testCtx)411  tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
412 {
413 	const VkBufferUsageFlags bufferUsageModes[] =
414 	{
415 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
416 		VK_BUFFER_USAGE_TRANSFER_DST_BIT,
417 		VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
418 		VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
419 		VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
420 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
421 		VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
422 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
423 		VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
424 	};
425 
426 	// \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag.
427 	const VkBufferCreateFlags bufferCreateFlags[] =
428 	{
429 		0,
430 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
431 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT	|	VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
432 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT	|												VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
433 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT	|	VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT	|	VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
434 	};
435 
436 	de::MovePtr<tcu::TestCaseGroup>	buffersTests	(new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
437 
438 	const deUint32 maximumValueOfBufferUsageFlags	= (1u << (DE_LENGTH_OF_ARRAY(bufferUsageModes) - 1)) - 1u;
439 
440 	for (deUint32 bufferCreateFlagsNdx = 0u; bufferCreateFlagsNdx < DE_LENGTH_OF_ARRAY(bufferCreateFlags); bufferCreateFlagsNdx++)
441 	for (deUint32 combinedBufferUsageFlags = 1u; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++)
442 	{
443 		const BufferCaseParameters	testParams =
444 		{
445 			combinedBufferUsageFlags,
446 			bufferCreateFlags[bufferCreateFlagsNdx],
447 			VK_SHARING_MODE_EXCLUSIVE
448 		};
449 		std::ostringstream	testName;
450 		std::ostringstream	testDescription;
451 		testName << "create_buffer_" << combinedBufferUsageFlags << "_" << testParams.flags;
452 		testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << testParams.flags;
453 		buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams));
454 	}
455 
456 	return buffersTests.release();
457 }
458 
459 } // api
460 } // vk
461