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