• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 namespace vkt
41 {
42 namespace synchronization
43 {
44 namespace
45 {
46 using namespace vk;
47 
48 class BaseTestInstance : public TestInstance
49 {
50 public:
BaseTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)51 	BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
52 		: TestInstance	(context)
53 		, m_opContext	(context, pipelineCacheData)
54 		, m_resource	(new Resource(m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
55 		, m_writeOp		(writeOp.build(m_opContext, *m_resource))
56 		, m_readOp		(readOp.build(m_opContext, *m_resource))
57 	{
58 	}
59 
60 protected:
61 	OperationContext					m_opContext;
62 	const de::UniquePtr<Resource>		m_resource;
63 	const de::UniquePtr<Operation>		m_writeOp;
64 	const de::UniquePtr<Operation>		m_readOp;
65 };
66 
67 class EventTestInstance : public BaseTestInstance
68 {
69 public:
EventTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)70 	EventTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
71 		: BaseTestInstance		(context, resourceDesc, writeOp, readOp, pipelineCacheData)
72 	{
73 	}
74 
iterate(void)75 	tcu::TestStatus iterate (void)
76 	{
77 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
78 		const VkDevice					device				= m_context.getDevice();
79 		const VkQueue					queue				= m_context.getUniversalQueue();
80 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
81 		const Unique<VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
82 		const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
83 		const Unique<VkEvent>			event				(makeEvent(vk, device));
84 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
85 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
86 
87 		beginCommandBuffer(vk, *cmdBuffer);
88 
89 		m_writeOp->recordCommands(*cmdBuffer);
90 		vk.cmdSetEvent(*cmdBuffer, *event, writeSync.stageMask);
91 
92 		if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
93 		{
94 			const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
95 				m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
96 			vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
97 		}
98 		else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
99 		{
100 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
101 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
102 			vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
103 		}
104 
105 		m_readOp->recordCommands(*cmdBuffer);
106 
107 		endCommandBuffer(vk, *cmdBuffer);
108 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
109 
110 		{
111 			const Data	expected = m_writeOp->getData();
112 			const Data	actual	 = m_readOp->getData();
113 
114 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
115 				return tcu::TestStatus::fail("Memory contents don't match");
116 		}
117 
118 		return tcu::TestStatus::pass("OK");
119 	}
120 };
121 
122 class BarrierTestInstance : public BaseTestInstance
123 {
124 public:
BarrierTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)125 	BarrierTestInstance	(Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
126 		: BaseTestInstance		(context, resourceDesc, writeOp, readOp, pipelineCacheData)
127 	{
128 	}
129 
iterate(void)130 	tcu::TestStatus iterate (void)
131 	{
132 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
133 		const VkDevice					device				= m_context.getDevice();
134 		const VkQueue					queue				= m_context.getUniversalQueue();
135 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
136 		const Unique<VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
137 		const Move<VkCommandBuffer>		cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
138 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
139 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
140 
141 		beginCommandBuffer(vk, *cmdBuffer);
142 
143 		m_writeOp->recordCommands(*cmdBuffer);
144 
145 		if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
146 		{
147 			const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
148 				m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
149 			vk.cmdPipelineBarrier(*cmdBuffer,  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
150 		}
151 		else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
152 		{
153 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
154 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
155 			vk.cmdPipelineBarrier(*cmdBuffer,  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
156 		}
157 
158 		m_readOp->recordCommands(*cmdBuffer);
159 
160 		endCommandBuffer(vk, *cmdBuffer);
161 
162 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
163 
164 		{
165 			const Data	expected = m_writeOp->getData();
166 			const Data	actual	 = m_readOp->getData();
167 
168 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
169 				return tcu::TestStatus::fail("Memory contents don't match");
170 		}
171 
172 		return tcu::TestStatus::pass("OK");
173 	}
174 };
175 
176 class SemaphoreTestInstance : public BaseTestInstance
177 {
178 public:
SemaphoreTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)179 	SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
180 		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
181 	{
182 	}
183 
iterate(void)184 	tcu::TestStatus	iterate (void)
185 	{
186 		enum {WRITE=0, READ, COUNT};
187 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
188 		const VkDevice					device				= m_context.getDevice();
189 		const VkQueue					queue				= m_context.getUniversalQueue();
190 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
191 		const VkSemaphoreCreateInfo		semaphoreInfo		=
192 															{
193 																VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,	//VkStructureType			sType;
194 																DE_NULL,									//const void*				pNext;
195 																0u											//VkSemaphoreCreateFlags	flags;
196 															};
197 		const Unique<VkSemaphore>		semaphore			(createSemaphore (vk, device, &semaphoreInfo, DE_NULL));
198 		const Unique<VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
199 		const Move<VkCommandBuffer>		ptrCmdBuffer[COUNT]	= {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
200 		VkCommandBuffer					cmdBuffers[COUNT]	= {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
201 		const VkPipelineStageFlags		stageBits[]			= { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
202 		const VkSubmitInfo				submitInfo[2]		=
203 															{
204 																{
205 																	VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType			sType;
206 																	DE_NULL,							// const void*				pNext;
207 																	0u,									// deUint32					waitSemaphoreCount;
208 																	DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
209 																	(const VkPipelineStageFlags*)DE_NULL,
210 																	1u,									// deUint32					commandBufferCount;
211 																	&cmdBuffers[WRITE],					// const VkCommandBuffer*	pCommandBuffers;
212 																	1u,									// deUint32					signalSemaphoreCount;
213 																	&semaphore.get(),					// const VkSemaphore*		pSignalSemaphores;
214 																},
215 																{
216 																	VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType				sType;
217 																	DE_NULL,							// const void*					pNext;
218 																	1u,									// deUint32						waitSemaphoreCount;
219 																	&semaphore.get(),					// const VkSemaphore*			pWaitSemaphores;
220 																	stageBits,							// const VkPipelineStageFlags*	pWaitDstStageMask;
221 																	1u,									// deUint32						commandBufferCount;
222 																	&cmdBuffers[READ],					// const VkCommandBuffer*		pCommandBuffers;
223 																	0u,									// deUint32						signalSemaphoreCount;
224 																	DE_NULL,							// const VkSemaphore*			pSignalSemaphores;
225 																}
226 															};
227 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
228 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
229 
230 		beginCommandBuffer(vk, cmdBuffers[WRITE]);
231 
232 		m_writeOp->recordCommands(cmdBuffers[WRITE]);
233 
234 		if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
235 		{
236 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
237 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
238 			vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
239 		}
240 
241 		endCommandBuffer(vk, cmdBuffers[WRITE]);
242 
243 		beginCommandBuffer(vk, cmdBuffers[READ]);
244 
245 		m_readOp->recordCommands(cmdBuffers[READ]);
246 
247 		endCommandBuffer(vk, cmdBuffers[READ]);
248 
249 		VK_CHECK(vk.queueSubmit(queue, 2u, submitInfo, DE_NULL));
250 		VK_CHECK(vk.queueWaitIdle(queue));
251 
252 		{
253 			const Data	expected = m_writeOp->getData();
254 			const Data	actual	 = m_readOp->getData();
255 
256 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
257 				return tcu::TestStatus::fail("Memory contents don't match");
258 		}
259 
260 		return tcu::TestStatus::pass("OK");
261 	}
262 };
263 
264 class FenceTestInstance : public BaseTestInstance
265 {
266 public:
FenceTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)267 	FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
268 		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
269 	{
270 	}
271 
iterate(void)272 	tcu::TestStatus	iterate (void)
273 	{
274 		enum {WRITE=0, READ, COUNT};
275 		const DeviceInterface&			vk					= m_context.getDeviceInterface();
276 		const VkDevice					device				= m_context.getDevice();
277 		const VkQueue					queue				= m_context.getUniversalQueue();
278 		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
279 		const Unique<VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
280 		const Move<VkCommandBuffer>		ptrCmdBuffer[COUNT]	= {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
281 		VkCommandBuffer					cmdBuffers[COUNT]	= {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
282 		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
283 		const SyncInfo					readSync			= m_readOp->getSyncInfo();
284 
285 		beginCommandBuffer(vk, cmdBuffers[WRITE]);
286 
287 		m_writeOp->recordCommands(cmdBuffers[WRITE]);
288 
289 		if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
290 		{
291 			const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
292 				writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
293 			vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
294 		}
295 
296 		endCommandBuffer(vk, cmdBuffers[WRITE]);
297 
298 		submitCommandsAndWait(vk, device, queue, cmdBuffers[WRITE]);
299 
300 		beginCommandBuffer(vk, cmdBuffers[READ]);
301 
302 		m_readOp->recordCommands(cmdBuffers[READ]);
303 
304 		endCommandBuffer(vk, cmdBuffers[READ]);
305 
306 		submitCommandsAndWait(vk, device, queue, cmdBuffers[READ]);
307 
308 		{
309 			const Data	expected = m_writeOp->getData();
310 			const Data	actual	 = m_readOp->getData();
311 
312 			if (0 != deMemCmp(expected.data, actual.data, expected.size))
313 				return tcu::TestStatus::fail("Memory contents don't match");
314 		}
315 
316 		return tcu::TestStatus::pass("OK");
317 	}
318 };
319 
320 class SyncTestCase : public TestCase
321 {
322 public:
SyncTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const SyncPrimitive syncPrimitive,const ResourceDescription resourceDesc,const OperationName writeOp,const OperationName readOp,PipelineCacheData & pipelineCacheData)323 	SyncTestCase	(tcu::TestContext&			testCtx,
324 					 const std::string&			name,
325 					 const std::string&			description,
326 					 const SyncPrimitive		syncPrimitive,
327 					 const ResourceDescription	resourceDesc,
328 					 const OperationName		writeOp,
329 					 const OperationName		readOp,
330 					 PipelineCacheData&			pipelineCacheData)
331 		: TestCase				(testCtx, name, description)
332 		, m_resourceDesc		(resourceDesc)
333 		, m_writeOp				(makeOperationSupport(writeOp, resourceDesc))
334 		, m_readOp				(makeOperationSupport(readOp, resourceDesc))
335 		, m_syncPrimitive		(syncPrimitive)
336 		, m_pipelineCacheData	(pipelineCacheData)
337 	{
338 	}
339 
initPrograms(SourceCollections & programCollection) const340 	void initPrograms (SourceCollections& programCollection) const
341 	{
342 		m_writeOp->initPrograms(programCollection);
343 		m_readOp->initPrograms(programCollection);
344 	}
345 
createInstance(Context & context) const346 	TestInstance* createInstance (Context& context) const
347 	{
348 		switch (m_syncPrimitive)
349 		{
350 			case SYNC_PRIMITIVE_FENCE:
351 				return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
352 			case SYNC_PRIMITIVE_SEMAPHORE:
353 				return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
354 			case SYNC_PRIMITIVE_BARRIER:
355 				return new BarrierTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
356 			case SYNC_PRIMITIVE_EVENT:
357 				return new EventTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
358 		}
359 
360 		DE_ASSERT(0);
361 		return DE_NULL;
362 	}
363 
364 private:
365 	const ResourceDescription				m_resourceDesc;
366 	const de::UniquePtr<OperationSupport>	m_writeOp;
367 	const de::UniquePtr<OperationSupport>	m_readOp;
368 	const SyncPrimitive						m_syncPrimitive;
369 	PipelineCacheData&						m_pipelineCacheData;
370 };
371 
createTests(tcu::TestCaseGroup * group,PipelineCacheData * pipelineCacheData)372 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
373 {
374 	tcu::TestContext& testCtx = group->getTestContext();
375 
376 	static const struct
377 	{
378 		const char*		name;
379 		SyncPrimitive	syncPrimitive;
380 		int				numOptions;
381 	} groups[] =
382 	{
383 		{ "fence",		SYNC_PRIMITIVE_FENCE,		0, },
384 		{ "semaphore",	SYNC_PRIMITIVE_SEMAPHORE,	0, },
385 		{ "barrier",	SYNC_PRIMITIVE_BARRIER,		1, },
386 		{ "event",		SYNC_PRIMITIVE_EVENT,		1, },
387 	};
388 
389 	for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
390 	{
391 		de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
392 
393 		for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
394 		for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
395 		{
396 			const OperationName	writeOp		= s_writeOps[writeOpNdx];
397 			const OperationName	readOp		= s_readOps[readOpNdx];
398 			const std::string	opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
399 			bool				empty		= true;
400 
401 			de::MovePtr<tcu::TestCaseGroup> opGroup	(new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
402 
403 			for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
404 			{
405 				const ResourceDescription&	resource	= s_resources[resourceNdx];
406 				std::string					name		= getResourceName(resource);
407 
408 				if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
409 				{
410 					opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, *pipelineCacheData));
411 					empty = false;
412 				}
413 			}
414 			if (!empty)
415 				synchGroup->addChild(opGroup.release());
416 		}
417 
418 		group->addChild(synchGroup.release());
419 	}
420 }
421 
422 } // anonymous
423 
createSynchronizedOperationSingleQueueTests(tcu::TestContext & testCtx,PipelineCacheData & pipelineCacheData)424 tcu::TestCaseGroup* createSynchronizedOperationSingleQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
425 {
426 	return createTestGroup(testCtx, "single_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
427 }
428 
429 } // synchronization
430 } // vkt
431