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 "vktTestCase.hpp"
34 
35 namespace vkt
36 {
37 
38 using namespace vk;
39 
40 namespace api
41 {
42 
43 namespace
44 {
45 
46 static const deUint32	MAX_BUFFER_SIZE_DIVISOR	= 16;
47 
48 struct BufferCaseParameters
49 {
50 	VkBufferUsageFlags	usage;
51 	VkBufferCreateFlags	flags;
52 	VkSharingMode		sharingMode;
53 };
54 
55 class BufferTestInstance : public TestInstance
56 {
57 public:
BufferTestInstance(Context & ctx,BufferCaseParameters testCase)58 								BufferTestInstance			(Context&				ctx,
59 															 BufferCaseParameters	testCase)
60 									: TestInstance	(ctx)
61 									, m_testCase	(testCase)
62 								{}
63 	virtual tcu::TestStatus		iterate						(void);
64 	tcu::TestStatus				bufferCreateAndAllocTest	(VkDeviceSize		size);
65 
66 private:
67 	BufferCaseParameters		m_testCase;
68 };
69 
70 class BuffersTestCase : public TestCase
71 {
72 public:
BuffersTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferCaseParameters testCase)73 							BuffersTestCase		(tcu::TestContext&		testCtx,
74 												 const std::string&		name,
75 												 const std::string&		description,
76 												 BufferCaseParameters	testCase)
77 								: TestCase(testCtx, name, description)
78 								, m_testCase(testCase)
79 							{}
80 
~BuffersTestCase(void)81 	virtual					~BuffersTestCase	(void) {}
createInstance(Context & ctx) const82 	virtual TestInstance*	createInstance		(Context&				ctx) const
83 							{
84 								tcu::TestLog& log	= m_testCtx.getLog();
85 								log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
86 								return new BufferTestInstance(ctx, m_testCase);
87 							}
88 
89 private:
90 	BufferCaseParameters		m_testCase;
91 };
92 
bufferCreateAndAllocTest(VkDeviceSize size)93  tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
94 {
95 	const VkPhysicalDevice		vkPhysicalDevice	= m_context.getPhysicalDevice();
96 	const InstanceInterface&	vkInstance			= m_context.getInstanceInterface();
97 	const VkDevice				vkDevice			= m_context.getDevice();
98 	const DeviceInterface&		vk					= m_context.getDeviceInterface();
99 	Move<VkBuffer>				testBuffer;
100 	VkMemoryRequirements		memReqs;
101 	Move<VkDeviceMemory>		memory;
102 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
103 	const VkPhysicalDeviceMemoryProperties	memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
104 
105 	// Create buffer
106 	{
107 		VkBufferCreateInfo		bufferParams		=
108 		{
109 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
110 			DE_NULL,
111 			m_testCase.flags,
112 			size,
113 			m_testCase.usage,
114 			m_testCase.sharingMode,
115 			1u,										//	deUint32			queueFamilyCount;
116 			&queueFamilyIndex,
117 		};
118 
119 		try
120 		{
121 			testBuffer = createBuffer(vk, vkDevice, &bufferParams);
122 		}
123 		catch (const vk::Error& error)
124 		{
125 			return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
126 		}
127 
128 		vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
129 
130 		const deUint32		heapTypeIndex	= (deUint32)deCtz32(memReqs.memoryTypeBits);
131 		const VkMemoryType	memoryType		= memoryProperties.memoryTypes[heapTypeIndex];
132 		const VkMemoryHeap	memoryHeap		= memoryProperties.memoryHeaps[memoryType.heapIndex];
133 		const VkDeviceSize	maxBufferSize	= memoryHeap.size / MAX_BUFFER_SIZE_DIVISOR;
134 		// If the requested size is too large, clamp it based on the selected heap size
135 		if (size > maxBufferSize)
136 		{
137 			size = maxBufferSize;
138 			bufferParams.size = size;
139 			try
140 			{
141 				// allocate a new buffer with the adjusted size, the old one will be destroyed by the smart pointer
142 				testBuffer = createBuffer(vk, vkDevice, &bufferParams);
143 			}
144 			catch (const vk::Error& error)
145 			{
146 				return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
147 			}
148 			vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
149 		}
150 
151 		if (size > memReqs.size)
152 		{
153 			std::ostringstream errorMsg;
154 			errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
155 			return tcu::TestStatus::fail(errorMsg.str());
156 		}
157 	}
158 
159 	// Allocate and bind memory
160 	{
161 		const VkMemoryAllocateInfo memAlloc =
162 		{
163 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
164 			NULL,
165 			memReqs.size,
166 			(deUint32)deCtz32(memReqs.memoryTypeBits)	//	deUint32		memoryTypeIndex
167 		};
168 
169 		try
170 		{
171 			memory = allocateMemory(vk, vkDevice, &memAlloc, (const VkAllocationCallbacks*)DE_NULL);
172 		}
173 		catch (const vk::Error& error)
174 		{
175 			return tcu::TestStatus::fail("Alloc memory failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
176 		}
177 
178 		if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
179 			(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
180 			(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
181 		{
182 			VkQueue queue												= 0;
183 
184 			vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue);
185 
186 			const VkSparseMemoryBind			sparseMemoryBind		=
187 			{
188 				0,										// VkDeviceSize								resourceOffset;
189 				memReqs.size,							// VkDeviceSize								size;
190 				*memory,								// VkDeviceMemory							memory;
191 				0,										// VkDeviceSize								memoryOffset;
192 				0										// VkSparseMemoryBindFlags					flags;
193 			};
194 
195 			const VkSparseBufferMemoryBindInfo	sparseBufferMemoryBindInfo	=
196 			{
197 				*testBuffer,							// VkBuffer									buffer;
198 				1u,										// deUint32									bindCount;
199 				&sparseMemoryBind						// const VkSparseMemoryBind*				pBinds;
200 			};
201 
202 			const VkBindSparseInfo				bindSparseInfo			=
203 			{
204 				VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,		// VkStructureType							sType;
205 				DE_NULL,								// const void*								pNext;
206 				0,										// deUint32									waitSemaphoreCount;
207 				DE_NULL,								// const VkSemaphore*						pWaitSemaphores;
208 				1u,										// deUint32									bufferBindCount;
209 				&sparseBufferMemoryBindInfo,			// const VkSparseBufferMemoryBindInfo*		pBufferBinds;
210 				0,										// deUint32									imageOpaqueBindCount;
211 				DE_NULL,								// const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
212 				0,										// deUint32									imageBindCount;
213 				DE_NULL,								// const VkSparseImageMemoryBindInfo*		pImageBinds;
214 				0,										// deUint32									signalSemaphoreCount;
215 				DE_NULL,								// const VkSemaphore*						pSignalSemaphores;
216 			};
217 
218 			const VkFenceCreateInfo fenceParams =
219 			{
220 				VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
221 				DE_NULL,								// const void*			pNext;
222 				0u										// VkFenceCreateFlags	flags;
223 			};
224 
225 			const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams));
226 
227 			VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
228 			if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
229 				return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
230 
231 			VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
232 		} else
233 			if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
234 				return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
235 	}
236 
237 	return tcu::TestStatus::pass("Buffer test");
238 }
239 
iterate(void)240 tcu::TestStatus BufferTestInstance::iterate (void)
241 {
242 	const VkPhysicalDeviceFeatures&	physicalDeviceFeatures	= m_context.getDeviceFeatures();
243 
244 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding)
245 		TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
246 
247 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer)
248 		TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
249 
250 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased)
251 		TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
252 
253 	const VkDeviceSize testSizes[] =
254 	{
255 		1,
256 		1181,
257 		15991,
258 		16384
259 	};
260 	tcu::TestStatus					testStatus			= tcu::TestStatus::pass("Buffer test");
261 
262 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); i++)
263 	{
264 		if ((testStatus = bufferCreateAndAllocTest(testSizes[i])).getCode() != QP_TEST_RESULT_PASS)
265 			return testStatus;
266 	}
267 
268 	if (m_testCase.usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT))
269 	{
270 		const VkPhysicalDevice					vkPhysicalDevice	= m_context.getPhysicalDevice();
271 		const InstanceInterface&				vkInstance			= m_context.getInstanceInterface();
272 		VkPhysicalDeviceProperties	props;
273 
274 		vkInstance.getPhysicalDeviceProperties(vkPhysicalDevice, &props);
275 		testStatus = bufferCreateAndAllocTest((VkDeviceSize) props.limits.maxTexelBufferElements);
276 	}
277 
278 	return testStatus;
279 }
280 
281 } // anonymous
282 
createBufferTests(tcu::TestContext & testCtx)283  tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
284 {
285 	const VkBufferUsageFlags bufferUsageModes[] =
286 	{
287 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
288 		VK_BUFFER_USAGE_TRANSFER_DST_BIT,
289 		VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
290 		VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
291 		VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
292 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
293 		VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
294 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
295 		VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
296 	};
297 
298 	const VkBufferCreateFlags bufferCreateFlags[] =
299 	{
300 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
301 		VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
302 		VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
303 	};
304 
305 	de::MovePtr<tcu::TestCaseGroup>	buffersTests	(new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
306 
307 	deUint32	numberOfBufferUsageFlags			= DE_LENGTH_OF_ARRAY(bufferUsageModes);
308 	deUint32	numberOfBufferCreateFlags			= DE_LENGTH_OF_ARRAY(bufferCreateFlags);
309 	deUint32	maximumValueOfBufferUsageFlags		= (1 << (numberOfBufferUsageFlags - 1)) - 1;
310 	deUint32	maximumValueOfBufferCreateFlags		= (1 << (numberOfBufferCreateFlags)) - 1;
311 
312 	for (deUint32 combinedBufferCreateFlags = 0; combinedBufferCreateFlags <= maximumValueOfBufferCreateFlags; combinedBufferCreateFlags++)
313 	{
314 		for (deUint32 combinedBufferUsageFlags = 1; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++)
315 		{
316 			if (combinedBufferCreateFlags == VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)
317 			{
318 				// spec says: If flags contains VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, it must also contain at least one of
319 				// VK_BUFFER_CREATE_SPARSE_BINDING_BIT or VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT
320 				continue;
321 			}
322 			BufferCaseParameters	testParams =
323 			{
324 				combinedBufferUsageFlags,
325 				combinedBufferCreateFlags,
326 				VK_SHARING_MODE_EXCLUSIVE
327 			};
328 			std::ostringstream	testName;
329 			std::ostringstream	testDescription;
330 			testName << "createBuffer_" << combinedBufferUsageFlags << "_" << combinedBufferCreateFlags;
331 			testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << combinedBufferCreateFlags;
332 			buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams));
333 		}
334 	}
335 
336 	return buffersTests.release();
337 }
338 
339 } // api
340 } // vk
341