1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Synchronization primitive tests with multi queue
22 *//*--------------------------------------------------------------------*/
24 #include "vktSynchronizationOperationMultiQueueTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.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"
44 namespace synchronization
60 QueuePair (const deUint32 familyWrite, const deUint32 familyRead, const VkQueue write, const VkQueue read)
61 : familyIndexWrite (familyWrite)
62 , familyIndexRead (familyRead)
67 deUint32 familyIndexWrite;
68 deUint32 familyIndexRead;
73 bool checkQueueFlags (VkQueueFlags availableFlags, const VkQueueFlags neededFlags)
75 if ((availableFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) != 0)
76 availableFlags |= VK_QUEUE_TRANSFER_BIT;
78 return (availableFlags & neededFlags) != 0;
86 std::vector<VkQueue> queue;
90 MultiQueues (const Context& context)
92 const InstanceInterface& instance = context.getInstanceInterface();
93 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
94 const std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice);
96 for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
98 addQueueIndex(queuePropertiesNdx,
99 std::min(2u, queueFamilyProperties[queuePropertiesNdx].queueCount),
100 queueFamilyProperties[queuePropertiesNdx].queueFlags);
103 std::vector<VkDeviceQueueCreateInfo> queueInfos;
104 const float queuePriorities[2] = { 1.0f, 1.0f }; //get max 2 queues from one family
106 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
108 const VkDeviceQueueCreateInfo queueInfo =
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;
117 queueInfos.push_back(queueInfo);
121 const std::vector<std::string>& deviceExtensions = context.getDeviceExtensions();
122 std::vector<const char*> charDevExtensions;
124 for (size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
125 charDevExtensions.push_back(deviceExtensions[ndx].c_str());
127 const VkDeviceCreateInfo deviceInfo =
129 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //VkStructureType sType;
130 DE_NULL, //const void* pNext;
131 0u, //VkDeviceCreateFlags flags;
132 static_cast<deUint32>(queueInfos.size()), //deUint32 queueCreateInfoCount;
133 &queueInfos[0], //const VkDeviceQueueCreateInfo* pQueueCreateInfos;
134 0u, //deUint32 enabledLayerCount;
135 DE_NULL, //const char* const* ppEnabledLayerNames;
136 static_cast<deUint32>(deviceExtensions.size()), //deUint32 enabledExtensionCount;
137 &charDevExtensions[0], //const char* const* ppEnabledExtensionNames;
138 &context.getDeviceFeatures() //const VkPhysicalDeviceFeatures* pEnabledFeatures;
141 m_logicalDevice = createDevice(instance, physicalDevice, &deviceInfo);
142 m_deviceDriver = MovePtr<DeviceDriver>(new DeviceDriver(instance, *m_logicalDevice));
143 m_allocator = MovePtr<Allocator>(new SimpleAllocator(*m_deviceDriver, *m_logicalDevice, getPhysicalDeviceMemoryProperties(instance, physicalDevice)));
145 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
146 for (int queueNdx = 0; queueNdx < static_cast<int>(it->second.queue.size()); ++queueNdx)
147 m_deviceDriver->getDeviceQueue(*m_logicalDevice, it->first, queueNdx, &it->second.queue[queueNdx]);
151 void addQueueIndex (const deUint32 queueFamilyIndex, const deUint32 count, const VkQueueFlags flags)
153 QueueData dataToPush;
154 dataToPush.flags = flags;
155 dataToPush.queue.resize(count);
156 m_queues[queueFamilyIndex] = dataToPush;
159 std::vector<QueuePair> getQueuesPairs (const VkQueueFlags flagsWrite, const VkQueueFlags flagsRead)
161 std::map<deUint32, QueueData> queuesWrite;
162 std::map<deUint32, QueueData> queuesRead;
163 std::vector<QueuePair> queuesPairs;
165 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
167 const bool writeQueue = checkQueueFlags(it->second.flags, flagsWrite);
168 const bool readQueue = checkQueueFlags(it->second.flags, flagsRead);
170 if (!(writeQueue || readQueue))
173 if (writeQueue && readQueue)
175 queuesWrite[it->first] = it->second;
176 queuesRead[it->first] = it->second;
179 queuesWrite[it->first] = it->second;
181 queuesRead[it->first] = it->second;
184 for (std::map<deUint32, QueueData>::iterator write = queuesWrite.begin(); write != queuesWrite.end(); ++write)
185 for (std::map<deUint32, QueueData>::iterator read = queuesRead.begin(); read != queuesRead.end(); ++read)
187 const int writeSize = static_cast<int>(write->second.queue.size());
188 const int readSize = static_cast<int>(read->second.queue.size());
190 for (int writeNdx = 0; writeNdx < writeSize; ++writeNdx)
191 for (int readNdx = 0; readNdx < readSize; ++readNdx)
193 if (write->second.queue[writeNdx] != read->second.queue[readNdx])
195 queuesPairs.push_back(QueuePair(write->first, read->first, write->second.queue[writeNdx], read->second.queue[readNdx]));
196 writeNdx = readNdx = std::max(writeSize, readSize); //exit from the loops
201 if (queuesPairs.empty())
202 TCU_THROW(NotSupportedError, "Queue not found");
207 VkDevice getDevice (void) const
209 return *m_logicalDevice;
212 const DeviceInterface& getDeviceInterface (void) const
214 return *m_deviceDriver;
217 Allocator& getAllocator (void)
223 Move<VkDevice> m_logicalDevice;
224 MovePtr<DeviceDriver> m_deviceDriver;
225 MovePtr<Allocator> m_allocator;
226 std::map<deUint32, QueueData> m_queues;
229 void createBarrierMultiQueue (const DeviceInterface& vk,
230 const VkCommandBuffer& cmdBuffer,
231 const SyncInfo& writeSync,
232 const SyncInfo& readSync,
233 const Resource& resource,
234 const deUint32 writeFamily,
235 const deUint32 readFamily,
236 const VkSharingMode sharingMode,
237 const bool secondQueue = false)
239 if (resource.getType() == RESOURCE_TYPE_IMAGE)
241 VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
242 writeSync.imageLayout, readSync.imageLayout, resource.getImage().handle, resource.getImage().subresourceRange);
244 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
246 barrier.srcQueueFamilyIndex = writeFamily;
247 barrier.dstQueueFamilyIndex = readFamily;
250 barrier.oldLayout = barrier.newLayout;
251 barrier.srcAccessMask = barrier.dstAccessMask;
253 vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
255 else if (!secondQueue)
256 vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
258 else if ((resource.getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(resource.getType())) &&
259 writeFamily != readFamily &&
260 VK_SHARING_MODE_EXCLUSIVE == sharingMode)
262 const VkBufferMemoryBarrier barrier =
264 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
265 DE_NULL, // const void* pNext;
266 writeSync.accessMask , // VkAccessFlags srcAccessMask;
267 readSync.accessMask, // VkAccessFlags dstAccessMask;
268 writeFamily, // deUint32 srcQueueFamilyIndex;
269 readFamily, // deUint32 destQueueFamilyIndex;
270 resource.getBuffer().handle, // VkBuffer buffer;
271 resource.getBuffer().offset, // VkDeviceSize offset;
272 resource.getBuffer().size, // VkDeviceSize size;
274 vk.cmdPipelineBarrier(cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, (const VkBufferMemoryBarrier*)&barrier, 0u, (const VkImageMemoryBarrier *)DE_NULL);
278 class BaseTestInstance : public TestInstance
281 BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
282 : TestInstance (context)
283 , m_queues (new MultiQueues(context))
284 , m_opContext (new OperationContext(context, pipelineCacheData, m_queues->getDeviceInterface(), m_queues->getDevice(), m_queues->getAllocator()))
285 , m_resourceDesc (resourceDesc)
286 , m_writeOp (writeOp)
292 const UniquePtr<MultiQueues> m_queues;
293 const UniquePtr<OperationContext> m_opContext;
294 const ResourceDescription m_resourceDesc;
295 const OperationSupport& m_writeOp;
296 const OperationSupport& m_readOp;
299 class SemaphoreTestInstance : public BaseTestInstance
302 SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
303 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
304 , m_sharingMode (sharingMode)
308 tcu::TestStatus iterate (void)
310 const DeviceInterface& vk = m_opContext->getDeviceInterface();
311 const VkDevice device = m_opContext->getDevice();
312 const std::vector<QueuePair> queuePairs = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
314 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
317 const UniquePtr<Resource> resource (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getResourceUsageFlags() | m_readOp.getResourceUsageFlags()));
318 const UniquePtr<Operation> writeOp (m_writeOp.build(*m_opContext, *resource));
319 const UniquePtr<Operation> readOp (m_readOp.build (*m_opContext, *resource));
321 const Move<VkCommandPool> cmdPool[] =
323 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
324 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
326 const Move<VkCommandBuffer> ptrCmdBuffer[] =
328 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
329 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
331 const VkCommandBuffer cmdBuffers[] =
333 *ptrCmdBuffer[QUEUETYPE_WRITE],
334 *ptrCmdBuffer[QUEUETYPE_READ]
336 const Unique<VkSemaphore> semaphore (createSemaphore(vk, device));
337 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
338 const VkSubmitInfo submitInfo[] =
341 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
342 DE_NULL, // const void* pNext;
343 0u, // deUint32 waitSemaphoreCount;
344 DE_NULL, // const VkSemaphore* pWaitSemaphores;
345 (const VkPipelineStageFlags*)DE_NULL,
346 1u, // deUint32 commandBufferCount;
347 &cmdBuffers[QUEUETYPE_WRITE], // const VkCommandBuffer* pCommandBuffers;
348 1u, // deUint32 signalSemaphoreCount;
349 &semaphore.get(), // const VkSemaphore* pSignalSemaphores;
352 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
353 DE_NULL, // const void* pNext;
354 1u, // deUint32 waitSemaphoreCount;
355 &semaphore.get(), // const VkSemaphore* pWaitSemaphores;
356 stageBits, // const VkPipelineStageFlags* pWaitDstStageMask;
357 1u, // deUint32 commandBufferCount;
358 &cmdBuffers[QUEUETYPE_READ], // const VkCommandBuffer* pCommandBuffers;
359 0u, // deUint32 signalSemaphoreCount;
360 DE_NULL, // const VkSemaphore* pSignalSemaphores;
363 const SyncInfo writeSync = writeOp->getSyncInfo();
364 const SyncInfo readSync = readOp->getSyncInfo();
366 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
367 writeOp->recordCommands (cmdBuffers[QUEUETYPE_WRITE]);
368 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
369 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
371 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
372 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
373 readOp->recordCommands (cmdBuffers[QUEUETYPE_READ]);
374 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
376 VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueWrite, 1u, &submitInfo[QUEUETYPE_WRITE], DE_NULL));
377 VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueRead, 1u, &submitInfo[QUEUETYPE_READ], DE_NULL));
378 VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueWrite));
379 VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueRead));
382 const Data expected = writeOp->getData();
383 const Data actual = readOp->getData();
385 if (0 != deMemCmp(expected.data, actual.data, expected.size))
386 return tcu::TestStatus::fail("Memory contents don't match");
389 return tcu::TestStatus::pass("OK");
393 const VkSharingMode m_sharingMode;
396 class FenceTestInstance : public BaseTestInstance
399 FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
400 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
401 , m_sharingMode (sharingMode)
405 tcu::TestStatus iterate (void)
407 const DeviceInterface& vk = m_opContext->getDeviceInterface();
408 const VkDevice device = m_opContext->getDevice();
409 const std::vector<QueuePair> queuePairs = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
411 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
413 const UniquePtr<Resource> resource (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getResourceUsageFlags() | m_readOp.getResourceUsageFlags()));
414 const UniquePtr<Operation> writeOp (m_writeOp.build(*m_opContext, *resource));
415 const UniquePtr<Operation> readOp (m_readOp.build(*m_opContext, *resource));
416 const Move<VkCommandPool> cmdPool[] =
418 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
419 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
421 const Move<VkCommandBuffer> ptrCmdBuffer[] =
423 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
424 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
426 const VkCommandBuffer cmdBuffers[] =
428 *ptrCmdBuffer[QUEUETYPE_WRITE],
429 *ptrCmdBuffer[QUEUETYPE_READ]
431 const SyncInfo writeSync = writeOp->getSyncInfo();
432 const SyncInfo readSync = readOp->getSyncInfo();
434 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
435 writeOp->recordCommands (cmdBuffers[QUEUETYPE_WRITE]);
436 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
437 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
439 submitCommandsAndWait (vk, device, queuePairs[pairNdx].queueWrite, cmdBuffers[QUEUETYPE_WRITE]);
441 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
442 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
443 readOp->recordCommands (cmdBuffers[QUEUETYPE_READ]);
444 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
446 submitCommandsAndWait (vk, device, queuePairs[pairNdx].queueRead, cmdBuffers[QUEUETYPE_READ]);
449 const Data expected = writeOp->getData();
450 const Data actual = readOp->getData();
452 if (0 != deMemCmp(expected.data, actual.data, expected.size))
453 return tcu::TestStatus::fail("Memory contents don't match");
456 return tcu::TestStatus::pass("OK");
460 const VkSharingMode m_sharingMode;
463 class BaseTestCase : public TestCase
466 BaseTestCase (tcu::TestContext& testCtx,
467 const std::string& name,
468 const std::string& description,
469 const SyncPrimitive syncPrimitive,
470 const ResourceDescription resourceDesc,
471 const OperationName writeOp,
472 const OperationName readOp,
473 const VkSharingMode sharingMode,
474 PipelineCacheData& pipelineCacheData)
475 : TestCase (testCtx, name, description)
476 , m_resourceDesc (resourceDesc)
477 , m_writeOp (makeOperationSupport(writeOp, resourceDesc))
478 , m_readOp (makeOperationSupport(readOp, resourceDesc))
479 , m_syncPrimitive (syncPrimitive)
480 , m_sharingMode (sharingMode)
481 , m_pipelineCacheData (pipelineCacheData)
485 void initPrograms (SourceCollections& programCollection) const
487 m_writeOp->initPrograms(programCollection);
488 m_readOp->initPrograms(programCollection);
491 TestInstance* createInstance (Context& context) const
493 switch (m_syncPrimitive)
495 case SYNC_PRIMITIVE_FENCE:
496 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
497 case SYNC_PRIMITIVE_SEMAPHORE:
498 return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
506 const ResourceDescription m_resourceDesc;
507 const UniquePtr<OperationSupport> m_writeOp;
508 const UniquePtr<OperationSupport> m_readOp;
509 const SyncPrimitive m_syncPrimitive;
510 const VkSharingMode m_sharingMode;
511 PipelineCacheData& m_pipelineCacheData;
514 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
516 tcu::TestContext& testCtx = group->getTestContext();
521 SyncPrimitive syncPrimitive;
525 { "fence", SYNC_PRIMITIVE_FENCE, 1 },
526 { "semaphore", SYNC_PRIMITIVE_SEMAPHORE, 1 }
529 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
531 MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
533 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
534 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
536 const OperationName writeOp = s_writeOps[writeOpNdx];
537 const OperationName readOp = s_readOps[readOpNdx];
538 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
541 MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
543 for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx)
544 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
546 const ResourceDescription& resource = s_resources[resourceNdx];
547 std::string name = getResourceName(resource);
548 VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE;
550 // queue family sharing mode used for resource
553 name += "_concurrent";
554 sharingMode = VK_SHARING_MODE_CONCURRENT;
557 name += "_exclusive";
559 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
561 opGroup->addChild(new BaseTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *pipelineCacheData));
566 synchGroup->addChild(opGroup.release());
568 group->addChild(synchGroup.release());
574 tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
576 return createTestGroup(testCtx, "multi_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);