Home | History | Annotate | Download | only in synchronization
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2016 The Khronos Group Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Synchronization primitive tests with single queue
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktSynchronizationOperationSingleQueueTests.hpp"
     25 #include "vkDefs.hpp"
     26 #include "vktTestCase.hpp"
     27 #include "vktTestCaseUtil.hpp"
     28 #include "vktTestGroupUtil.hpp"
     29 #include "vkRef.hpp"
     30 #include "vkRefUtil.hpp"
     31 #include "vkMemUtil.hpp"
     32 #include "vkQueryUtil.hpp"
     33 #include "vkTypeUtil.hpp"
     34 #include "deUniquePtr.hpp"
     35 #include "tcuTestLog.hpp"
     36 #include "vktSynchronizationUtil.hpp"
     37 #include "vktSynchronizationOperation.hpp"
     38 #include "vktSynchronizationOperationTestData.hpp"
     39 #include "vktSynchronizationOperationResources.hpp"
     40 
     41 namespace vkt
     42 {
     43 namespace synchronization
     44 {
     45 namespace
     46 {
     47 using namespace vk;
     48 
     49 class BaseTestInstance : public TestInstance
     50 {
     51 public:
     52 	BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
     53 		: TestInstance	(context)
     54 		, m_opContext	(context, pipelineCacheData)
     55 		, m_resource	(new Resource(m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
     56 		, m_writeOp		(writeOp.build(m_opContext, *m_resource))
     57 		, m_readOp		(readOp.build(m_opContext, *m_resource))
     58 	{
     59 	}
     60 
     61 protected:
     62 	OperationContext					m_opContext;
     63 	const de::UniquePtr<Resource>		m_resource;
     64 	const de::UniquePtr<Operation>		m_writeOp;
     65 	const de::UniquePtr<Operation>		m_readOp;
     66 };
     67 
     68 class EventTestInstance : public BaseTestInstance
     69 {
     70 public:
     71 	EventTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
     72 		: BaseTestInstance		(context, resourceDesc, writeOp, readOp, pipelineCacheData)
     73 	{
     74 	}
     75 
     76 	tcu::TestStatus iterate (void)
     77 	{
     78 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
     79 		const VkDevice					device				= m_context.getDevice();
     80 		const VkQueue					queue				= m_context.getUniversalQueue();
     81 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
     82 		const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
     83 		const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
     84 		const Unique<VkEvent>			event				(createEvent(vk, device));
     85 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
     86 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
     87 
     88 		beginCommandBuffer(vk, *cmdBuffer);
     89 
     90 		m_writeOp->recordCommands(*cmdBuffer);
     91 		vk.cmdSetEvent(*cmdBuffer, *event, writeSync.stageMask);
     92 
     93 		if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
     94 		{
     95 			const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
     96 				m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
     97 			vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
     98 		}
     99 		else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
    100 		{
    101 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
    102 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
    103 			vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
    104 		}
    105 
    106 		m_readOp->recordCommands(*cmdBuffer);
    107 
    108 		endCommandBuffer(vk, *cmdBuffer);
    109 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
    110 
    111 		{
    112 			const Data	expected = m_writeOp->getData();
    113 			const Data	actual	 = m_readOp->getData();
    114 
    115 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
    116 				return tcu::TestStatus::fail("Memory contents don't match");
    117 		}
    118 
    119 		return tcu::TestStatus::pass("OK");
    120 	}
    121 };
    122 
    123 class BarrierTestInstance : public BaseTestInstance
    124 {
    125 public:
    126 	BarrierTestInstance	(Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
    127 		: BaseTestInstance		(context, resourceDesc, writeOp, readOp, pipelineCacheData)
    128 	{
    129 	}
    130 
    131 	tcu::TestStatus iterate (void)
    132 	{
    133 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
    134 		const VkDevice					device				= m_context.getDevice();
    135 		const VkQueue					queue				= m_context.getUniversalQueue();
    136 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
    137 		const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
    138 		const Move<VkCommandBuffer>		cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
    139 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
    140 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
    141 
    142 		beginCommandBuffer(vk, *cmdBuffer);
    143 
    144 		m_writeOp->recordCommands(*cmdBuffer);
    145 
    146 		if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
    147 		{
    148 			const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
    149 				m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
    150 			vk.cmdPipelineBarrier(*cmdBuffer,  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
    151 		}
    152 		else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
    153 		{
    154 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
    155 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
    156 			vk.cmdPipelineBarrier(*cmdBuffer,  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
    157 		}
    158 
    159 		m_readOp->recordCommands(*cmdBuffer);
    160 
    161 		endCommandBuffer(vk, *cmdBuffer);
    162 
    163 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
    164 
    165 		{
    166 			const Data	expected = m_writeOp->getData();
    167 			const Data	actual	 = m_readOp->getData();
    168 
    169 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
    170 				return tcu::TestStatus::fail("Memory contents don't match");
    171 		}
    172 
    173 		return tcu::TestStatus::pass("OK");
    174 	}
    175 };
    176 
    177 class SemaphoreTestInstance : public BaseTestInstance
    178 {
    179 public:
    180 	SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
    181 		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
    182 	{
    183 	}
    184 
    185 	tcu::TestStatus	iterate (void)
    186 	{
    187 		enum {WRITE=0, READ, COUNT};
    188 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
    189 		const VkDevice					device				= m_context.getDevice();
    190 		const VkQueue					queue				= m_context.getUniversalQueue();
    191 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
    192 		const Unique<VkSemaphore>		semaphore			(createSemaphore (vk, device));
    193 		const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
    194 		const Move<VkCommandBuffer>		ptrCmdBuffer[COUNT]	= {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
    195 		VkCommandBuffer					cmdBuffers[COUNT]	= {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
    196 		const VkPipelineStageFlags		stageBits[]			= { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
    197 		const VkSubmitInfo				submitInfo[2]		=
    198 															{
    199 																{
    200 																	VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType			sType;
    201 																	DE_NULL,							// const void*				pNext;
    202 																	0u,									// deUint32					waitSemaphoreCount;
    203 																	DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
    204 																	(const VkPipelineStageFlags*)DE_NULL,
    205 																	1u,									// deUint32					commandBufferCount;
    206 																	&cmdBuffers[WRITE],					// const VkCommandBuffer*	pCommandBuffers;
    207 																	1u,									// deUint32					signalSemaphoreCount;
    208 																	&semaphore.get(),					// const VkSemaphore*		pSignalSemaphores;
    209 																},
    210 																{
    211 																	VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType				sType;
    212 																	DE_NULL,							// const void*					pNext;
    213 																	1u,									// deUint32						waitSemaphoreCount;
    214 																	&semaphore.get(),					// const VkSemaphore*			pWaitSemaphores;
    215 																	stageBits,							// const VkPipelineStageFlags*	pWaitDstStageMask;
    216 																	1u,									// deUint32						commandBufferCount;
    217 																	&cmdBuffers[READ],					// const VkCommandBuffer*		pCommandBuffers;
    218 																	0u,									// deUint32						signalSemaphoreCount;
    219 																	DE_NULL,							// const VkSemaphore*			pSignalSemaphores;
    220 																}
    221 															};
    222 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
    223 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
    224 
    225 		beginCommandBuffer(vk, cmdBuffers[WRITE]);
    226 
    227 		m_writeOp->recordCommands(cmdBuffers[WRITE]);
    228 
    229 		if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
    230 		{
    231 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
    232 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
    233 			vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
    234 		}
    235 
    236 		endCommandBuffer(vk, cmdBuffers[WRITE]);
    237 
    238 		beginCommandBuffer(vk, cmdBuffers[READ]);
    239 
    240 		m_readOp->recordCommands(cmdBuffers[READ]);
    241 
    242 		endCommandBuffer(vk, cmdBuffers[READ]);
    243 
    244 		VK_CHECK(vk.queueSubmit(queue, 2u, submitInfo, DE_NULL));
    245 		VK_CHECK(vk.queueWaitIdle(queue));
    246 
    247 		{
    248 			const Data	expected = m_writeOp->getData();
    249 			const Data	actual	 = m_readOp->getData();
    250 
    251 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
    252 				return tcu::TestStatus::fail("Memory contents don't match");
    253 		}
    254 
    255 		return tcu::TestStatus::pass("OK");
    256 	}
    257 };
    258 
    259 class FenceTestInstance : public BaseTestInstance
    260 {
    261 public:
    262 	FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
    263 		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
    264 	{
    265 	}
    266 
    267 	tcu::TestStatus	iterate (void)
    268 	{
    269 		enum {WRITE=0, READ, COUNT};
    270 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
    271 		const VkDevice					device				= m_context.getDevice();
    272 		const VkQueue					queue				= m_context.getUniversalQueue();
    273 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
    274 		const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
    275 		const Move<VkCommandBuffer>		ptrCmdBuffer[COUNT]	= {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
    276 		VkCommandBuffer					cmdBuffers[COUNT]	= {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
    277 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
    278 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
    279 
    280 		beginCommandBuffer(vk, cmdBuffers[WRITE]);
    281 
    282 		m_writeOp->recordCommands(cmdBuffers[WRITE]);
    283 
    284 		if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
    285 		{
    286 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
    287 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
    288 			vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
    289 		}
    290 
    291 		endCommandBuffer(vk, cmdBuffers[WRITE]);
    292 
    293 		submitCommandsAndWait(vk, device, queue, cmdBuffers[WRITE]);
    294 
    295 		beginCommandBuffer(vk, cmdBuffers[READ]);
    296 
    297 		m_readOp->recordCommands(cmdBuffers[READ]);
    298 
    299 		endCommandBuffer(vk, cmdBuffers[READ]);
    300 
    301 		submitCommandsAndWait(vk, device, queue, cmdBuffers[READ]);
    302 
    303 		{
    304 			const Data	expected = m_writeOp->getData();
    305 			const Data	actual	 = m_readOp->getData();
    306 
    307 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
    308 				return tcu::TestStatus::fail("Memory contents don't match");
    309 		}
    310 
    311 		return tcu::TestStatus::pass("OK");
    312 	}
    313 };
    314 
    315 class SyncTestCase : public TestCase
    316 {
    317 public:
    318 	SyncTestCase	(tcu::TestContext&			testCtx,
    319 					 const std::string&			name,
    320 					 const std::string&			description,
    321 					 const SyncPrimitive		syncPrimitive,
    322 					 const ResourceDescription	resourceDesc,
    323 					 const OperationName		writeOp,
    324 					 const OperationName		readOp,
    325 					 PipelineCacheData&			pipelineCacheData)
    326 		: TestCase				(testCtx, name, description)
    327 		, m_resourceDesc		(resourceDesc)
    328 		, m_writeOp				(makeOperationSupport(writeOp, resourceDesc))
    329 		, m_readOp				(makeOperationSupport(readOp, resourceDesc))
    330 		, m_syncPrimitive		(syncPrimitive)
    331 		, m_pipelineCacheData	(pipelineCacheData)
    332 	{
    333 	}
    334 
    335 	void initPrograms (SourceCollections& programCollection) const
    336 	{
    337 		m_writeOp->initPrograms(programCollection);
    338 		m_readOp->initPrograms(programCollection);
    339 	}
    340 
    341 	TestInstance* createInstance (Context& context) const
    342 	{
    343 		switch (m_syncPrimitive)
    344 		{
    345 			case SYNC_PRIMITIVE_FENCE:
    346 				return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
    347 			case SYNC_PRIMITIVE_SEMAPHORE:
    348 				return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
    349 			case SYNC_PRIMITIVE_BARRIER:
    350 				return new BarrierTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
    351 			case SYNC_PRIMITIVE_EVENT:
    352 				return new EventTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
    353 		}
    354 
    355 		DE_ASSERT(0);
    356 		return DE_NULL;
    357 	}
    358 
    359 private:
    360 	const ResourceDescription				m_resourceDesc;
    361 	const de::UniquePtr<OperationSupport>	m_writeOp;
    362 	const de::UniquePtr<OperationSupport>	m_readOp;
    363 	const SyncPrimitive						m_syncPrimitive;
    364 	PipelineCacheData&						m_pipelineCacheData;
    365 };
    366 
    367 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
    368 {
    369 	tcu::TestContext& testCtx = group->getTestContext();
    370 
    371 	static const struct
    372 	{
    373 		const char*		name;
    374 		SyncPrimitive	syncPrimitive;
    375 		int				numOptions;
    376 	} groups[] =
    377 	{
    378 		{ "fence",		SYNC_PRIMITIVE_FENCE,		0, },
    379 		{ "semaphore",	SYNC_PRIMITIVE_SEMAPHORE,	0, },
    380 		{ "barrier",	SYNC_PRIMITIVE_BARRIER,		1, },
    381 		{ "event",		SYNC_PRIMITIVE_EVENT,		1, },
    382 	};
    383 
    384 	for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
    385 	{
    386 		de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
    387 
    388 		for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
    389 		for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
    390 		{
    391 			const OperationName	writeOp		= s_writeOps[writeOpNdx];
    392 			const OperationName	readOp		= s_readOps[readOpNdx];
    393 			const std::string	opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
    394 			bool				empty		= true;
    395 
    396 			de::MovePtr<tcu::TestCaseGroup> opGroup	(new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
    397 
    398 			for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
    399 			{
    400 				const ResourceDescription&	resource	= s_resources[resourceNdx];
    401 				std::string					name		= getResourceName(resource);
    402 
    403 				if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
    404 				{
    405 					opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, *pipelineCacheData));
    406 					empty = false;
    407 				}
    408 			}
    409 			if (!empty)
    410 				synchGroup->addChild(opGroup.release());
    411 		}
    412 
    413 		group->addChild(synchGroup.release());
    414 	}
    415 }
    416 
    417 } // anonymous
    418 
    419 tcu::TestCaseGroup* createSynchronizedOperationSingleQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
    420 {
    421 	return createTestGroup(testCtx, "single_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
    422 }
    423 
    424 } // synchronization
    425 } // vkt
    426