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 multi queue
22 *//*--------------------------------------------------------------------*/
23
24#include "vktSynchronizationOperationMultiQueueTests.hpp"
25#include "vkDefs.hpp"
26#include "vktTestCase.hpp"
27#include "vktTestCaseUtil.hpp"
28#include "vkRef.hpp"
29#include "vkRefUtil.hpp"
30#include "vkMemUtil.hpp"
31#include "vkQueryUtil.hpp"
32#include "vkTypeUtil.hpp"
33#include "vkPlatform.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#include "vktTestGroupUtil.hpp"
41
42namespace vkt
43{
44namespace synchronization
45{
46namespace
47{
48using namespace vk;
49using de::MovePtr;
50using de::UniquePtr;
51
52enum QueueType
53{
54	QUEUETYPE_WRITE,
55	QUEUETYPE_READ
56};
57
58struct QueuePair
59{
60	QueuePair	(const deUint32 familyWrite, const deUint32 familyRead, const VkQueue write, const VkQueue read)
61		: familyIndexWrite	(familyWrite)
62		, familyIndexRead	(familyRead)
63		, queueWrite		(write)
64		, queueRead			(read)
65	{}
66
67	deUint32	familyIndexWrite;
68	deUint32	familyIndexRead;
69	VkQueue		queueWrite;
70	VkQueue		queueRead;
71};
72
73bool checkQueueFlags (VkQueueFlags availableFlags, const VkQueueFlags neededFlags)
74{
75	if ((availableFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) != 0)
76		availableFlags |= VK_QUEUE_TRANSFER_BIT;
77
78	return (availableFlags & neededFlags) != 0;
79}
80
81class MultiQueues
82{
83	struct QueueData
84	{
85		VkQueueFlags			flags;
86		std::vector<VkQueue>	queue;
87	};
88
89public:
90	MultiQueues	(const Context& context)
91	{
92		const InstanceInterface&					instance				= context.getInstanceInterface();
93		const VkPhysicalDevice						physicalDevice			= context.getPhysicalDevice();
94		const std::vector<VkQueueFamilyProperties>	queueFamilyProperties	= getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice);
95
96		for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
97		{
98			addQueueIndex(queuePropertiesNdx,
99						  std::min(2u, queueFamilyProperties[queuePropertiesNdx].queueCount),
100						  queueFamilyProperties[queuePropertiesNdx].queueFlags);
101		}
102
103		std::vector<VkDeviceQueueCreateInfo>	queueInfos;
104		const float								queuePriorities[2] = { 1.0f, 1.0f };	//get max 2 queues from one family
105
106		for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
107		{
108			const VkDeviceQueueCreateInfo queueInfo	=
109			{
110				VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,		//VkStructureType			sType;
111				DE_NULL,										//const void*				pNext;
112				(VkDeviceQueueCreateFlags)0u,					//VkDeviceQueueCreateFlags	flags;
113				it->first,										//deUint32					queueFamilyIndex;
114				static_cast<deUint32>(it->second.queue.size()),	//deUint32					queueCount;
115				&queuePriorities[0]								//const float*				pQueuePriorities;
116			};
117			queueInfos.push_back(queueInfo);
118		}
119
120		{
121			const VkDeviceCreateInfo		deviceInfo		=
122			{
123				VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,							//VkStructureType					sType;
124				DE_NULL,														//const void*						pNext;
125				0u,																//VkDeviceCreateFlags				flags;
126				static_cast<deUint32>(queueInfos.size()),						//deUint32							queueCreateInfoCount;
127				&queueInfos[0],													//const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
128				0u,																//deUint32							enabledLayerCount;
129				DE_NULL,														//const char* const*				ppEnabledLayerNames;
130				0u,																//deUint32							enabledExtensionCount;
131				DE_NULL,														//const char* const*				ppEnabledExtensionNames;
132				&context.getDeviceFeatures()									//const VkPhysicalDeviceFeatures*	pEnabledFeatures;
133			};
134
135			m_logicalDevice	= createDevice(instance, physicalDevice, &deviceInfo);
136			m_deviceDriver	= MovePtr<DeviceDriver>(new DeviceDriver(instance, *m_logicalDevice));
137			m_allocator		= MovePtr<Allocator>(new SimpleAllocator(*m_deviceDriver, *m_logicalDevice, getPhysicalDeviceMemoryProperties(instance, physicalDevice)));
138
139			for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
140			for (int queueNdx = 0; queueNdx < static_cast<int>(it->second.queue.size()); ++queueNdx)
141				m_deviceDriver->getDeviceQueue(*m_logicalDevice, it->first, queueNdx, &it->second.queue[queueNdx]);
142		}
143	}
144
145	void addQueueIndex (const deUint32 queueFamilyIndex, const deUint32 count, const VkQueueFlags flags)
146	{
147		QueueData dataToPush;
148		dataToPush.flags = flags;
149		dataToPush.queue.resize(count);
150		m_queues[queueFamilyIndex] = dataToPush;
151	}
152
153	std::vector<QueuePair> getQueuesPairs (const VkQueueFlags flagsWrite, const VkQueueFlags flagsRead)
154	{
155		std::map<deUint32, QueueData>	queuesWrite;
156		std::map<deUint32, QueueData>	queuesRead;
157		std::vector<QueuePair>			queuesPairs;
158
159		for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
160		{
161			const bool writeQueue	= checkQueueFlags(it->second.flags, flagsWrite);
162			const bool readQueue	= checkQueueFlags(it->second.flags, flagsRead);
163
164			if (!(writeQueue || readQueue))
165				continue;
166
167			if (writeQueue && readQueue)
168			{
169				queuesWrite[it->first]	= it->second;
170				queuesRead[it->first]	= it->second;
171			}
172			else if (writeQueue)
173				queuesWrite[it->first]	= it->second;
174			else if (readQueue)
175				queuesRead[it->first]	= it->second;
176		}
177
178		for (std::map<deUint32, QueueData>::iterator write = queuesWrite.begin(); write != queuesWrite.end(); ++write)
179		for (std::map<deUint32, QueueData>::iterator read  = queuesRead.begin();  read  != queuesRead.end();  ++read)
180		{
181			const int writeSize	= static_cast<int>(write->second.queue.size());
182			const int readSize	= static_cast<int>(read->second.queue.size());
183
184			for (int writeNdx = 0; writeNdx < writeSize; ++writeNdx)
185			for (int readNdx  = 0; readNdx  < readSize;  ++readNdx)
186			{
187				if (write->second.queue[writeNdx] != read->second.queue[readNdx])
188				{
189					queuesPairs.push_back(QueuePair(write->first, read->first, write->second.queue[writeNdx], read->second.queue[readNdx]));
190					writeNdx = readNdx = std::max(writeSize, readSize);	//exit from the loops
191				}
192			}
193		}
194
195		if (queuesPairs.empty())
196			TCU_THROW(NotSupportedError, "Queue not found");
197
198		return queuesPairs;
199	}
200
201	VkDevice getDevice (void) const
202	{
203		return *m_logicalDevice;
204	}
205
206	const DeviceInterface& getDeviceInterface (void) const
207	{
208		return *m_deviceDriver;
209	}
210
211	Allocator& getAllocator (void)
212	{
213		return *m_allocator;
214	}
215
216private:
217	Move<VkDevice>					m_logicalDevice;
218	MovePtr<DeviceDriver>			m_deviceDriver;
219	MovePtr<Allocator>				m_allocator;
220	std::map<deUint32, QueueData>	m_queues;
221};
222
223void createBarrierMultiQueue (const DeviceInterface&	vk,
224							  const VkCommandBuffer&	cmdBuffer,
225							  const SyncInfo&			writeSync,
226							  const SyncInfo&			readSync,
227							  const Resource&			resource,
228							  const deUint32			writeFamily,
229							  const deUint32			readFamily,
230							  const VkSharingMode		sharingMode,
231							  const bool				secondQueue = false)
232{
233	if (resource.getType() == RESOURCE_TYPE_IMAGE)
234	{
235		VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
236			writeSync.imageLayout, readSync.imageLayout, resource.getImage().handle, resource.getImage().subresourceRange);
237
238		if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
239		{
240			barrier.srcQueueFamilyIndex = writeFamily;
241			barrier.dstQueueFamilyIndex = readFamily;
242			if (secondQueue)
243			{
244				barrier.oldLayout		= barrier.newLayout;
245				barrier.srcAccessMask	= barrier.dstAccessMask;
246			}
247			vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
248		}
249		else if (!secondQueue)
250			vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
251	}
252	else if ((resource.getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(resource.getType()))	&&
253			 writeFamily != readFamily																&&
254			 VK_SHARING_MODE_EXCLUSIVE == sharingMode)
255	{
256		const VkBufferMemoryBarrier barrier =
257		{
258			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
259			DE_NULL,									// const void*		pNext;
260			writeSync.accessMask ,						// VkAccessFlags	srcAccessMask;
261			readSync.accessMask,						// VkAccessFlags	dstAccessMask;
262			writeFamily,								// deUint32			srcQueueFamilyIndex;
263			readFamily,									// deUint32			destQueueFamilyIndex;
264			resource.getBuffer().handle,				// VkBuffer			buffer;
265			resource.getBuffer().offset,				// VkDeviceSize		offset;
266			resource.getBuffer().size,					// VkDeviceSize		size;
267		};
268		vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, (const VkBufferMemoryBarrier*)&barrier, 0u, (const VkImageMemoryBarrier *)DE_NULL);
269	}
270}
271
272class BaseTestInstance : public TestInstance
273{
274public:
275	BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
276		: TestInstance		(context)
277		, m_queues			(new MultiQueues(context))
278		, m_opContext		(new OperationContext(context, pipelineCacheData, m_queues->getDeviceInterface(), m_queues->getDevice(), m_queues->getAllocator()))
279		, m_resourceDesc	(resourceDesc)
280		, m_writeOp			(writeOp)
281		, m_readOp			(readOp)
282	{
283	}
284
285protected:
286	const UniquePtr<MultiQueues>		m_queues;
287	const UniquePtr<OperationContext>	m_opContext;
288	const ResourceDescription			m_resourceDesc;
289	const OperationSupport&				m_writeOp;
290	const OperationSupport&				m_readOp;
291};
292
293class SemaphoreTestInstance : public BaseTestInstance
294{
295public:
296	SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
297		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
298		, m_sharingMode		(sharingMode)
299	{
300	}
301
302	tcu::TestStatus	iterate (void)
303	{
304		const DeviceInterface&			vk			= m_opContext->getDeviceInterface();
305		const VkDevice					device		= m_opContext->getDevice();
306		const std::vector<QueuePair>	queuePairs	= m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
307
308		for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
309		{
310
311			const UniquePtr<Resource>		resource		(new Resource(*m_opContext, m_resourceDesc, m_writeOp.getResourceUsageFlags() | m_readOp.getResourceUsageFlags()));
312			const UniquePtr<Operation>		writeOp			(m_writeOp.build(*m_opContext, *resource));
313			const UniquePtr<Operation>		readOp			(m_readOp.build (*m_opContext, *resource));
314
315			const Move<VkCommandPool>		cmdPool[]		=
316			{
317				createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
318				createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
319			};
320			const Move<VkCommandBuffer>		ptrCmdBuffer[]	=
321			{
322				makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
323				makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
324			};
325			const VkCommandBuffer			cmdBuffers[]	=
326			{
327				*ptrCmdBuffer[QUEUETYPE_WRITE],
328				*ptrCmdBuffer[QUEUETYPE_READ]
329			};
330			const Unique<VkSemaphore>		semaphore		(createSemaphore(vk, device));
331			const VkPipelineStageFlags		stageBits[]		= { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
332			const VkSubmitInfo				submitInfo[]	=
333			{
334				{
335					VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType			sType;
336					DE_NULL,							// const void*				pNext;
337					0u,									// deUint32					waitSemaphoreCount;
338					DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
339					(const VkPipelineStageFlags*)DE_NULL,
340					1u,									// deUint32					commandBufferCount;
341					&cmdBuffers[QUEUETYPE_WRITE],		// const VkCommandBuffer*	pCommandBuffers;
342					1u,									// deUint32					signalSemaphoreCount;
343					&semaphore.get(),					// const VkSemaphore*		pSignalSemaphores;
344				},
345				{
346					VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType				sType;
347					DE_NULL,							// const void*					pNext;
348					1u,									// deUint32						waitSemaphoreCount;
349					&semaphore.get(),					// const VkSemaphore*			pWaitSemaphores;
350					stageBits,							// const VkPipelineStageFlags*	pWaitDstStageMask;
351					1u,									// deUint32						commandBufferCount;
352					&cmdBuffers[QUEUETYPE_READ],		// const VkCommandBuffer*		pCommandBuffers;
353					0u,									// deUint32						signalSemaphoreCount;
354					DE_NULL,							// const VkSemaphore*			pSignalSemaphores;
355				}
356			};
357			const SyncInfo					writeSync		= writeOp->getSyncInfo();
358			const SyncInfo					readSync		= readOp->getSyncInfo();
359
360			beginCommandBuffer		(vk, cmdBuffers[QUEUETYPE_WRITE]);
361			writeOp->recordCommands	(cmdBuffers[QUEUETYPE_WRITE]);
362			createBarrierMultiQueue	(vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
363			endCommandBuffer		(vk, cmdBuffers[QUEUETYPE_WRITE]);
364
365			beginCommandBuffer		(vk, cmdBuffers[QUEUETYPE_READ]);
366			createBarrierMultiQueue	(vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
367			readOp->recordCommands	(cmdBuffers[QUEUETYPE_READ]);
368			endCommandBuffer		(vk, cmdBuffers[QUEUETYPE_READ]);
369
370			VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueWrite, 1u, &submitInfo[QUEUETYPE_WRITE], DE_NULL));
371			VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueRead, 1u, &submitInfo[QUEUETYPE_READ], DE_NULL));
372			VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueWrite));
373			VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueRead));
374
375			{
376				const Data	expected	= writeOp->getData();
377				const Data	actual		= readOp->getData();
378
379				if (0 != deMemCmp(expected.data, actual.data, expected.size))
380					return tcu::TestStatus::fail("Memory contents don't match");
381			}
382		}
383		return tcu::TestStatus::pass("OK");
384	}
385
386private:
387	const VkSharingMode	m_sharingMode;
388};
389
390class FenceTestInstance : public BaseTestInstance
391{
392public:
393	FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
394		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
395		, m_sharingMode		(sharingMode)
396	{
397	}
398
399	tcu::TestStatus	iterate (void)
400	{
401		const DeviceInterface&			vk			= m_opContext->getDeviceInterface();
402		const VkDevice					device		= m_opContext->getDevice();
403		const std::vector<QueuePair>	queuePairs	= m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
404
405		for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
406		{
407			const UniquePtr<Resource>		resource		(new Resource(*m_opContext, m_resourceDesc, m_writeOp.getResourceUsageFlags() | m_readOp.getResourceUsageFlags()));
408			const UniquePtr<Operation>		writeOp			(m_writeOp.build(*m_opContext, *resource));
409			const UniquePtr<Operation>		readOp			(m_readOp.build(*m_opContext, *resource));
410			const Move<VkCommandPool>		cmdPool[]		=
411			{
412				createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
413				createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
414			};
415			const Move<VkCommandBuffer>		ptrCmdBuffer[]	=
416			{
417				makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
418				makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
419			};
420			const VkCommandBuffer			cmdBuffers[]	=
421			{
422				*ptrCmdBuffer[QUEUETYPE_WRITE],
423				*ptrCmdBuffer[QUEUETYPE_READ]
424			};
425			const SyncInfo					writeSync		= writeOp->getSyncInfo();
426			const SyncInfo					readSync		= readOp->getSyncInfo();
427
428			beginCommandBuffer		(vk, cmdBuffers[QUEUETYPE_WRITE]);
429			writeOp->recordCommands	(cmdBuffers[QUEUETYPE_WRITE]);
430			createBarrierMultiQueue	(vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
431			endCommandBuffer		(vk, cmdBuffers[QUEUETYPE_WRITE]);
432
433			submitCommandsAndWait	(vk, device, queuePairs[pairNdx].queueWrite, cmdBuffers[QUEUETYPE_WRITE]);
434
435			beginCommandBuffer		(vk, cmdBuffers[QUEUETYPE_READ]);
436			createBarrierMultiQueue	(vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
437			readOp->recordCommands	(cmdBuffers[QUEUETYPE_READ]);
438			endCommandBuffer		(vk, cmdBuffers[QUEUETYPE_READ]);
439
440			submitCommandsAndWait	(vk, device, queuePairs[pairNdx].queueRead, cmdBuffers[QUEUETYPE_READ]);
441
442			{
443				const Data	expected = writeOp->getData();
444				const Data	actual	 = readOp->getData();
445
446				if (0 != deMemCmp(expected.data, actual.data, expected.size))
447					return tcu::TestStatus::fail("Memory contents don't match");
448			}
449		}
450		return tcu::TestStatus::pass("OK");
451	}
452
453private:
454	const VkSharingMode	m_sharingMode;
455};
456
457class BaseTestCase : public TestCase
458{
459public:
460	BaseTestCase (tcu::TestContext&			testCtx,
461				  const std::string&		name,
462				  const std::string&		description,
463				  const SyncPrimitive		syncPrimitive,
464				  const ResourceDescription	resourceDesc,
465				  const OperationName		writeOp,
466				  const OperationName		readOp,
467				  const VkSharingMode		sharingMode,
468				  PipelineCacheData&		pipelineCacheData)
469		: TestCase				(testCtx, name, description)
470		, m_resourceDesc		(resourceDesc)
471		, m_writeOp				(makeOperationSupport(writeOp, resourceDesc))
472		, m_readOp				(makeOperationSupport(readOp, resourceDesc))
473		, m_syncPrimitive		(syncPrimitive)
474		, m_sharingMode			(sharingMode)
475		, m_pipelineCacheData	(pipelineCacheData)
476	{
477	}
478
479	void initPrograms (SourceCollections& programCollection) const
480	{
481		m_writeOp->initPrograms(programCollection);
482		m_readOp->initPrograms(programCollection);
483	}
484
485	TestInstance* createInstance (Context& context) const
486	{
487		switch (m_syncPrimitive)
488		{
489			case SYNC_PRIMITIVE_FENCE:
490				return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
491			case SYNC_PRIMITIVE_SEMAPHORE:
492				return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
493			default:
494				DE_ASSERT(0);
495				return DE_NULL;
496		}
497	}
498
499private:
500	const ResourceDescription				m_resourceDesc;
501	const UniquePtr<OperationSupport>		m_writeOp;
502	const UniquePtr<OperationSupport>		m_readOp;
503	const SyncPrimitive						m_syncPrimitive;
504	const VkSharingMode						m_sharingMode;
505	PipelineCacheData&						m_pipelineCacheData;
506};
507
508void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
509{
510	tcu::TestContext& testCtx = group->getTestContext();
511
512	static const struct
513	{
514		const char*		name;
515		SyncPrimitive	syncPrimitive;
516		int				numOptions;
517	} groups[] =
518	{
519		{ "fence",		SYNC_PRIMITIVE_FENCE,		1 },
520		{ "semaphore",	SYNC_PRIMITIVE_SEMAPHORE,	1 }
521	};
522
523	for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
524	{
525		MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
526
527		for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
528		for (int readOpNdx  = 0; readOpNdx  < DE_LENGTH_OF_ARRAY(s_readOps);  ++readOpNdx)
529		{
530			const OperationName	writeOp		= s_writeOps[writeOpNdx];
531			const OperationName	readOp		= s_readOps[readOpNdx];
532			const std::string	opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
533			bool				empty		= true;
534
535			MovePtr<tcu::TestCaseGroup> opGroup		(new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
536
537			for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx)
538			for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
539			{
540				const ResourceDescription&	resource	= s_resources[resourceNdx];
541				std::string					name		= getResourceName(resource);
542				VkSharingMode				sharingMode = VK_SHARING_MODE_EXCLUSIVE;
543
544				// queue family sharing mode used for resource
545				if (optionNdx)
546				{
547					name += "_concurrent";
548					sharingMode = VK_SHARING_MODE_CONCURRENT;
549				}
550				else
551					name += "_exclusive";
552
553				if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
554				{
555					opGroup->addChild(new BaseTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *pipelineCacheData));
556					empty = false;
557				}
558			}
559			if (!empty)
560				synchGroup->addChild(opGroup.release());
561		}
562		group->addChild(synchGroup.release());
563	}
564}
565
566} // anonymous
567
568tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
569{
570	return createTestGroup(testCtx, "multi_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
571}
572
573} // synchronization
574} // vkt
575