• 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 PlatformMemoryLimits getPlatformMemoryLimits (Context& context)
57 {
58 	PlatformMemoryLimits	memoryLimits;
59 
60 	context.getTestContext().getPlatform().getVulkanPlatform().getMemoryLimits(memoryLimits);
61 
62 	return memoryLimits;
63 }
64 
getMaxBufferSize(const VkDeviceSize & bufferSize,const VkDeviceSize & alignment,const PlatformMemoryLimits & limits)65 VkDeviceSize getMaxBufferSize(const VkDeviceSize& bufferSize,
66 							  const VkDeviceSize& alignment,
67 							  const 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 			if (size > memReqs.size)
281 			{
282 				std::ostringstream		errorMsg;
283 				errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
284 				return tcu::TestStatus::fail(errorMsg.str());
285 			}
286 
287 			// Allocate the memory
288 			{
289 				VkResult				result							= VK_ERROR_OUT_OF_HOST_MEMORY;
290 				VkDeviceMemory			rawMemory						= DE_NULL;
291 
292 				const VkMemoryAllocateInfo
293 										memAlloc						=
294 				{
295 					VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,				// VkStructureType			sType;
296 					NULL,												// const void*				pNext;
297 					memReqs.size,										// VkDeviceSize				allocationSize;
298 					heapTypeIndex,										// uint32_t					memoryTypeIndex;
299 				};
300 
301 				result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
302 
303 				if (result != VK_SUCCESS)
304 				{
305 					size = deAlign64(size >> shrinkBits, memReqs.alignment);
306 
307 					if (size == 0 || memReqs.size == memReqs.alignment)
308 					{
309 						return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory");
310 					}
311 
312 					continue;	// didn't work, try with a smaller allocation (and a smaller buffer)
313 				}
314 
315 				memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
316 			}
317 		} // while
318 	}
319 
320 	// Bind the memory
321 	if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0)
322 	{
323 		const VkQueue					queue							= m_context.getSparseQueue();
324 
325 		const VkSparseMemoryBind		sparseMemoryBind				=
326 		{
327 			0,															// VkDeviceSize				resourceOffset;
328 			memReqs.size,												// VkDeviceSize				size;
329 			*memory,													// VkDeviceMemory			memory;
330 			0,															// VkDeviceSize				memoryOffset;
331 			0															// VkSparseMemoryBindFlags	flags;
332 		};
333 
334 		const VkSparseBufferMemoryBindInfo
335 										sparseBufferMemoryBindInfo		=
336 		{
337 			*buffer,													// VkBuffer					buffer;
338 			1u,															// deUint32					bindCount;
339 			&sparseMemoryBind											// const VkSparseMemoryBind* pBinds;
340 		};
341 
342 		const VkBindSparseInfo			bindSparseInfo					=
343 		{
344 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,							// VkStructureType			sType;
345 			DE_NULL,													// const void*				pNext;
346 			0,															// deUint32					waitSemaphoreCount;
347 			DE_NULL,													// const VkSemaphore*		pWaitSemaphores;
348 			1u,															// deUint32					bufferBindCount;
349 			&sparseBufferMemoryBindInfo,								// const VkSparseBufferMemoryBindInfo* pBufferBinds;
350 			0,															// deUint32					imageOpaqueBindCount;
351 			DE_NULL,													// const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
352 			0,															// deUint32					imageBindCount;
353 			DE_NULL,													// const VkSparseImageMemoryBindInfo* pImageBinds;
354 			0,															// deUint32					signalSemaphoreCount;
355 			DE_NULL,													// const VkSemaphore*		pSignalSemaphores;
356 		};
357 
358 		const vk::Unique<vk::VkFence>	fence							(vk::createFence(vk, vkDevice));
359 
360 		if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
361 			return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
362 
363 		VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
364 	}
365 	else if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
366 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
367 
368 	return tcu::TestStatus::pass("Pass");
369 }
370 
iterate(void)371 tcu::TestStatus							BufferTestInstance::iterate		(void)
372 {
373 	const VkDeviceSize					testSizes[]						=
374 	{
375 		1,
376 		1181,
377 		15991,
378 		16384,
379 		~0ull,		// try to exercise a very large buffer too (will be clamped to a sensible size later)
380 	};
381 
382 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i)
383 	{
384 		const tcu::TestStatus			testStatus						= bufferCreateAndAllocTest(testSizes[i]);
385 
386 		if (testStatus.getCode() != QP_TEST_RESULT_PASS)
387 			return testStatus;
388 	}
389 
390 	return tcu::TestStatus::pass("Pass");
391 }
392 
bufferCreateAndAllocTest(VkDeviceSize size)393 tcu::TestStatus							DedicatedAllocationBufferTestInstance::bufferCreateAndAllocTest
394 																		(VkDeviceSize				size)
395 {
396 	const VkPhysicalDevice				vkPhysicalDevice				= m_context.getPhysicalDevice();
397 	const InstanceInterface&			vkInstance						= m_context.getInstanceInterface();
398 	const VkDevice						vkDevice						= m_context.getDevice();
399 	const DeviceInterface&				vk								= m_context.getDeviceInterface();
400 	const deUint32						queueFamilyIndex				= m_context.getUniversalQueueFamilyIndex();
401 	const VkPhysicalDeviceMemoryProperties
402 										memoryProperties				= getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
403 	const VkPhysicalDeviceLimits		limits							= getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits;
404 
405 	VkMemoryDedicatedRequirements	dedicatedRequirements			=
406 	{
407 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,				// VkStructureType			sType;
408 		DE_NULL,														// const void*				pNext;
409 		false,															// VkBool32					prefersDedicatedAllocation
410 		false															// VkBool32					requiresDedicatedAllocation
411 	};
412 	VkMemoryRequirements2			memReqs							=
413 	{
414 		VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,						// VkStructureType			sType
415 		&dedicatedRequirements,											// void*					pNext
416 		{0, 0, 0}														// VkMemoryRequirements		memoryRequirements
417 	};
418 
419 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
420 		size = std::min(size, limits.sparseAddressSpaceSize);
421 
422 	// Create a minimal buffer first to get the supported memory types
423 	VkBufferCreateInfo					bufferParams					=
424 	{
425 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							// VkStructureType			sType
426 		DE_NULL,														// const void*				pNext
427 		m_testCase.flags,												// VkBufferCreateFlags		flags
428 		1u,																// VkDeviceSize				size
429 		m_testCase.usage,												// VkBufferUsageFlags		usage
430 		m_testCase.sharingMode,											// VkSharingMode			sharingMode
431 		1u,																// uint32_t					queueFamilyIndexCount
432 		&queueFamilyIndex,												// const uint32_t*			pQueueFamilyIndices
433 	};
434 
435 	Move<VkBuffer>						buffer							= createBuffer(vk, vkDevice, &bufferParams);
436 
437 	VkBufferMemoryRequirementsInfo2	info							=
438 	{
439 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,			// VkStructureType			sType
440 		DE_NULL,														// const void*				pNext
441 		*buffer															// VkBuffer					buffer
442 	};
443 
444 	vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);
445 
446 	if (dedicatedRequirements.requiresDedicatedAllocation == VK_TRUE)
447 	{
448 		std::ostringstream				errorMsg;
449 		errorMsg << "Nonexternal objects cannot require dedicated allocation.";
450 		return tcu::TestStatus::fail(errorMsg.str());
451 	}
452 
453 	const deUint32						heapTypeIndex					= static_cast<deUint32>(deCtz32(memReqs.memoryRequirements.memoryTypeBits));
454 	const VkMemoryType					memoryType						= memoryProperties.memoryTypes[heapTypeIndex];
455 	const VkMemoryHeap					memoryHeap						= memoryProperties.memoryHeaps[memoryType.heapIndex];
456 	const deUint32						shrinkBits						= 4u;	// number of bits to shift when reducing the size with each iteration
457 
458 	// Buffer size - Choose half of the reported heap size for the maximum buffer size, we
459 	// should attempt to test as large a portion as possible.
460 	//
461 	// However on a system where device memory is shared with the system, the maximum size
462 	// should be tested against the platform memory limits as a significant portion of the heap
463 	// may already be in use by the operating system and other running processes.
464 	const VkDeviceSize maxBufferSize = getMaxBufferSize(memoryHeap.size,
465 													   memReqs.memoryRequirements.alignment,
466 													   getPlatformMemoryLimits(m_context));
467 
468 	Move<VkDeviceMemory>				memory;
469 	size = deAlign64(std::min(size, maxBufferSize >> 1), memReqs.memoryRequirements.alignment);
470 	while (*memory == DE_NULL)
471 	{
472 		// Create the buffer
473 		{
474 			VkResult					result							= VK_ERROR_OUT_OF_HOST_MEMORY;
475 			VkBuffer					rawBuffer						= DE_NULL;
476 
477 			bufferParams.size = size;
478 			buffer = Move<VkBuffer>(); // free the previous buffer, if any
479 			result = vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer);
480 
481 			if (result != VK_SUCCESS)
482 			{
483 				size = deAlign64(size >> shrinkBits, memReqs.memoryRequirements.alignment);
484 
485 				if (size == 0 || bufferParams.size == memReqs.memoryRequirements.alignment)
486 					return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")");
487 
488 				continue; // didn't work, try with a smaller buffer
489 			}
490 
491 			buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL));
492 		}
493 
494 		info.buffer = *buffer;
495 		vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);		// get the proper size requirement
496 
497 		if (size > memReqs.memoryRequirements.size)
498 		{
499 			std::ostringstream			errorMsg;
500 			errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
501 			return tcu::TestStatus::fail(errorMsg.str());
502 		}
503 
504 		// Allocate the memory
505 		{
506 			VkResult					result							= VK_ERROR_OUT_OF_HOST_MEMORY;
507 			VkDeviceMemory				rawMemory						= DE_NULL;
508 
509 			vk::VkMemoryDedicatedAllocateInfo
510 										dedicatedInfo					=
511 			{
512 				VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,		// VkStructureType			sType
513 				DE_NULL,												// const void*				pNext
514 				DE_NULL,												// VkImage					image
515 				*buffer													// VkBuffer					buffer
516 			};
517 
518 			VkMemoryAllocateInfo		memoryAllocateInfo				=
519 			{
520 				VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,					// VkStructureType			sType
521 				&dedicatedInfo,											// const void*				pNext
522 				memReqs.memoryRequirements.size,						// VkDeviceSize				allocationSize
523 				heapTypeIndex,											// deUint32					memoryTypeIndex
524 			};
525 
526 			result = vk.allocateMemory(vkDevice, &memoryAllocateInfo, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
527 
528 			if (result != VK_SUCCESS)
529 			{
530 				size = deAlign64(size >> shrinkBits, memReqs.memoryRequirements.alignment);
531 
532 				if (size == 0 || memReqs.memoryRequirements.size == memReqs.memoryRequirements.alignment)
533 					return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.memoryRequirements.size) + " bytes of memory");
534 
535 				continue; // didn't work, try with a smaller allocation (and a smaller buffer)
536 			}
537 
538 			memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
539 		}
540 	} // while
541 
542 	if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
543 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
544 
545 	return tcu::TestStatus::pass("Pass");
546 }
547 
getBufferUsageFlagsName(const VkBufferUsageFlags flags)548 std::string getBufferUsageFlagsName (const VkBufferUsageFlags flags)
549 {
550 	switch (flags)
551 	{
552 		case VK_BUFFER_USAGE_TRANSFER_SRC_BIT:			return "transfer_src";
553 		case VK_BUFFER_USAGE_TRANSFER_DST_BIT:			return "transfer_dst";
554 		case VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT:	return "uniform_texel";
555 		case VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT:	return "storage_texel";
556 		case VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT:		return "uniform";
557 		case VK_BUFFER_USAGE_STORAGE_BUFFER_BIT:		return "storage";
558 		case VK_BUFFER_USAGE_INDEX_BUFFER_BIT:			return "index";
559 		case VK_BUFFER_USAGE_VERTEX_BUFFER_BIT:			return "vertex";
560 		case VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT:		return "indirect";
561 		default:
562 			DE_FATAL("Unknown buffer usage flag");
563 			return "";
564 	}
565 }
566 
getBufferCreateFlagsName(const VkBufferCreateFlags flags)567 std::string getBufferCreateFlagsName (const VkBufferCreateFlags flags)
568 {
569 	std::ostringstream name;
570 
571 	if (flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)
572 		name << "_binding";
573 	if (flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT)
574 		name << "_residency";
575 	if (flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)
576 		name << "_aliased";
577 	if (flags == 0u)
578 		name << "_zero";
579 
580 	DE_ASSERT(!name.str().empty());
581 
582 	return name.str().substr(1);
583 }
584 
585 // Create all VkBufferUsageFlags combinations recursively
createBufferUsageCases(tcu::TestCaseGroup & testGroup,const deUint32 firstNdx,const deUint32 bufferUsageFlags,const AllocationKind allocationKind)586 void createBufferUsageCases (tcu::TestCaseGroup& testGroup, const deUint32 firstNdx, const deUint32 bufferUsageFlags, const AllocationKind allocationKind)
587 {
588 	const VkBufferUsageFlags			bufferUsageModes[]	=
589 	{
590 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
591 		VK_BUFFER_USAGE_TRANSFER_DST_BIT,
592 		VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
593 		VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
594 		VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
595 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
596 		VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
597 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
598 		VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
599 	};
600 
601 	tcu::TestContext&					testCtx				= testGroup.getTestContext();
602 
603 	// Add test groups
604 	for (deUint32 currentNdx = firstNdx; currentNdx < DE_LENGTH_OF_ARRAY(bufferUsageModes); currentNdx++)
605 	{
606 		const deUint32					newBufferUsageFlags	= bufferUsageFlags | bufferUsageModes[currentNdx];
607 		const std::string				newGroupName		= getBufferUsageFlagsName(bufferUsageModes[currentNdx]);
608 		de::MovePtr<tcu::TestCaseGroup>	newTestGroup		(new tcu::TestCaseGroup(testCtx, newGroupName.c_str(), ""));
609 
610 		createBufferUsageCases(*newTestGroup, currentNdx + 1u, newBufferUsageFlags, allocationKind);
611 		testGroup.addChild(newTestGroup.release());
612 	}
613 
614 	// Add test cases
615 	if (bufferUsageFlags != 0u)
616 	{
617 		// \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag.
618 		const VkBufferCreateFlags		bufferCreateFlags[]		=
619 		{
620 			0,
621 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
622 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
623 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
624 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
625 		};
626 
627 		// Dedicated allocation does not support sparse feature
628 		const int						numBufferCreateFlags	= (allocationKind == ALLOCATION_KIND_SUBALLOCATED) ? DE_LENGTH_OF_ARRAY(bufferCreateFlags) : 1;
629 
630 		de::MovePtr<tcu::TestCaseGroup>	newTestGroup			(new tcu::TestCaseGroup(testCtx, "create", ""));
631 
632 		for (int bufferCreateFlagsNdx = 0; bufferCreateFlagsNdx < numBufferCreateFlags; bufferCreateFlagsNdx++)
633 		{
634 			const BufferCaseParameters	testParams	=
635 			{
636 				bufferUsageFlags,
637 				bufferCreateFlags[bufferCreateFlagsNdx],
638 				VK_SHARING_MODE_EXCLUSIVE
639 			};
640 
641 			const std::string			allocStr	= (allocationKind == ALLOCATION_KIND_SUBALLOCATED) ? "suballocation of " : "dedicated alloc. of ";
642 			const std::string			caseName	= getBufferCreateFlagsName(bufferCreateFlags[bufferCreateFlagsNdx]);
643 			const std::string			caseDesc	= "vkCreateBuffer test: " + allocStr + de::toString(bufferUsageFlags) + " " + de::toString(testParams.flags);
644 
645 			switch (allocationKind)
646 			{
647 				case ALLOCATION_KIND_SUBALLOCATED:
648 					newTestGroup->addChild(new BuffersTestCase(testCtx, caseName.c_str(), caseDesc.c_str(), testParams));
649 					break;
650 				case ALLOCATION_KIND_DEDICATED:
651 					newTestGroup->addChild(new DedicatedAllocationBuffersTestCase(testCtx, caseName.c_str(), caseDesc.c_str(), testParams));
652 					break;
653 				default:
654 					DE_FATAL("Unknown test type");
655 			}
656 		}
657 		testGroup.addChild(newTestGroup.release());
658 	}
659 }
660 
testDepthStencilBufferFeatures(Context & context,VkFormat format)661 tcu::TestStatus testDepthStencilBufferFeatures(Context& context, VkFormat format)
662 {
663 	const InstanceInterface&	vki				= context.getInstanceInterface();
664 	VkPhysicalDevice			physicalDevice	= context.getPhysicalDevice();
665 	VkFormatProperties			formatProperties;
666 
667 	vki.getPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
668 
669 	if (formatProperties.bufferFeatures == 0x0)
670 		return tcu::TestStatus::pass("Pass");
671 	else
672 		return tcu::TestStatus::fail("Fail");
673 }
674 
675 struct LargeBufferParameters
676 {
677 	deUint64				bufferSize;
678 	bool					useMaxBufferSize;
679 	VkBufferCreateFlags		flags;
680 };
681 
testLargeBuffer(Context & context,LargeBufferParameters params)682 tcu::TestStatus testLargeBuffer(Context& context, LargeBufferParameters params)
683 {
684 	const DeviceInterface&	vk					= context.getDeviceInterface();
685 	const VkDevice			vkDevice			= context.getDevice();
686 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
687 	VkBuffer				rawBuffer			= DE_NULL;
688 
689 	if (params.useMaxBufferSize)
690 		params.bufferSize = context.getMaintenance4Properties().maxBufferSize;
691 
692 	VkBufferCreateInfo bufferParams =
693 	{
694 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType			sType;
695 		DE_NULL,								// const void*				pNext;
696 		params.flags,							// VkBufferCreateFlags		flags;
697 		params.bufferSize,						// VkDeviceSize				size;
698 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		// VkBufferUsageFlags		usage;
699 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode;
700 		1u,										// uint32_t					queueFamilyIndexCount;
701 		&queueFamilyIndex,						// const uint32_t*			pQueueFamilyIndices;
702 	};
703 
704 	VkResult result = vk.createBuffer(vkDevice, &bufferParams, (vk::VkAllocationCallbacks*)DE_NULL, &rawBuffer);
705 
706 	// if buffer creation succeeds verify that the correct amount of memory was bound to it
707 	if (result == VK_SUCCESS)
708 	{
709 		VkMemoryRequirements memoryRequirements;
710 		vk.getBufferMemoryRequirements(vkDevice, rawBuffer, &memoryRequirements);
711 		vk.destroyBuffer(vkDevice, rawBuffer, DE_NULL);
712 
713 		if (memoryRequirements.size >= params.bufferSize)
714 			return tcu::TestStatus::pass("Pass");
715 		return tcu::TestStatus::fail("Fail");
716 	}
717 
718 	vk.destroyBuffer(vkDevice, rawBuffer, DE_NULL);
719 
720 	// check if one of the allowed errors was returned
721 	if ((result == VK_ERROR_OUT_OF_DEVICE_MEMORY) ||
722 		(result == VK_ERROR_OUT_OF_HOST_MEMORY))
723 		return tcu::TestStatus::pass("Pass");
724 
725 	return tcu::TestStatus::fail("Fail");
726 }
727 
checkMaintenance4Support(Context & context,LargeBufferParameters params)728 void checkMaintenance4Support(Context& context, LargeBufferParameters params)
729 {
730 	if (params.useMaxBufferSize)
731 		context.requireDeviceFunctionality("VK_KHR_maintenance4");
732 	else if (context.isDeviceFunctionalitySupported("VK_KHR_maintenance4") &&
733 		params.bufferSize > context.getMaintenance4Properties().maxBufferSize)
734 		TCU_THROW(NotSupportedError, "vkCreateBuffer with a size larger than maxBufferSize is not valid usage");
735 
736 	const VkPhysicalDeviceFeatures& physicalDeviceFeatures = getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
737 	if ((params.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && !physicalDeviceFeatures.sparseBinding)
738 		TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
739 }
740 
741 } // anonymous
742 
createBufferTests(tcu::TestContext & testCtx)743  tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
744 {
745 	de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
746 
747 	{
748 		de::MovePtr<tcu::TestCaseGroup>	regularAllocation	(new tcu::TestCaseGroup(testCtx, "suballocation", "Regular suballocation of memory."));
749 		createBufferUsageCases(*regularAllocation, 0u, 0u, ALLOCATION_KIND_SUBALLOCATED);
750 		buffersTests->addChild(regularAllocation.release());
751 	}
752 
753 	{
754 		de::MovePtr<tcu::TestCaseGroup>	dedicatedAllocation	(new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "Dedicated allocation of memory."));
755 		createBufferUsageCases(*dedicatedAllocation, 0u, 0u, ALLOCATION_KIND_DEDICATED);
756 		buffersTests->addChild(dedicatedAllocation.release());
757 	}
758 
759 	{
760 		de::MovePtr<tcu::TestCaseGroup> basicTests(new tcu::TestCaseGroup(testCtx, "basic", "Basic buffer tests."));
761 		addFunctionCase(basicTests.get(), "max_size", "Creating buffer using maxBufferSize limit.",
762 						checkMaintenance4Support, testLargeBuffer, LargeBufferParameters
763 						{
764 							0u,
765 							true,
766 							0u
767 						});
768 		addFunctionCase(basicTests.get(), "max_size_sparse", "Creating sparse buffer using maxBufferSize limit.",
769 						checkMaintenance4Support, testLargeBuffer, LargeBufferParameters
770 						{
771 							0u,
772 							true,
773 							VK_BUFFER_CREATE_SPARSE_BINDING_BIT
774 						});
775 		addFunctionCase(basicTests.get(), "size_max_uint64", "Creating a ULLONG_MAX buffer and verify that it either succeeds or returns one of the allowed errors.",
776 						checkMaintenance4Support, testLargeBuffer, LargeBufferParameters
777 						{
778 							std::numeric_limits<deUint64>::max(),
779 							false,
780 							0u
781 						});
782 		buffersTests->addChild(basicTests.release());
783 	}
784 
785 	{
786 		static const VkFormat dsFormats[] =
787 		{
788 			VK_FORMAT_S8_UINT,
789 			VK_FORMAT_D16_UNORM,
790 			VK_FORMAT_D16_UNORM_S8_UINT,
791 			VK_FORMAT_D24_UNORM_S8_UINT,
792 			VK_FORMAT_D32_SFLOAT,
793 			VK_FORMAT_D32_SFLOAT_S8_UINT,
794 			VK_FORMAT_X8_D24_UNORM_PACK32
795 		};
796 
797 		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."));
798 
799 		for (const auto& testFormat : dsFormats)
800 		{
801 			std::string formatName = de::toLower(getFormatName(testFormat));
802 
803 			addFunctionCase(invalidBufferFeatures.get(), formatName, formatName, testDepthStencilBufferFeatures, testFormat);
804 		}
805 
806 		buffersTests->addChild(invalidBufferFeatures.release());
807 	}
808 
809 	return buffersTests.release();
810 }
811 
812 } // api
813 } // vk
814