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 
     27 #include "deStringUtil.hpp"
     28 #include "gluVarType.hpp"
     29 #include "tcuTestLog.hpp"
     30 #include "vkPrograms.hpp"
     31 #include "vkQueryUtil.hpp"
     32 #include "vkRefUtil.hpp"
     33 #include "vkPlatform.hpp"
     34 #include "vktTestCase.hpp"
     35 
     36 namespace vkt
     37 {
     38 namespace api
     39 {
     40 namespace
     41 {
     42 using namespace vk;
     43 
     44 struct BufferCaseParameters
     45 {
     46 	VkBufferUsageFlags	usage;
     47 	VkBufferCreateFlags	flags;
     48 	VkSharingMode		sharingMode;
     49 };
     50 
     51 class BufferTestInstance : public TestInstance
     52 {
     53 public:
     54 								BufferTestInstance			(Context&				ctx,
     55 															 BufferCaseParameters	testCase)
     56 									: TestInstance		(ctx)
     57 									, m_testCase		(testCase)
     58 									, m_sparseContext	(createSparseContext())
     59 								{}
     60 	virtual tcu::TestStatus		iterate						(void);
     61 	tcu::TestStatus				bufferCreateAndAllocTest	(VkDeviceSize		size);
     62 
     63 private:
     64 	BufferCaseParameters		m_testCase;
     65 
     66 private:
     67 	// Custom context for sparse cases
     68 	struct SparseContext
     69 	{
     70 		SparseContext (Move<VkDevice>& device, const deUint32 queueFamilyIndex, const InstanceInterface& interface)
     71 		: m_device				(device)
     72 		, m_queueFamilyIndex	(queueFamilyIndex)
     73 		, m_deviceInterface		(interface, *m_device)
     74 		{}
     75 
     76 		Unique<VkDevice>	m_device;
     77 		const deUint32		m_queueFamilyIndex;
     78 		DeviceDriver		m_deviceInterface;
     79 	};
     80 
     81 	de::UniquePtr<SparseContext>	m_sparseContext;
     82 
     83 	// Wrapper functions around m_context calls to support sparse cases.
     84 	VkPhysicalDevice				getPhysicalDevice (void) const
     85 	{
     86 		// Same in sparse and regular case
     87 		return m_context.getPhysicalDevice();
     88 	}
     89 
     90 	VkDevice						getDevice (void) const
     91 	{
     92 		if (m_sparseContext)
     93 			return *(m_sparseContext->m_device);
     94 
     95 		return m_context.getDevice();
     96 	}
     97 
     98 	const InstanceInterface&		getInstanceInterface (void) const
     99 	{
    100 		// Same in sparse and regular case
    101 		return m_context.getInstanceInterface();
    102 	}
    103 
    104 	const DeviceInterface&			getDeviceInterface (void) const
    105 	{
    106 		if (m_sparseContext)
    107 			return m_sparseContext->m_deviceInterface;
    108 
    109 		return m_context.getDeviceInterface();
    110 	}
    111 
    112 	deUint32						getUniversalQueueFamilyIndex (void) const
    113 	{
    114 		if (m_sparseContext)
    115 			return m_sparseContext->m_queueFamilyIndex;
    116 
    117 		return m_context.getUniversalQueueFamilyIndex();
    118 	}
    119 
    120 	static deUint32					findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
    121 	{
    122 		const std::vector<VkQueueFamilyProperties>	queueProps	= getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
    123 
    124 		for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
    125 		{
    126 			if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
    127 				return (deUint32)queueNdx;
    128 		}
    129 
    130 		TCU_THROW(NotSupportedError, "No matching queue found");
    131 	}
    132 
    133 	// Create the sparseContext
    134 	SparseContext*					createSparseContext	(void) const
    135 	{
    136 		if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
    137 			(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
    138 			(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
    139 		{
    140 			const InstanceInterface&		vk				= getInstanceInterface();
    141 			const VkPhysicalDevice			physicalDevice	= getPhysicalDevice();
    142 			const VkPhysicalDeviceFeatures	deviceFeatures	= getPhysicalDeviceFeatures(vk, physicalDevice);
    143 
    144 			const deUint32 queueIndex = findQueueFamilyIndexWithCaps(vk, physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT);
    145 
    146 			VkDeviceQueueCreateInfo			queueInfo;
    147 			VkDeviceCreateInfo				deviceInfo;
    148 			const float						queuePriority	= 1.0f;
    149 
    150 			deMemset(&queueInfo,	0, sizeof(queueInfo));
    151 			deMemset(&deviceInfo,	0, sizeof(deviceInfo));
    152 
    153 			queueInfo.sType							= VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    154 			queueInfo.pNext							= DE_NULL;
    155 			queueInfo.flags							= (VkDeviceQueueCreateFlags)0u;
    156 			queueInfo.queueFamilyIndex				= queueIndex;
    157 			queueInfo.queueCount					= 1u;
    158 			queueInfo.pQueuePriorities				= &queuePriority;
    159 
    160 			deviceInfo.sType						= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    161 			deviceInfo.pNext						= DE_NULL;
    162 			deviceInfo.queueCreateInfoCount			= 1u;
    163 			deviceInfo.pQueueCreateInfos			= &queueInfo;
    164 			deviceInfo.enabledExtensionCount		= 0u;
    165 			deviceInfo.ppEnabledExtensionNames		= DE_NULL;
    166 			deviceInfo.enabledLayerCount			= 0u;
    167 			deviceInfo.ppEnabledLayerNames			= DE_NULL;
    168 			deviceInfo.pEnabledFeatures				= &deviceFeatures;
    169 
    170 			Move<VkDevice>	device = createDevice(vk, physicalDevice, &deviceInfo);
    171 
    172 			return new SparseContext(device, queueIndex, vk);
    173 		}
    174 
    175 		return DE_NULL;
    176 	}
    177 };
    178 
    179 class BuffersTestCase : public TestCase
    180 {
    181 public:
    182 							BuffersTestCase		(tcu::TestContext&		testCtx,
    183 												 const std::string&		name,
    184 												 const std::string&		description,
    185 												 BufferCaseParameters	testCase)
    186 								: TestCase(testCtx, name, description)
    187 								, m_testCase(testCase)
    188 							{}
    189 
    190 	virtual					~BuffersTestCase	(void) {}
    191 	virtual TestInstance*	createInstance		(Context&				ctx) const
    192 							{
    193 								tcu::TestLog& log	= m_testCtx.getLog();
    194 								log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
    195 								return new BufferTestInstance(ctx, m_testCase);
    196 							}
    197 
    198 private:
    199 	BufferCaseParameters		m_testCase;
    200 };
    201 
    202 inline VkDeviceSize alignDeviceSize (VkDeviceSize val, VkDeviceSize align)
    203 {
    204 	DE_ASSERT(deIsPowerOfTwo64(align));
    205 	DE_ASSERT(val + align >= val);				// crash on overflow
    206 	return (val + align - 1) & ~(align - 1);
    207 }
    208 
    209 tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
    210 {
    211 	const VkPhysicalDevice					vkPhysicalDevice	= getPhysicalDevice();
    212 	const InstanceInterface&				vkInstance			= getInstanceInterface();
    213 	const VkDevice							vkDevice			= getDevice();
    214 	const DeviceInterface&					vk					= getDeviceInterface();
    215 	const deUint32							queueFamilyIndex	= getUniversalQueueFamilyIndex();
    216 	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
    217 	const VkPhysicalDeviceLimits			limits				= getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits;
    218 	Move<VkBuffer>							buffer;
    219 	Move<VkDeviceMemory>					memory;
    220 	VkMemoryRequirements					memReqs;
    221 
    222 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
    223 		size = std::min(size, limits.sparseAddressSpaceSize);
    224 
    225 	// Create the test buffer and a memory allocation for it
    226 	{
    227 		// Create a minimal buffer first to get the supported memory types
    228 		VkBufferCreateInfo bufferParams =
    229 		{
    230 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType        sType;
    231 			DE_NULL,								// const void*            pNext;
    232 			m_testCase.flags,						// VkBufferCreateFlags    flags;
    233 			1u,										// VkDeviceSize           size;
    234 			m_testCase.usage,						// VkBufferUsageFlags     usage;
    235 			m_testCase.sharingMode,					// VkSharingMode          sharingMode;
    236 			1u,										// uint32_t               queueFamilyIndexCount;
    237 			&queueFamilyIndex,						// const uint32_t*        pQueueFamilyIndices;
    238 		};
    239 
    240 		buffer = createBuffer(vk, vkDevice, &bufferParams);
    241 		vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);
    242 
    243 		const deUint32		heapTypeIndex	= (deUint32)deCtz32(memReqs.memoryTypeBits);
    244 		const VkMemoryType	memoryType		= memoryProperties.memoryTypes[heapTypeIndex];
    245 		const VkMemoryHeap	memoryHeap		= memoryProperties.memoryHeaps[memoryType.heapIndex];
    246 		const VkDeviceSize	maxBufferSize	= alignDeviceSize(memoryHeap.size >> 1, memReqs.alignment);
    247 		const deUint32		shrinkBits		= 4;	// number of bits to shift when reducing the size with each iteration
    248 
    249 		size = std::min(size, maxBufferSize);
    250 
    251 		while (*memory == DE_NULL)
    252 		{
    253 			// Create the buffer
    254 			{
    255 				VkResult result		= VK_ERROR_OUT_OF_HOST_MEMORY;
    256 				VkBuffer rawBuffer	= DE_NULL;
    257 
    258 				bufferParams.size	= size;
    259 				buffer				= Move<VkBuffer>();		// free the previous buffer, if any
    260 				result				= vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer);
    261 
    262 				if (result != VK_SUCCESS)
    263 				{
    264 					size = alignDeviceSize(size >> shrinkBits, memReqs.alignment);
    265 
    266 					if (size == 0 || bufferParams.size == memReqs.alignment)
    267 						return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")");
    268 
    269 					continue;	// didn't work, try with a smaller buffer
    270 				}
    271 
    272 				buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL));
    273 			}
    274 
    275 			vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);	// get the proper size requirement
    276 
    277 			if (size > memReqs.size)
    278 			{
    279 				std::ostringstream errorMsg;
    280 				errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
    281 				return tcu::TestStatus::fail(errorMsg.str());
    282 			}
    283 
    284 			// Allocate the memory
    285 			{
    286 				VkResult		result			= VK_ERROR_OUT_OF_HOST_MEMORY;
    287 				VkDeviceMemory	rawMemory		= DE_NULL;
    288 
    289 				const VkMemoryAllocateInfo memAlloc =
    290 				{
    291 					VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,		// VkStructureType    sType;
    292 					NULL,										// const void*        pNext;
    293 					memReqs.size,								// VkDeviceSize       allocationSize;
    294 					heapTypeIndex,								// uint32_t           memoryTypeIndex;
    295 				};
    296 
    297 				result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
    298 
    299 				if (result != VK_SUCCESS)
    300 				{
    301 					size = alignDeviceSize(size >> shrinkBits, memReqs.alignment);
    302 
    303 					if (size == 0 || memReqs.size == memReqs.alignment)
    304 						return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory");
    305 
    306 					continue;	// didn't work, try with a smaller allocation (and a smaller buffer)
    307 				}
    308 
    309 				memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
    310 			}
    311 		} // while
    312 	}
    313 
    314 	// Bind the memory
    315 	if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0)
    316 	{
    317 		VkQueue								queue					= DE_NULL;
    318 
    319 		vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue);
    320 
    321 		const VkSparseMemoryBind			sparseMemoryBind		=
    322 		{
    323 			0,										// VkDeviceSize								resourceOffset;
    324 			memReqs.size,							// VkDeviceSize								size;
    325 			*memory,								// VkDeviceMemory							memory;
    326 			0,										// VkDeviceSize								memoryOffset;
    327 			0										// VkSparseMemoryBindFlags					flags;
    328 		};
    329 
    330 		const VkSparseBufferMemoryBindInfo	sparseBufferMemoryBindInfo	=
    331 		{
    332 			*buffer,							// VkBuffer									buffer;
    333 			1u,										// deUint32									bindCount;
    334 			&sparseMemoryBind						// const VkSparseMemoryBind*				pBinds;
    335 		};
    336 
    337 		const VkBindSparseInfo				bindSparseInfo			=
    338 		{
    339 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,		// VkStructureType							sType;
    340 			DE_NULL,								// const void*								pNext;
    341 			0,										// deUint32									waitSemaphoreCount;
    342 			DE_NULL,								// const VkSemaphore*						pWaitSemaphores;
    343 			1u,										// deUint32									bufferBindCount;
    344 			&sparseBufferMemoryBindInfo,			// const VkSparseBufferMemoryBindInfo*		pBufferBinds;
    345 			0,										// deUint32									imageOpaqueBindCount;
    346 			DE_NULL,								// const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
    347 			0,										// deUint32									imageBindCount;
    348 			DE_NULL,								// const VkSparseImageMemoryBindInfo*		pImageBinds;
    349 			0,										// deUint32									signalSemaphoreCount;
    350 			DE_NULL,								// const VkSemaphore*						pSignalSemaphores;
    351 		};
    352 
    353 		const VkFenceCreateInfo fenceParams =
    354 		{
    355 			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
    356 			DE_NULL,								// const void*			pNext;
    357 			0u										// VkFenceCreateFlags	flags;
    358 		};
    359 
    360 		const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams));
    361 
    362 		if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
    363 			return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
    364 
    365 		VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
    366 	}
    367 	else
    368 	{
    369 		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 	}
    372 
    373 	return tcu::TestStatus::pass("Pass");
    374 }
    375 
    376 tcu::TestStatus BufferTestInstance::iterate (void)
    377 {
    378 	const VkPhysicalDeviceFeatures&	physicalDeviceFeatures	= getPhysicalDeviceFeatures(getInstanceInterface(), getPhysicalDevice());
    379 
    380 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding)
    381 		TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
    382 
    383 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer)
    384 		TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
    385 
    386 	if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased)
    387 		TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
    388 
    389 	const VkDeviceSize testSizes[] =
    390 	{
    391 		1,
    392 		1181,
    393 		15991,
    394 		16384,
    395 		~0ull,		// try to exercise a very large buffer too (will be clamped to a sensible size later)
    396 	};
    397 
    398 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i)
    399 	{
    400 		const tcu::TestStatus testStatus = bufferCreateAndAllocTest(testSizes[i]);
    401 
    402 		if (testStatus.getCode() != QP_TEST_RESULT_PASS)
    403 			return testStatus;
    404 	}
    405 
    406 	return tcu::TestStatus::pass("Pass");
    407 }
    408 
    409 } // anonymous
    410 
    411  tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
    412 {
    413 	const VkBufferUsageFlags bufferUsageModes[] =
    414 	{
    415 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
    416 		VK_BUFFER_USAGE_TRANSFER_DST_BIT,
    417 		VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
    418 		VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
    419 		VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
    420 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    421 		VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
    422 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
    423 		VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
    424 	};
    425 
    426 	// \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag.
    427 	const VkBufferCreateFlags bufferCreateFlags[] =
    428 	{
    429 		0,
    430 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
    431 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT	|	VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
    432 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT	|												VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
    433 		VK_BUFFER_CREATE_SPARSE_BINDING_BIT	|	VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT	|	VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
    434 	};
    435 
    436 	de::MovePtr<tcu::TestCaseGroup>	buffersTests	(new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
    437 
    438 	const deUint32 maximumValueOfBufferUsageFlags	= (1u << (DE_LENGTH_OF_ARRAY(bufferUsageModes) - 1)) - 1u;
    439 
    440 	for (deUint32 bufferCreateFlagsNdx = 0u; bufferCreateFlagsNdx < DE_LENGTH_OF_ARRAY(bufferCreateFlags); bufferCreateFlagsNdx++)
    441 	for (deUint32 combinedBufferUsageFlags = 1u; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++)
    442 	{
    443 		const BufferCaseParameters	testParams =
    444 		{
    445 			combinedBufferUsageFlags,
    446 			bufferCreateFlags[bufferCreateFlagsNdx],
    447 			VK_SHARING_MODE_EXCLUSIVE
    448 		};
    449 		std::ostringstream	testName;
    450 		std::ostringstream	testDescription;
    451 		testName << "create_buffer_" << combinedBufferUsageFlags << "_" << testParams.flags;
    452 		testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << testParams.flags;
    453 		buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams));
    454 	}
    455 
    456 	return buffersTests.release();
    457 }
    458 
    459 } // api
    460 } // vk
    461