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