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
40namespace vkt
41{
42namespace api
43{
44namespace
45{
46using namespace vk;
47
48enum AllocationKind
49{
50	ALLOCATION_KIND_SUBALLOCATED = 0,
51	ALLOCATION_KIND_DEDICATED,
52
53	ALLOCATION_KIND_LAST,
54};
55
56tcu::PlatformMemoryLimits getPlatformMemoryLimits (Context& context)
57{
58	tcu::PlatformMemoryLimits memoryLimits;
59
60	context.getTestContext().getPlatform().getMemoryLimits(memoryLimits);
61
62	return memoryLimits;
63}
64
65VkDeviceSize 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
85struct BufferCaseParameters
86{
87	VkBufferUsageFlags	usage;
88	VkBufferCreateFlags	flags;
89	VkSharingMode		sharingMode;
90};
91
92class BufferTestInstance : public TestInstance
93{
94public:
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
104protected:
105	BufferCaseParameters				m_testCase;
106};
107
108class DedicatedAllocationBufferTestInstance : public BufferTestInstance
109{
110public:
111										DedicatedAllocationBufferTestInstance
112																		(Context&					ctx,
113																		 BufferCaseParameters		testCase)
114										: BufferTestInstance			(ctx, testCase)
115	{
116	}
117	virtual tcu::TestStatus				bufferCreateAndAllocTest		(VkDeviceSize				size);
118};
119
120class BuffersTestCase : public TestCase
121{
122public:
123										BuffersTestCase					(tcu::TestContext&			testCtx,
124																		 const std::string&			name,
125																		 BufferCaseParameters		testCase)
126										: TestCase						(testCtx, name)
127										, m_testCase					(testCase)
128	{
129	}
130
131	virtual								~BuffersTestCase				(void)
132	{
133	}
134
135	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
142	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
156private:
157	BufferCaseParameters				m_testCase;
158};
159
160class DedicatedAllocationBuffersTestCase : public TestCase
161{
162	public:
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
172	virtual								~DedicatedAllocationBuffersTestCase
173																		(void)
174	{
175	}
176
177	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
184	virtual void						checkSupport					(Context&					ctx) const
185	{
186		if (!ctx.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
187			TCU_THROW(NotSupportedError, "Not supported");
188	}
189private:
190	BufferCaseParameters				m_testCase;
191};
192
193tcu::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
379tcu::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
403tcu::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
561std::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
580std::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
599void 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
675tcu::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
689struct LargeBufferParameters
690{
691	deUint64				bufferSize;
692	bool					useMaxBufferSize;
693	VkBufferCreateFlags		flags;
694};
695
696#ifndef CTS_USES_VULKANSC
697tcu::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
750void 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
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