blob: 2eb433eabf9667fa9d807e7632c407a94cb76acd [file] [log] [blame]
/*------------------------------------------------------------------------
* 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