/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 * Copyright (c) 2016 The Khronos Group Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Synchronization primitive tests with multi queue
 *//*--------------------------------------------------------------------*/

#include "vktSynchronizationOperationMultiQueueTests.hpp"
#include "vkDefs.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkPlatform.hpp"
#include "deUniquePtr.hpp"
#include "tcuTestLog.hpp"
#include "vktSynchronizationUtil.hpp"
#include "vktSynchronizationOperation.hpp"
#include "vktSynchronizationOperationTestData.hpp"
#include "vktTestGroupUtil.hpp"

namespace vkt
{
namespace synchronization
{
namespace
{
using namespace vk;

enum QueueType {WRITE, READ, COUNT};
enum {NO_MATCH_FOUND = ~((deUint32)0)};

class MultiQueues
{
public:
	MultiQueues	(MultiQueues &obj)
		: m_logicalDevice	(obj.m_logicalDevice)
		, m_allocator		(obj.m_allocator)
	{
		m_queues.resize(COUNT);
		m_queueFamilyIndex.resize(COUNT);
		for (int ndx = 0; ndx < COUNT; ++ndx)
		{
			m_queues[ndx]			= obj.m_queues[ndx];
			m_queueFamilyIndex[ndx]	= obj.m_queueFamilyIndex[ndx];
		}
	}

	MultiQueues	()
	{
		m_queues.resize(COUNT);
		m_queueFamilyIndex.resize(COUNT);
		for (int ndx = 0; ndx < COUNT; ++ndx)
			m_queueFamilyIndex[ndx] = NO_MATCH_FOUND;
	}

	Move<VkDevice>				m_logicalDevice;
	de::MovePtr<DeviceDriver>	m_deviceDriver;
	de::MovePtr<Allocator>		m_allocator;
	std::vector<VkQueue>		m_queues;
	std::vector<deUint32>		m_queueFamilyIndex;
};

bool checkQueueFlags (const vk::VkQueueFlags& availableFlag, const vk::VkQueueFlags& neededFlag)
{
	if (VK_QUEUE_TRANSFER_BIT == neededFlag)
	{
		if ( (availableFlag & VK_QUEUE_GRAPHICS_BIT) == VK_QUEUE_GRAPHICS_BIT ||
			 (availableFlag & VK_QUEUE_COMPUTE_BIT)	 == VK_QUEUE_COMPUTE_BIT  ||
			 (availableFlag & VK_QUEUE_TRANSFER_BIT) == VK_QUEUE_TRANSFER_BIT
		   )
			return true;
	}
	else if ((availableFlag & neededFlag) == neededFlag)
	{
		return true;
	}
	return false;
}

de::MovePtr<MultiQueues> createQueues (Context& context, const vk::VkQueueFlags& queueFlagWrite, const vk::VkQueueFlags& queueFlagRead)
{
	const InstanceInterface&				instance				= context.getInstanceInterface();
	const VkPhysicalDevice					physicalDevice			= context.getPhysicalDevice();
	const float								queuePriorities[COUNT]	= {1.0f, 1.0f};
	VkDeviceCreateInfo						deviceInfo;
	VkPhysicalDeviceFeatures				deviceFeatures;
	std::vector<VkQueueFamilyProperties>	queueFamilyProperties;
	VkDeviceQueueCreateInfo					queueInfos[COUNT];
	VkQueueFlags							queueFlags[COUNT]		= {queueFlagWrite,queueFlagRead};
	int										fisrtQueueToFind		= WRITE;
	int										secondQueueToFind		= READ;
	de::MovePtr<MultiQueues>				queuesMovePtr			(new MultiQueues());
	MultiQueues&							queues					= *queuesMovePtr;

	queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice);

	{
		int	counterWrite = 0;
		int	counterRead	 = 0;

		for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
		{
			if (checkQueueFlags(queueFamilyProperties[queuePropertiesNdx].queueFlags, queueFlagWrite))
				counterWrite++;

			if (checkQueueFlags(queueFamilyProperties[queuePropertiesNdx].queueFlags, queueFlagRead))
				counterRead++;
		}

		if (counterRead < counterWrite)
		{
			fisrtQueueToFind	= READ;
			secondQueueToFind	= WRITE;
		}
	}

	for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
	{
		if (NO_MATCH_FOUND == queues.m_queueFamilyIndex[fisrtQueueToFind])
		if (checkQueueFlags(queueFamilyProperties[queuePropertiesNdx].queueFlags, queueFlags[fisrtQueueToFind]))
		{
			queues.m_queueFamilyIndex[fisrtQueueToFind] = queuePropertiesNdx;
		}

		if (NO_MATCH_FOUND == queues.m_queueFamilyIndex[secondQueueToFind])
		if (checkQueueFlags(queueFamilyProperties[queuePropertiesNdx].queueFlags, queueFlags[secondQueueToFind]))
		{
			if (queuePropertiesNdx != queues.m_queueFamilyIndex[fisrtQueueToFind] || queueFamilyProperties[queuePropertiesNdx].queueCount > 1u)
			{
				queues.m_queueFamilyIndex[secondQueueToFind] = queuePropertiesNdx;
			}
		}
	}

	if (NO_MATCH_FOUND == queues.m_queueFamilyIndex[WRITE] || NO_MATCH_FOUND == queues.m_queueFamilyIndex[READ])
	{
		TCU_THROW(NotSupportedError, "Queue not found");
	}

	for (int queueNdx = 0; queueNdx < COUNT; ++queueNdx)
	{
		VkDeviceQueueCreateInfo queueInfo;
		deMemset(&queueInfo, 0, sizeof(queueInfo));

		queueInfo.sType				= VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
		queueInfo.pNext				= DE_NULL;
		queueInfo.flags				= (VkDeviceQueueCreateFlags)0u;
		queueInfo.queueFamilyIndex	= queues.m_queueFamilyIndex[queueNdx];
		queueInfo.queueCount		= (queues.m_queueFamilyIndex[WRITE] == queues.m_queueFamilyIndex[READ]) ? static_cast<deUint32>(COUNT) : 1u;
		queueInfo.pQueuePriorities	= queuePriorities;

		queueInfos[queueNdx]	= queueInfo;

		if (queues.m_queueFamilyIndex[WRITE] == queues.m_queueFamilyIndex[READ])
			break;
	}

	deMemset(&deviceInfo, 0, sizeof(deviceInfo));
	instance.getPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);

	deviceInfo.sType					= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
	deviceInfo.pNext					= DE_NULL;
	deviceInfo.enabledExtensionCount	= 0u;
	deviceInfo.ppEnabledExtensionNames	= DE_NULL;
	deviceInfo.enabledLayerCount		= 0u;
	deviceInfo.ppEnabledLayerNames		= DE_NULL;
	deviceInfo.pEnabledFeatures			= &deviceFeatures;
	deviceInfo.queueCreateInfoCount		= (queues.m_queueFamilyIndex[WRITE] == queues.m_queueFamilyIndex[READ]) ? 1u : static_cast<deUint32>(COUNT);
	deviceInfo.pQueueCreateInfos		= queueInfos;

	queues.m_logicalDevice	= createDevice(instance, physicalDevice, &deviceInfo);
	queues.m_deviceDriver	= de::MovePtr<DeviceDriver>(new DeviceDriver(instance, *queues.m_logicalDevice));
	queues.m_allocator		= de::MovePtr<Allocator>(new SimpleAllocator(*queues.m_deviceDriver, *queues.m_logicalDevice, getPhysicalDeviceMemoryProperties(instance, physicalDevice)));

	for (deUint32 queueReqNdx = 0; queueReqNdx < COUNT; ++queueReqNdx)
	{
		if (queues.m_queueFamilyIndex[WRITE] == queues.m_queueFamilyIndex[READ])
			queues.m_deviceDriver->getDeviceQueue(*queues.m_logicalDevice, queues.m_queueFamilyIndex[queueReqNdx], queueReqNdx, &queues.m_queues[queueReqNdx]);
		else
			queues.m_deviceDriver->getDeviceQueue(*queues.m_logicalDevice, queues.m_queueFamilyIndex[queueReqNdx], 0u, &queues.m_queues[queueReqNdx]);
	}

	return queuesMovePtr;
}

void createBarrierMultiQueue (const DeviceInterface& vk, const VkCommandBuffer& cmdBuffer, const SyncInfo& writeSync, const SyncInfo& readSync,
							  const Resource& resource, const MultiQueues& queues, const vk::VkSharingMode sharingMode, const bool secondQueue=false)
{
	if (resource.getType() == RESOURCE_TYPE_IMAGE)
	{
		VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
			writeSync.imageLayout, readSync.imageLayout, resource.getImage().handle, resource.getImage().subresourceRange);

		if (queues.m_queueFamilyIndex[WRITE] != queues.m_queueFamilyIndex[READ] && vk::VK_SHARING_MODE_EXCLUSIVE == sharingMode)
		{
			barrier.srcQueueFamilyIndex = queues.m_queueFamilyIndex[WRITE];
			barrier.dstQueueFamilyIndex = queues.m_queueFamilyIndex[READ];
			if (secondQueue)
			{
				barrier.oldLayout		= barrier.newLayout;
				barrier.srcAccessMask	= barrier.dstAccessMask;
			}
			vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
		}
		else if (!secondQueue)
			vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
	}
	else if ((resource.getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(resource.getType())) &&
			 queues.m_queueFamilyIndex[WRITE] != queues.m_queueFamilyIndex[READ] &&
			 vk::VK_SHARING_MODE_EXCLUSIVE == sharingMode)
	{
		const VkBufferMemoryBarrier barrier =
			{
				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
				DE_NULL,									// const void*		pNext;
				writeSync.accessMask ,						// VkAccessFlags	srcAccessMask;
				readSync.accessMask,						// VkAccessFlags	dstAccessMask;
				queues.m_queueFamilyIndex[WRITE],			// deUint32			srcQueueFamilyIndex;
				queues.m_queueFamilyIndex[READ],			// deUint32			destQueueFamilyIndex;
				resource.getBuffer().handle,				// VkBuffer			buffer;
				resource.getBuffer().offset,				// VkDeviceSize		offset;
				resource.getBuffer().size,					// VkDeviceSize		size;
			};
		vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, (const VkBufferMemoryBarrier*)&barrier, 0u, (const VkImageMemoryBarrier *)DE_NULL);
	}
}

class BaseTestInstance : public TestInstance
{
public:
	BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
		: TestInstance	(context)
		, m_queues		(createQueues(context, writeOp.getQueueFlags(), readOp.getQueueFlags()))
		, m_opContext	(new OperationContext(context, pipelineCacheData, *m_queues->m_deviceDriver, *m_queues->m_logicalDevice, *m_queues->m_allocator))
		, m_resource	(new Resource(*m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
		, m_writeOp		(writeOp.build(*m_opContext, *m_resource))
		, m_readOp		(readOp.build(*m_opContext, *m_resource))
	{
	}

protected:
	de::UniquePtr<MultiQueues>		m_queues;
	de::UniquePtr<OperationContext>	m_opContext;
	de::UniquePtr<Resource>			m_resource;
	de::MovePtr<Operation>			m_writeOp;
	de::MovePtr<Operation>			m_readOp;
};

class SemaphoreTestInstance : public BaseTestInstance
{
public:
	SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const vk::VkSharingMode sharingMode)
		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
		, m_sharingMode		(sharingMode)
	{
	}

	tcu::TestStatus	iterate (void)
	{
		const DeviceInterface&			vk					= (*m_opContext).getDeviceInterface();
		const VkDevice					device				= (*m_opContext).getDevice();
		const Move<VkCommandPool>		cmdPool[COUNT]		= {makeCommandPool(vk, device, (*m_queues).m_queueFamilyIndex[WRITE]), makeCommandPool(vk, device, (*m_queues).m_queueFamilyIndex[READ])};
		const Move<VkCommandBuffer>		ptrCmdBuffer[COUNT]	= {makeCommandBuffer(vk, device, *cmdPool[WRITE]), makeCommandBuffer(vk, device, *cmdPool[READ])};
		VkCommandBuffer					cmdBuffers[COUNT]	= {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
		const VkSemaphoreCreateInfo		semaphoreInfo		=
															{
																VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,	//VkStructureType			sType;
																DE_NULL,									//const void*				pNext;
																0u											//VkSemaphoreCreateFlags	flags;
															};
		const Unique<VkSemaphore>		semaphore			(createSemaphore(vk, device, &semaphoreInfo, DE_NULL));
		const VkPipelineStageFlags		stageBits[]			= { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
		const VkSubmitInfo				submitInfo[COUNT]	=
															{
																{
																	VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType			sType;
																	DE_NULL,							// const void*				pNext;
																	0u,									// deUint32					waitSemaphoreCount;
																	DE_NULL,							// const VkSemaphore*		pWaitSemaphores;
																	(const VkPipelineStageFlags*)DE_NULL,
																	1u,									// deUint32					commandBufferCount;
																	&cmdBuffers[WRITE],					// const VkCommandBuffer*	pCommandBuffers;
																	1u,									// deUint32					signalSemaphoreCount;
																	&semaphore.get(),					// const VkSemaphore*		pSignalSemaphores;
																},
																{
																	VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType				sType;
																	DE_NULL,							// const void*					pNext;
																	1u,									// deUint32						waitSemaphoreCount;
																	&semaphore.get(),					// const VkSemaphore*			pWaitSemaphores;
																	stageBits,							// const VkPipelineStageFlags*	pWaitDstStageMask;
																	1u,									// deUint32						commandBufferCount;
																	&cmdBuffers[READ],					// const VkCommandBuffer*		pCommandBuffers;
																	0u,									// deUint32						signalSemaphoreCount;
																	DE_NULL,							// const VkSemaphore*			pSignalSemaphores;
																}
															};
		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
		const SyncInfo					readSync			= m_readOp->getSyncInfo();

		beginCommandBuffer(vk, cmdBuffers[WRITE]);
		m_writeOp->recordCommands(cmdBuffers[WRITE]);
		createBarrierMultiQueue(vk,cmdBuffers[WRITE], writeSync, readSync, (*m_resource), (*m_queues), m_sharingMode);
		endCommandBuffer(vk, cmdBuffers[WRITE]);

		beginCommandBuffer(vk, cmdBuffers[READ]);
		createBarrierMultiQueue(vk,cmdBuffers[READ], writeSync, readSync, (*m_resource), (*m_queues), m_sharingMode, true);
		m_readOp->recordCommands(cmdBuffers[READ]);
		endCommandBuffer(vk, cmdBuffers[READ]);

		VK_CHECK(vk.queueSubmit((*m_queues).m_queues[WRITE], 1u, &submitInfo[WRITE], DE_NULL));
		VK_CHECK(vk.queueSubmit((*m_queues).m_queues[READ], 1u, &submitInfo[READ], DE_NULL));
		VK_CHECK(vk.queueWaitIdle((*m_queues).m_queues[WRITE]));
		VK_CHECK(vk.queueWaitIdle((*m_queues).m_queues[READ]));

		{
			const Data	expected = m_writeOp->getData();
			const Data	actual	 = m_readOp->getData();

			if (0 != deMemCmp(expected.data, actual.data, expected.size))
				return tcu::TestStatus::fail("Memory contents don't match");
		}
		return tcu::TestStatus::pass("OK");
	}
private:
	const vk::VkSharingMode		m_sharingMode;
};

class FenceTestInstance : public BaseTestInstance
{
public:
	FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const vk::VkSharingMode sharingMode)
		: BaseTestInstance	(context, resourceDesc, writeOp, readOp, pipelineCacheData)
		, m_sharingMode		(sharingMode)
	{
	}

	tcu::TestStatus	iterate (void)
	{
		const DeviceInterface&			vk					= (*m_opContext).getDeviceInterface();
		const VkDevice					device				= (*m_opContext).getDevice();
		const Move<VkCommandPool>		cmdPool[COUNT]		= {makeCommandPool(vk, device, (*m_queues).m_queueFamilyIndex[WRITE]), makeCommandPool(vk, device, (*m_queues).m_queueFamilyIndex[READ])};
		const Move<VkCommandBuffer>		ptrCmdBuffer[COUNT]	= {makeCommandBuffer(vk, device, *cmdPool[WRITE]), makeCommandBuffer(vk, device, *cmdPool[READ])};
		VkCommandBuffer					cmdBuffers[COUNT]	= {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
		const SyncInfo					writeSync			= m_writeOp->getSyncInfo();
		const SyncInfo					readSync			= m_readOp->getSyncInfo();

		beginCommandBuffer(vk, cmdBuffers[WRITE]);
		m_writeOp->recordCommands(cmdBuffers[WRITE]);
		createBarrierMultiQueue(vk,cmdBuffers[WRITE], writeSync, readSync, (*m_resource), (*m_queues), m_sharingMode);
		endCommandBuffer(vk, cmdBuffers[WRITE]);

		submitCommandsAndWait(vk, device, (*m_queues).m_queues[WRITE], cmdBuffers[WRITE]);

		beginCommandBuffer(vk, cmdBuffers[READ]);
		createBarrierMultiQueue(vk,cmdBuffers[READ], writeSync, readSync, (*m_resource), (*m_queues), m_sharingMode, true);
		m_readOp->recordCommands(cmdBuffers[READ]);
		endCommandBuffer(vk, cmdBuffers[READ]);

		submitCommandsAndWait(vk, device, (*m_queues).m_queues[READ], cmdBuffers[READ]);

		{
			const Data	expected = m_writeOp->getData();
			const Data	actual	 = m_readOp->getData();

			if (0 != deMemCmp(expected.data, actual.data, expected.size))
				return tcu::TestStatus::fail("Memory contents don't match");
		}
		return tcu::TestStatus::pass("OK");
	}

private:
	const vk::VkSharingMode		m_sharingMode;
};

class BaseTestCase : public TestCase
{
public:
	BaseTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description,
					const ResourceDescription resourceDesc, const OperationName writeOp, const OperationName readOp)
		: TestCase				(testCtx, name, description)
		, m_resourceDesc		(resourceDesc)
		, m_writeOp				(makeOperationSupport(writeOp, resourceDesc))
		, m_readOp				(makeOperationSupport(readOp, resourceDesc))
	{
	}

	void initPrograms (SourceCollections& programCollection) const
	{
		m_writeOp->initPrograms(programCollection);
		m_readOp->initPrograms(programCollection);
	}

protected:
	const ResourceDescription				m_resourceDesc;
	const de::UniquePtr<OperationSupport>	m_writeOp;
	const de::UniquePtr<OperationSupport>	m_readOp;
};

class SyncTestCase : public TestCase
{
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,
					const vk::VkSharingMode		sharingMode,
					PipelineCacheData&			pipelineCacheData)
		: TestCase				(testCtx, name, description)
		, m_resourceDesc		(resourceDesc)
		, m_writeOp				(makeOperationSupport(writeOp, resourceDesc))
		, m_readOp				(makeOperationSupport(readOp, resourceDesc))
		, m_syncPrimitive		(syncPrimitive)
		, m_sharingMode			(sharingMode)
		, m_pipelineCacheData	(pipelineCacheData)
	{
	}

	void initPrograms (SourceCollections& programCollection) const
	{
		m_writeOp->initPrograms(programCollection);
		m_readOp->initPrograms(programCollection);
	}

	TestInstance* createInstance (Context& context) const
	{
		switch (m_syncPrimitive)
		{
			case SYNC_PRIMITIVE_FENCE:
				return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
			case SYNC_PRIMITIVE_SEMAPHORE:
				return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
			default :
				DE_ASSERT(0);
				return DE_NULL;
		}
	}

private:
	const ResourceDescription				m_resourceDesc;
	const de::UniquePtr<OperationSupport>	m_writeOp;
	const de::UniquePtr<OperationSupport>	m_readOp;
	const SyncPrimitive						m_syncPrimitive;
	const vk::VkSharingMode					m_sharingMode;
	PipelineCacheData&						m_pipelineCacheData;
};

void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
{
	tcu::TestContext& testCtx = group->getTestContext();

	static const struct
	{
		const char*		name;
		SyncPrimitive	syncPrimitive;
		int				numOptions;
	} groups[] =
	{
		{ "fence",		SYNC_PRIMITIVE_FENCE,		1 },
		{ "semaphore",	SYNC_PRIMITIVE_SEMAPHORE,	1 }
	};

	for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
	{
		de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));

		for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
		for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
		{
			const OperationName	writeOp		= s_writeOps[writeOpNdx];
			const OperationName	readOp		= s_readOps[readOpNdx];
			const std::string	opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
			bool				empty		= true;

			de::MovePtr<tcu::TestCaseGroup> opGroup	(new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));

			for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx)
			for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
			{
				const ResourceDescription&	resource	= s_resources[resourceNdx];
				std::string					name		= getResourceName(resource);

				vk::VkSharingMode sharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
				// queue family sharing mode used for resource
				if (optionNdx)
				{
					name += "_concurrent";
					sharingMode = vk::VK_SHARING_MODE_CONCURRENT;
				}
				else
					name += "_exclusive";

				if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
				{
					opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *pipelineCacheData));
					empty = false;
				}
			}
			if (!empty)
				synchGroup->addChild(opGroup.release());
		}

		group->addChild(synchGroup.release());
	}
}

} // anonymous

tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
{
	return createTestGroup(testCtx, "multi_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
}

} // synchronization
} // vkt
