• 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 #include "gluVarType.hpp"
27 #include "deStringUtil.hpp"
28 #include "tcuTestLog.hpp"
29 #include "vkPlatform.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "tcuPlatform.hpp"
36 
37 #include <algorithm>
38 #include <limits>
39 
40 namespace vkt
41 {
42 namespace api
43 {
44 namespace
45 {
46 using namespace vk;
47 
48 enum AllocationKind
49 {
50 	ALLOCATION_KIND_SUBALLOCATED = 0,
51 	ALLOCATION_KIND_DEDICATED,
52 
53 	ALLOCATION_KIND_LAST,
54 };
55 
getPlatformMemoryLimits(Context & context)56 tcu::PlatformMemoryLimits getPlatformMemoryLimits (Context& context)
57 {
58 	tcu::PlatformMemoryLimits memoryLimits;
59 
60 	context.getTestContext().getPlatform().getMemoryLimits(memoryLimits);
61 
62 	return memoryLimits;
63 }
64 
getMaxBufferSize(const VkDeviceSize & bufferSize,const VkDeviceSize & alignment,const tcu::PlatformMemoryLimits & limits)65 VkDeviceSize getMaxBufferSize(const VkDeviceSize& bufferSize,
66 							  const VkDeviceSize& alignment,
67 							  const tcu::PlatformMemoryLimits& limits)
68 {
69 	VkDeviceSize size = bufferSize;
70 
71 	if (limits.totalDeviceLocalMemory == 0)
72 	{
73 		// 'UMA' systems where device memory counts against system memory
74 		size = std::min(bufferSize, limits.totalSystemMemory - alignment);
75 	}
76 	else
77 	{
78 		// 'LMA' systems where device memory is local to the GPU
79 		size = std::min(bufferSize, limits.totalDeviceLocalMemory - alignment);
80 	}
81 
82 	return size;
83 }
84 
85 struct BufferCaseParameters
86 {
87 	VkBufferUsageFlags	usage;
88 	VkBufferCreateFlags	flags;
89 	VkSharingMode		sharingMode;
90 };
91 
92 class BufferTestInstance : public TestInstance
93 {
94 public:
BufferTestInstance(Context & ctx,BufferCaseParameters testCase)95 										BufferTestInstance				(Context&					ctx,
96 																		 BufferCaseParameters		testCase)
97 										: TestInstance					(ctx)
98 										, m_testCase					(testCase)
99 	{
100 	}
101 	virtual tcu::TestStatus				iterate							(void);
102 	virtual tcu::TestStatus				bufferCreateAndAllocTest		(VkDeviceSize				size);
103 
104 protected:
105 	BufferCaseParameters				m_testCase;
106 };
107 
108 class DedicatedAllocationBufferTestInstance : public BufferTestInstance
109 {
110 public:
DedicatedAllocationBufferTestInstance(Context & ctx,BufferCaseParameters testCase)111 										DedicatedAllocationBufferTestInstance
112 																		(Context&					ctx,
113 																		 BufferCaseParameters		testCase)
114 										: BufferTestInstance			(ctx, testCase)
115 	{
116 	}
117 	virtual tcu::TestStatus				bufferCreateAndAllocTest		(VkDeviceSize				size);
118 };
119 
120 class BuffersTestCase : public TestCase
121 {
122 public:
BuffersTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferCaseParameters testCase)123 										BuffersTestCase					(tcu::TestContext&			testCtx,
124 																		 const std::string&			name,
125 																		 const std::string&			description,
126 																		 BufferCaseParameters		testCase)
127 										: TestCase						(testCtx, name, description)
128 										, m_testCase					(testCase)
129 	{
130 	}
131 
~BuffersTestCase(void)132 	virtual								~BuffersTestCase				(void)
133 	{
134 	}
135 
createInstance(Context & ctx) const136 	virtual TestInstance*				createInstance					(Context&					ctx) const
137 	{
138 		tcu::TestLog&					log								= m_testCtx.getLog();
139 		log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
140 		return new BufferTestInstance(ctx, m_testCase);
141 	}
142 
checkSupport(Context & ctx) const143 	virtual void						checkSupport					(Context&					ctx) const
144 	{
145 		const VkPhysicalDeviceFeatures&		physicalDeviceFeatures = getPhysicalDeviceFeatures(ctx.getInstanceInterface(), ctx.getPhysicalDevice());
146 
147 		if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && !physicalDeviceFeatures.sparseBinding)
148 			TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
149 
150 		if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && !physicalDeviceFeatures.sparseResidencyBuffer)
151 			TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
152 
153 		if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && !physicalDeviceFeatures.sparseResidencyAliased)
154 			TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
155 	}
156 
157 private:
158 	BufferCaseParameters				m_testCase;
159 };
160 
161 class DedicatedAllocationBuffersTestCase : public TestCase
162 {
163 	public:
DedicatedAllocationBuffersTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferCaseParameters testCase)164 										DedicatedAllocationBuffersTestCase
165 																		(tcu::TestContext&			testCtx,
166 																		 const std::string&			name,
167 																		 const std::string&			description,
168 																		 BufferCaseParameters		testCase)
169 										: TestCase						(testCtx, name, description)
170 										, m_testCase					(testCase)
171 	{
172 	}
173 
~DedicatedAllocationBuffersTestCase(void)174 	virtual								~DedicatedAllocationBuffersTestCase
175 																		(void)
176 	{
177 	}
178 
createInstance(Context & ctx) const179 	virtual TestInstance*				createInstance					(Context&					ctx) const
180 	{
181 		tcu::TestLog&					log								= m_testCtx.getLog();
182 		log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
183 		return new DedicatedAllocationBufferTestInstance(ctx, m_testCase);
184 	}
185 
checkSupport(Context & ctx) const186 	virtual void						checkSupport					(Context&					ctx) const
187 	{
188 		if (!ctx.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
189 			TCU_THROW(NotSupportedError, "Not supported");
190 	}
191 private:
192 	BufferCaseParameters				m_testCase;
193 };
194 
bufferCreateAndAllocTest(VkDeviceSize size)195 tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest			(VkDeviceSize				size)
196 {
197 	const VkPhysicalDevice				vkPhysicalDevice				= m_context.getPhysicalDevice();
198 	const InstanceInterface&			vkInstance						= m_context.getInstanceInterface();
199 	const VkDevice						vkDevice						= m_context.getDevice();
200 	const DeviceInterface&				vk								= m_context.getDeviceInterface();
201 	const deUint32						queueFamilyIndex				= m_context.getSparseQueueFamilyIndex();
202 	const VkPhysicalDeviceMemoryProperties
203 										memoryProperties				= getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
204 	const VkPhysicalDeviceLimits		limits							= getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits;
205 	Move<VkBuffer>						buffer;
206 	Move<VkDeviceMemory>				memory;
207 	VkMemoryRequirements				memReqs;
208 
209 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
210 	{
211 		size = std::min(size, limits.sparseAddressSpaceSize);
212 	}
213 
214 	// Create the test buffer and a memory allocation for it
215 	{
216 		// Create a minimal buffer first to get the supported memory types
217 		VkBufferCreateInfo				bufferParams					=
218 		{
219 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,						// VkStructureType			sType;
220 			DE_NULL,													// const void*				pNext;
221 			m_testCase.flags,											// VkBufferCreateFlags		flags;
222 			1u,															// VkDeviceSize				size;
223 			m_testCase.usage,											// VkBufferUsageFlags		usage;
224 			m_testCase.sharingMode,										// VkSharingMode			sharingMode;
225 			1u,															// uint32_t					queueFamilyIndexCount;
226 			&queueFamilyIndex,											// const uint32_t*			pQueueFamilyIndices;
227 		};
228 
229 		buffer = createBuffer(vk, vkDevice, &bufferParams);
230 		vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);
231 
232 		const deUint32					heapTypeIndex					= (deUint32)deCtz32(memReqs.memoryTypeBits);
233 		const VkMemoryType				memoryType						= memoryProperties.memoryTypes[heapTypeIndex];
234 		const VkMemoryHeap				memoryHeap						= memoryProperties.memoryHeaps[memoryType.heapIndex];
235 		const deUint32					shrinkBits						= 4u;	// number of bits to shift when reducing the size with each iteration
236 
237 		// Buffer size - Choose half of the reported heap size for the maximum buffer size, we
238 		// should attempt to test as large a portion as possible.
239 		//
240 		// However on a system where device memory is shared with the system, the maximum size
241 		// should be tested against the platform memory limits as significant portion of the heap
242 		// may already be in use by the operating system and other running processes.
243 		const VkDeviceSize  availableBufferSize	= getMaxBufferSize(memoryHeap.size,
244 																   memReqs.alignment,
245 																   getPlatformMemoryLimits(m_context));
246 
247 		// For our test buffer size, halve the maximum available size and align
248 		const VkDeviceSize maxBufferSize = deAlign64(availableBufferSize >> 1, memReqs.alignment);
249 
250 		size = std::min(size, maxBufferSize);
251 
252 		while (*memory == DE_NULL)
253 		{
254 			// Create the buffer
255 			{
256 				VkResult				result							= VK_ERROR_OUT_OF_HOST_MEMORY;
257 				VkBuffer				rawBuffer						= DE_NULL;
258 
259 				bufferParams.size = size;
260 				buffer = Move<VkBuffer>();		// free the previous buffer, if any
261 				result = vk.createBuffer(vkDevice, &bufferParams, (vk::VkAllocationCallbacks*)DE_NULL, &rawBuffer);
262 
263 				if (result != VK_SUCCESS)
264 				{
265 					size = deAlign64(size >> shrinkBits, memReqs.alignment);
266 
267 					if (size == 0 || bufferParams.size == memReqs.alignment)
268 					{
269 						return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")");
270 					}
271 
272 					continue;	// didn't work, try with a smaller buffer
273 				}
274 
275 				buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL));
276 			}
277 
278 			vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);	// get the proper size requirement
279 
280 #ifdef CTS_USES_VULKANSC
281 			if (m_context.getTestContext().getCommandLine().isSubProcess())
282 #endif // CTS_USES_VULKANSC
283 			{
284 				if (size > memReqs.size)
285 				{
286 					std::ostringstream		errorMsg;
287 					errorMsg << "Required memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
288 					return tcu::TestStatus::fail(errorMsg.str());
289 				}
290 			}
291 
292 			// Allocate the memory
293 			{
294 				VkResult				result							= VK_ERROR_OUT_OF_HOST_MEMORY;
295 				VkDeviceMemory			rawMemory						= DE_NULL;
296 
297 				const VkMemoryAllocateInfo
298 										memAlloc						=
299 				{
300 					VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,				// VkStructureType			sType;
301 					NULL,												// const void*				pNext;
302 					memReqs.size,										// VkDeviceSize				allocationSize;
303 					heapTypeIndex,										// uint32_t					memoryTypeIndex;
304 				};
305 
306 				result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
307 
308 				if (result != VK_SUCCESS)
309 				{
310 					size = deAlign64(size >> shrinkBits, memReqs.alignment);
311 
312 					if (size == 0 || memReqs.size == memReqs.alignment)
313 					{
314 						return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory");
315 					}
316 
317 					continue;	// didn't work, try with a smaller allocation (and a smaller buffer)
318 				}
319 
320 				memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
321 			}
322 		} // while
323 	}
324 
325 	// Bind the memory
326 #ifndef CTS_USES_VULKANSC
327 	if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0)
328 	{
329 		const VkQueue					queue							= m_context.getSparseQueue();
330 
331 		const VkSparseMemoryBind		sparseMemoryBind				=
332 		{
333 			0,															// VkDeviceSize				resourceOffset;
334 			memReqs.size,												// VkDeviceSize				size;
335 			*memory,													// VkDeviceMemory			memory;
336 			0,															// VkDeviceSize				memoryOffset;
337 			0															// VkSparseMemoryBindFlags	flags;
338 		};
339 
340 		const VkSparseBufferMemoryBindInfo
341 										sparseBufferMemoryBindInfo		=
342 		{
343 			*buffer,													// VkBuffer					buffer;
344 			1u,															// deUint32					bindCount;
345 			&sparseMemoryBind											// const VkSparseMemoryBind* pBinds;
346 		};
347 
348 		const VkBindSparseInfo			bindSparseInfo					=
349 		{
350 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,							// VkStructureType			sType;
351 			DE_NULL,													// const void*				pNext;
352 			0,															// deUint32					waitSemaphoreCount;
353 			DE_NULL,													// const VkSemaphore*		pWaitSemaphores;
354 			1u,															// deUint32					bufferBindCount;
355 			&sparseBufferMemoryBindInfo,								// const VkSparseBufferMemoryBindInfo* pBufferBinds;
356 			0,															// deUint32					imageOpaqueBindCount;
357 			DE_NULL,													// const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
358 			0,															// deUint32					imageBindCount;
359 			DE_NULL,													// const VkSparseImageMemoryBindInfo* pImageBinds;
360 			0,															// deUint32					signalSemaphoreCount;
361 			DE_NULL,													// const VkSemaphore*		pSignalSemaphores;
362 		};
363 
364 		const vk::Unique<vk::VkFence>	fence							(vk::createFence(vk, vkDevice));
365 
366 		if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
367 			return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
368 
369 		VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
370 	}
371 	else if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
372 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
373 #else
374 	if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
375 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
376 #endif // CTS_USES_VULKANSC
377 
378 	return tcu::TestStatus::pass("Pass");
379 }
380 
iterate(void)381 tcu::TestStatus							BufferTestInstance::iterate		(void)
382 {
383 	const VkDeviceSize					testSizes[]						=
384 	{
385 		1,
386 		1181,
387 		15991,
388 		16384,
389 #ifndef CTS_USES_VULKANSC
390 		~0ull,		// try to exercise a very large buffer too (will be clamped to a sensible size later)
391 #endif // CTS_USES_VULKANSC
392 	};
393 
394 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i)
395 	{
396 		const tcu::TestStatus			testStatus						= bufferCreateAndAllocTest(testSizes[i]);
397 
398 		if (testStatus.getCode() != QP_TEST_RESULT_PASS)
399 			return testStatus;
400 	}
401 
402 	return tcu::TestStatus::pass("Pass");
403 }
404 
bufferCreateAndAllocTest(VkDeviceSize size)405 tcu::TestStatus							DedicatedAllocationBufferTestInstance::bufferCreateAndAllocTest
406 																		(VkDeviceSize				size)
407 {
408 	const VkPhysicalDevice				vkPhysicalDevice				= m_context.getPhysicalDevice();
409 	const InstanceInterface&			vkInstance						= m_context.getInstanceInterface();
410 	const VkDevice						vkDevice						= m_context.getDevice();
411 	const DeviceInterface&				vk								= m_context.getDeviceInterface();
412 	const deUint32						queueFamilyIndex				= m_context.getUniversalQueueFamilyIndex();
413 	const VkPhysicalDeviceMemoryProperties
414 										memoryProperties				= getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
415 	const VkPhysicalDeviceLimits		limits							= getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits;
416 
417 	VkMemoryDedicatedRequirements	dedicatedRequirements			=
418 	{
419 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,				// VkStructureType			sType;
420 		DE_NULL,														// const void*				pNext;
421 		false,															// VkBool32					prefersDedicatedAllocation
422 		false															// VkBool32					requiresDedicatedAllocation
423 	};
424 	VkMemoryRequirements2			memReqs							=
425 	{
426 		VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,						// VkStructureType			sType
427 		&dedicatedRequirements,											// void*					pNext
428 		{0, 0, 0}														// VkMemoryRequirements		memoryRequirements
429 	};
430 
431 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
432 		size = std::min(size, limits.sparseAddressSpaceSize);
433 
434 	// Create a minimal buffer first to get the supported memory types
435 	VkBufferCreateInfo					bufferParams					=
436 	{
437 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							// VkStructureType			sType
438 		DE_NULL,														// const void*				pNext
439 		m_testCase.flags,												// VkBufferCreateFlags		flags
440 		1u,																// VkDeviceSize				size
441 		m_testCase.usage,												// VkBufferUsageFlags		usage
442 		m_testCase.sharingMode,											// VkSharingMode			sharingMode
443 		1u,																// uint32_t					queueFamilyIndexCount
444 		&queueFamilyIndex,												// const uint32_t*			pQueueFamilyIndices
445 	};
446 
447 	Move<VkBuffer>						buffer							= createBuffer(vk, vkDevice, &bufferParams);
448 
449 	VkBufferMemoryRequirementsInfo2	info							=
450 	{
451 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,			// VkStructureType			sType
452 		DE_NULL,														// const void*				pNext
453 		*buffer															// VkBuffer					buffer
454 	};
455 
456 	vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);
457 
458 	if (dedicatedRequirements.requiresDedicatedAllocation == VK_TRUE)
459 	{
460 		std::ostringstream				errorMsg;
461 		errorMsg << "Nonexternal objects cannot require dedicated allocation.";
462 		return tcu::TestStatus::fail(errorMsg.str());
463 	}
464 
465 	if(memReqs.memoryRequirements.memoryTypeBits == 0)
466 		return tcu::TestStatus::fail("memoryTypeBits is 0");
467 
468 	const deUint32						heapTypeIndex					= static_cast<deUint32>(deCtz32(memReqs.memoryRequirements.memoryTypeBits));
469 	const VkMemoryType					memoryType						= memoryProperties.memoryTypes[heapTypeIndex];
470 	const VkMemoryHeap					memoryHeap						= memoryProperties.memoryHeaps[memoryType.heapIndex];
471 	const deUint32						shrinkBits						= 4u;	// number of bits to shift when reducing the size with each iteration
472 
473 	// Buffer size - Choose half of the reported heap size for the maximum buffer size, we
474 	// should attempt to test as large a portion as possible.
475 	//
476 	// However on a system where device memory is shared with the system, the maximum size
477 	// should be tested against the platform memory limits as a significant portion of the heap
478 	// may already be in use by the operating system and other running processes.
479 	const VkDeviceSize maxBufferSize = getMaxBufferSize(memoryHeap.size,
480 													   memReqs.memoryRequirements.alignment,
481 													   getPlatformMemoryLimits(m_context));
482 
483 	Move<VkDeviceMemory>				memory;
484 	size = deAlign64(std::min(size, maxBufferSize >> 1), memReqs.memoryRequirements.alignment);
485 	while (*memory == DE_NULL)
486 	{
487 		// Create the buffer
488 		{
489 			VkResult					result							= VK_ERROR_OUT_OF_HOST_MEMORY;
490 			VkBuffer					rawBuffer						= DE_NULL;
491 
492 			bufferParams.size = size;
493 			buffer = Move<VkBuffer>(); // free the previous buffer, if any
494 			result = vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer);
495 
496 			if (result != VK_SUCCESS)
497 			{
498 				size = deAlign64(size >> shrinkBits, memReqs.memoryRequirements.alignment);
499 
500 				if (size == 0 || bufferParams.size == memReqs.memoryRequirements.alignment)
501 					return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")");
502 
503 				continue; // didn't work, try with a smaller buffer
504 			}
505 
506 			buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL));
507 		}
508 
509 		info.buffer = *buffer;
510 		vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);		// get the proper size requirement
511 
512 		if (size > memReqs.memoryRequirements.size)
513 		{
514 			std::ostringstream			errorMsg;
515 			errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
516 			return tcu::TestStatus::fail(errorMsg.str());
517 		}
518 
519 		// Allocate the memory
520 		{
521 			VkResult					result							= VK_ERROR_OUT_OF_HOST_MEMORY;
522 			VkDeviceMemory				rawMemory						= DE_NULL;
523 
524 			vk::VkMemoryDedicatedAllocateInfo
525 										dedicatedInfo					=
526 			{
527 				VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,		// VkStructureType			sType
528 				DE_NULL,												// const void*				pNext
529 				DE_NULL,												// VkImage					image
530 				*buffer													// VkBuffer					buffer
531 			};
532 
533 			VkMemoryAllocateInfo		memoryAllocateInfo				=
534 			{
535 				VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,					// VkStructureType			sType
536 				&dedicatedInfo,											// const void*				pNext
537 				memReqs.memoryRequirements.size,						// VkDeviceSize				allocationSize
538 				heapTypeIndex,											// deUint32					memoryTypeIndex
539 			};
540 
541 			result = vk.allocateMemory(vkDevice, &memoryAllocateInfo, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
542 
543 			if (result != VK_SUCCESS)
544 			{
545 				size = deAlign64(size >> shrinkBits, memReqs.memoryRequirements.alignment);
546 
547 				if (size == 0 || memReqs.memoryRequirements.size == memReqs.memoryRequirements.alignment)
548 					return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.memoryRequirements.size) + " bytes of memory");
549 
550 				continue; // didn't work, try with a smaller allocation (and a smaller buffer)
551 			}
552 
553 			memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
554 		}
555 	} // while
556 
557 	if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
558 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
559 
560 	return tcu::TestStatus::pass("Pass");
561 }
562 
getBufferUsageFlagsName(const VkBufferUsageFlags flags)563 std::string getBufferUsageFlagsName (const VkBufferUsageFlags flags)
564 {
565 	switch (flags)
566 	{
567 		case VK_BUFFER_USAGE_TRANSFER_SRC_BIT:			return "transfer_src";
568 		case VK_BUFFER_USAGE_TRANSFER_DST_BIT:			return "transfer_dst";
569 		case VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT:	return "uniform_texel";
570 		case VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT:	return "storage_texel";
571 		case VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT:		return "uniform";
572 		case VK_BUFFER_USAGE_STORAGE_BUFFER_BIT:		return "storage";
573 		case VK_BUFFER_USAGE_INDEX_BUFFER_BIT:			return "index";
574 		case VK_BUFFER_USAGE_VERTEX_BUFFER_BIT:			return "vertex";
575 		case VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT:		return "indirect";
576 		default:
577 			DE_FATAL("Unknown buffer usage flag");
578 			return "";
579 	}
580 }
581 
getBufferCreateFlagsName(const VkBufferCreateFlags flags)582 std::string getBufferCreateFlagsName (const VkBufferCreateFlags flags)
583 {
584 	std::ostringstream name;
585 
586 	if (flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)
587 		name << "_binding";
588 	if (flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT)
589 		name << "_residency";
590 	if (flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)
591 		name << "_aliased";
592 	if (flags == 0u)
593 		name << "_zero";
594 
595 	DE_ASSERT(!name.str().empty());
596 
597 	return name.str().substr(1);
598 }
599 
600 // Create all VkBufferUsageFlags combinations recursively
createBufferUsageCases(tcu::TestCaseGroup & testGroup,const deUint32 firstNdx,const deUint32 bufferUsageFlags,const AllocationKind allocationKind)601 void createBufferUsageCases (tcu::TestCaseGroup& testGroup, const deUint32 firstNdx, const deUint32 bufferUsageFlags, const AllocationKind allocationKind)
602 {
603 	const VkBufferUsageFlags			bufferUsageModes[]	=
604 	{
605 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
606 		VK_BUFFER_USAGE_TRANSFER_DST_BIT,
607 		VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
608 		VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
609 		VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
610 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
611 		VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
612 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
613 		VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
614 	};
615 
616 	tcu::TestContext&					testCtx				= testGroup.getTestContext();
617 
618 	// Add test groups
619 	for (deUint32 currentNdx = firstNdx; currentNdx < DE_LENGTH_OF_ARRAY(bufferUsageModes); currentNdx++)
620 	{
621 		const deUint32					newBufferUsageFlags	= bufferUsageFlags | bufferUsageModes[currentNdx];
622 		const std::string				newGroupName		= getBufferUsageFlagsName(bufferUsageModes[currentNdx]);
623 		de::MovePtr<tcu::TestCaseGroup>	newTestGroup		(new tcu::TestCaseGroup(testCtx, newGroupName.c_str(), ""));
624 
625 		createBufferUsageCases(*newTestGroup, currentNdx + 1u, newBufferUsageFlags, allocationKind);
626 		testGroup.addChild(newTestGroup.release());
627 	}
628 
629 	// Add test cases
630 	if (bufferUsageFlags != 0u)
631 	{
632 		// \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag.
633 		const VkBufferCreateFlags		bufferCreateFlags[]		=
634 		{
635 			0,
636 #ifndef CTS_USES_VULKANSC
637 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
638 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
639 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
640 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
641 #endif // CTS_USES_VULKANSC
642 		};
643 
644 		// Dedicated allocation does not support sparse feature
645 		const int						numBufferCreateFlags	= (allocationKind == ALLOCATION_KIND_SUBALLOCATED) ? DE_LENGTH_OF_ARRAY(bufferCreateFlags) : 1;
646 
647 		de::MovePtr<tcu::TestCaseGroup>	newTestGroup			(new tcu::TestCaseGroup(testCtx, "create", ""));
648 
649 		for (int bufferCreateFlagsNdx = 0; bufferCreateFlagsNdx < numBufferCreateFlags; bufferCreateFlagsNdx++)
650 		{
651 			const BufferCaseParameters	testParams	=
652 			{
653 				bufferUsageFlags,
654 				bufferCreateFlags[bufferCreateFlagsNdx],
655 				VK_SHARING_MODE_EXCLUSIVE
656 			};
657 
658 			const std::string			allocStr	= (allocationKind == ALLOCATION_KIND_SUBALLOCATED) ? "suballocation of " : "dedicated alloc. of ";
659 			const std::string			caseName	= getBufferCreateFlagsName(bufferCreateFlags[bufferCreateFlagsNdx]);
660 			const std::string			caseDesc	= "vkCreateBuffer test: " + allocStr + de::toString(bufferUsageFlags) + " " + de::toString(testParams.flags);
661 
662 			switch (allocationKind)
663 			{
664 				case ALLOCATION_KIND_SUBALLOCATED:
665 					newTestGroup->addChild(new BuffersTestCase(testCtx, caseName.c_str(), caseDesc.c_str(), testParams));
666 					break;
667 				case ALLOCATION_KIND_DEDICATED:
668 					newTestGroup->addChild(new DedicatedAllocationBuffersTestCase(testCtx, caseName.c_str(), caseDesc.c_str(), testParams));
669 					break;
670 				default:
671 					DE_FATAL("Unknown test type");
672 			}
673 		}
674 		testGroup.addChild(newTestGroup.release());
675 	}
676 }
677 
testDepthStencilBufferFeatures(Context & context,VkFormat format)678 tcu::TestStatus testDepthStencilBufferFeatures(Context& context, VkFormat format)
679 {
680 	const InstanceInterface&	vki				= context.getInstanceInterface();
681 	VkPhysicalDevice			physicalDevice	= context.getPhysicalDevice();
682 	VkFormatProperties			formatProperties;
683 
684 	vki.getPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
685 
686 	if (formatProperties.bufferFeatures == 0x0)
687 		return tcu::TestStatus::pass("Pass");
688 	else
689 		return tcu::TestStatus::fail("Fail");
690 }
691 
692 struct LargeBufferParameters
693 {
694 	deUint64				bufferSize;
695 	bool					useMaxBufferSize;
696 	VkBufferCreateFlags		flags;
697 };
698 
699 #ifndef CTS_USES_VULKANSC
testLargeBuffer(Context & context,LargeBufferParameters params)700 tcu::TestStatus testLargeBuffer(Context& context, LargeBufferParameters params)
701 {
702 	const DeviceInterface&			vk					= context.getDeviceInterface();
703 	const VkDevice					vkDevice			= context.getDevice();
704 	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
705 	const VkPhysicalDeviceLimits	limits				= getPhysicalDeviceProperties(context.getInstanceInterface(),
706 				                                                                      context.getPhysicalDevice()).limits;
707 	VkBuffer						rawBuffer			= DE_NULL;
708 
709 #ifndef CTS_USES_VULKANSC
710 	if (params.useMaxBufferSize)
711 		params.bufferSize = context.getMaintenance4Properties().maxBufferSize;
712 #endif // CTS_USES_VULKANSC
713 
714 	if ((params.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
715 		params.bufferSize = std::min(params.bufferSize, limits.sparseAddressSpaceSize);
716 
717 	VkBufferCreateInfo bufferParams =
718 	{
719 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType			sType;
720 		DE_NULL,								// const void*				pNext;
721 		params.flags,							// VkBufferCreateFlags		flags;
722 		params.bufferSize,						// VkDeviceSize				size;
723 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		// VkBufferUsageFlags		usage;
724 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode;
725 		1u,										// uint32_t					queueFamilyIndexCount;
726 		&queueFamilyIndex,						// const uint32_t*			pQueueFamilyIndices;
727 	};
728 
729 	VkResult result = vk.createBuffer(vkDevice, &bufferParams, (vk::VkAllocationCallbacks*)DE_NULL, &rawBuffer);
730 
731 	// if buffer creation succeeds verify that the correct amount of memory was bound to it
732 	if (result == VK_SUCCESS)
733 	{
734 		VkMemoryRequirements memoryRequirements;
735 		vk.getBufferMemoryRequirements(vkDevice, rawBuffer, &memoryRequirements);
736 		vk.destroyBuffer(vkDevice, rawBuffer, DE_NULL);
737 
738 		if (memoryRequirements.size >= params.bufferSize)
739 			return tcu::TestStatus::pass("Pass");
740 		return tcu::TestStatus::fail("Fail");
741 	}
742 
743 	// check if one of the allowed errors was returned
744 	if ((result == VK_ERROR_OUT_OF_DEVICE_MEMORY) ||
745 		(result == VK_ERROR_OUT_OF_HOST_MEMORY))
746 		return tcu::TestStatus::pass("Pass");
747 
748 	return tcu::TestStatus::fail("Fail");
749 }
750 #endif // CTS_USES_VULKANSC
751 
752 #ifndef CTS_USES_VULKANSC
checkMaintenance4Support(Context & context,LargeBufferParameters params)753 void checkMaintenance4Support(Context& context, LargeBufferParameters params)
754 {
755 	if (params.useMaxBufferSize)
756 		context.requireDeviceFunctionality("VK_KHR_maintenance4");
757 	else if (context.isDeviceFunctionalitySupported("VK_KHR_maintenance4") &&
758 		params.bufferSize > context.getMaintenance4Properties().maxBufferSize)
759 		TCU_THROW(NotSupportedError, "vkCreateBuffer with a size larger than maxBufferSize is not valid usage");
760 
761 	const VkPhysicalDeviceFeatures& physicalDeviceFeatures = getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
762 	if ((params.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && !physicalDeviceFeatures.sparseBinding)
763 		TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
764 }
765 #endif // CTS_USES_VULKANSC
766 
767 } // anonymous
768 
createBufferTests(tcu::TestContext & testCtx)769  tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
770 {
771 	de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
772 
773 	{
774 		de::MovePtr<tcu::TestCaseGroup>	regularAllocation	(new tcu::TestCaseGroup(testCtx, "suballocation", "Regular suballocation of memory."));
775 		createBufferUsageCases(*regularAllocation, 0u, 0u, ALLOCATION_KIND_SUBALLOCATED);
776 		buffersTests->addChild(regularAllocation.release());
777 	}
778 
779 	{
780 		de::MovePtr<tcu::TestCaseGroup>	dedicatedAllocation	(new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "Dedicated allocation of memory."));
781 		createBufferUsageCases(*dedicatedAllocation, 0u, 0u, ALLOCATION_KIND_DEDICATED);
782 		buffersTests->addChild(dedicatedAllocation.release());
783 	}
784 
785 	{
786 		de::MovePtr<tcu::TestCaseGroup> basicTests(new tcu::TestCaseGroup(testCtx, "basic", "Basic buffer tests."));
787 #ifndef CTS_USES_VULKANSC
788 		addFunctionCase(basicTests.get(), "max_size", "Creating buffer using maxBufferSize limit.",
789 						checkMaintenance4Support, testLargeBuffer, LargeBufferParameters
790 						{
791 							0u,
792 							true,
793 							0u
794 						});
795 		addFunctionCase(basicTests.get(), "max_size_sparse", "Creating sparse buffer using maxBufferSize limit.",
796 						checkMaintenance4Support, testLargeBuffer, LargeBufferParameters
797 						{
798 							0u,
799 							true,
800 							VK_BUFFER_CREATE_SPARSE_BINDING_BIT
801 						});
802 		addFunctionCase(basicTests.get(), "size_max_uint64", "Creating a ULLONG_MAX buffer and verify that it either succeeds or returns one of the allowed errors.",
803 						checkMaintenance4Support, testLargeBuffer, LargeBufferParameters
804 						{
805 							std::numeric_limits<deUint64>::max(),
806 							false,
807 							0u
808 						});
809 #endif // CTS_USES_VULKANSC
810 		buffersTests->addChild(basicTests.release());
811 	}
812 
813 	{
814 		static const VkFormat dsFormats[] =
815 		{
816 			VK_FORMAT_S8_UINT,
817 			VK_FORMAT_D16_UNORM,
818 			VK_FORMAT_D16_UNORM_S8_UINT,
819 			VK_FORMAT_D24_UNORM_S8_UINT,
820 			VK_FORMAT_D32_SFLOAT,
821 			VK_FORMAT_D32_SFLOAT_S8_UINT,
822 			VK_FORMAT_X8_D24_UNORM_PACK32
823 		};
824 
825 		de::MovePtr<tcu::TestCaseGroup>	invalidBufferFeatures(new tcu::TestCaseGroup(testCtx, "invalid_buffer_features", "Checks that drivers are not exposing undesired format features for depth/stencil formats."));
826 
827 		for (const auto& testFormat : dsFormats)
828 		{
829 			std::string formatName = de::toLower(getFormatName(testFormat));
830 
831 			addFunctionCase(invalidBufferFeatures.get(), formatName, formatName, testDepthStencilBufferFeatures, testFormat);
832 		}
833 
834 		buffersTests->addChild(invalidBufferFeatures.release());
835 	}
836 
837 	return buffersTests.release();
838 }
839 
840 } // api
841 } // vk
842