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