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 "vkBarrierUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "deRandom.hpp"
37 #include "deUniquePtr.hpp"
38 #include "deSharedPtr.hpp"
39 #include "tcuTestLog.hpp"
40 #include "vktSynchronizationUtil.hpp"
41 #include "vktSynchronizationOperation.hpp"
42 #include "vktSynchronizationOperationTestData.hpp"
43 #include "vktSynchronizationOperationResources.hpp"
44 #include "vktTestGroupUtil.hpp"
50 namespace synchronization
68 QueuePair (const deUint32 familyWrite, const deUint32 familyRead, const VkQueue write, const VkQueue read)
69 : familyIndexWrite (familyWrite)
70 , familyIndexRead (familyRead)
75 deUint32 familyIndexWrite;
76 deUint32 familyIndexRead;
83 Queue (const deUint32 familyOp, const VkQueue queueOp)
92 bool checkQueueFlags (VkQueueFlags availableFlags, const VkQueueFlags neededFlags)
94 if ((availableFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) != 0)
95 availableFlags |= VK_QUEUE_TRANSFER_BIT;
97 return (availableFlags & neededFlags) != 0;
105 std::vector<VkQueue> queue;
108 MultiQueues (const Context& context, bool timelineSemaphore)
111 const InstanceInterface& instance = context.getInstanceInterface();
112 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
113 const std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice);
115 for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
117 addQueueIndex(queuePropertiesNdx,
118 std::min(2u, queueFamilyProperties[queuePropertiesNdx].queueCount),
119 queueFamilyProperties[queuePropertiesNdx].queueFlags);
122 std::vector<VkDeviceQueueCreateInfo> queueInfos;
123 const float queuePriorities[2] = { 1.0f, 1.0f }; //get max 2 queues from one family
125 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
127 const VkDeviceQueueCreateInfo queueInfo =
129 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, //VkStructureType sType;
130 DE_NULL, //const void* pNext;
131 (VkDeviceQueueCreateFlags)0u, //VkDeviceQueueCreateFlags flags;
132 it->first, //deUint32 queueFamilyIndex;
133 static_cast<deUint32>(it->second.queue.size()), //deUint32 queueCount;
134 &queuePriorities[0] //const float* pQueuePriorities;
136 queueInfos.push_back(queueInfo);
140 const char * extensions[] =
142 "VK_KHR_timeline_semaphore"
144 const VkDeviceCreateInfo deviceInfo =
146 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //VkStructureType sType;
147 DE_NULL, //const void* pNext;
148 0u, //VkDeviceCreateFlags flags;
149 static_cast<deUint32>(queueInfos.size()), //deUint32 queueCreateInfoCount;
150 &queueInfos[0], //const VkDeviceQueueCreateInfo* pQueueCreateInfos;
151 0u, //deUint32 enabledLayerCount;
152 DE_NULL, //const char* const* ppEnabledLayerNames;
153 timelineSemaphore ? 1u : 0u, //deUint32 enabledExtensionCount;
154 extensions, //const char* const* ppEnabledExtensionNames;
155 &context.getDeviceFeatures() //const VkPhysicalDeviceFeatures* pEnabledFeatures;
158 if (timelineSemaphore && !context.getTimelineSemaphoreFeatures().timelineSemaphore)
159 TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
161 m_logicalDevice = createDevice(context.getPlatformInterface(), context.getInstance(), instance, physicalDevice, &deviceInfo);
162 m_deviceDriver = MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *m_logicalDevice));
163 m_allocator = MovePtr<Allocator>(new SimpleAllocator(*m_deviceDriver, *m_logicalDevice, getPhysicalDeviceMemoryProperties(instance, physicalDevice)));
165 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
166 for (int queueNdx = 0; queueNdx < static_cast<int>(it->second.queue.size()); ++queueNdx)
167 m_deviceDriver->getDeviceQueue(*m_logicalDevice, it->first, queueNdx, &it->second.queue[queueNdx]);
171 void addQueueIndex (const deUint32 queueFamilyIndex, const deUint32 count, const VkQueueFlags flags)
173 QueueData dataToPush;
174 dataToPush.flags = flags;
175 dataToPush.queue.resize(count);
176 m_queues[queueFamilyIndex] = dataToPush;
182 std::vector<QueuePair> getQueuesPairs (const VkQueueFlags flagsWrite, const VkQueueFlags flagsRead) const
184 std::map<deUint32, QueueData> queuesWrite;
185 std::map<deUint32, QueueData> queuesRead;
186 std::vector<QueuePair> queuesPairs;
188 for (std::map<deUint32, QueueData>::const_iterator it = m_queues.begin(); it != m_queues.end(); ++it)
190 const bool writeQueue = checkQueueFlags(it->second.flags, flagsWrite);
191 const bool readQueue = checkQueueFlags(it->second.flags, flagsRead);
193 if (!(writeQueue || readQueue))
196 if (writeQueue && readQueue)
198 queuesWrite[it->first] = it->second;
199 queuesRead[it->first] = it->second;
202 queuesWrite[it->first] = it->second;
204 queuesRead[it->first] = it->second;
207 for (std::map<deUint32, QueueData>::iterator write = queuesWrite.begin(); write != queuesWrite.end(); ++write)
208 for (std::map<deUint32, QueueData>::iterator read = queuesRead.begin(); read != queuesRead.end(); ++read)
210 const int writeSize = static_cast<int>(write->second.queue.size());
211 const int readSize = static_cast<int>(read->second.queue.size());
213 for (int writeNdx = 0; writeNdx < writeSize; ++writeNdx)
214 for (int readNdx = 0; readNdx < readSize; ++readNdx)
216 if (write->second.queue[writeNdx] != read->second.queue[readNdx])
218 queuesPairs.push_back(QueuePair(write->first, read->first, write->second.queue[writeNdx], read->second.queue[readNdx]));
219 writeNdx = readNdx = std::max(writeSize, readSize); //exit from the loops
224 if (queuesPairs.empty())
225 TCU_THROW(NotSupportedError, "Queue not found");
230 Queue getDefaultQueue(const VkQueueFlags flagsOp) const
232 for (std::map<deUint32, QueueData>::const_iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
234 if (checkQueueFlags(it->second.flags, flagsOp))
235 return Queue(it->first, it->second.queue[0]);
238 TCU_THROW(NotSupportedError, "Queue not found");
241 Queue getQueue (const deUint32 familyIdx, const deUint32 queueIdx)
243 return Queue(familyIdx, m_queues[familyIdx].queue[queueIdx]);
246 VkQueueFlags getQueueFamilyFlags (const deUint32 familyIdx)
248 return m_queues[familyIdx].flags;
251 deUint32 queueFamilyCount (const deUint32 familyIdx)
253 return (deUint32) m_queues[familyIdx].queue.size();
256 deUint32 familyCount (void) const
258 return (deUint32) m_queues.size();
261 deUint32 totalQueueCount (void)
265 for (deUint32 familyIdx = 0; familyIdx < familyCount(); familyIdx++)
267 count += queueFamilyCount(familyIdx);
273 VkDevice getDevice (void) const
275 return *m_logicalDevice;
278 const DeviceInterface& getDeviceInterface (void) const
280 return *m_deviceDriver;
283 Allocator& getAllocator (void)
288 static SharedPtr<MultiQueues> getInstance(const Context& context, bool timelineSemaphore)
291 m_multiQueues = SharedPtr<MultiQueues>(new MultiQueues(context, timelineSemaphore));
293 return m_multiQueues;
295 static void destroy()
297 m_multiQueues.clear();
301 Move<VkDevice> m_logicalDevice;
302 MovePtr<DeviceDriver> m_deviceDriver;
303 MovePtr<Allocator> m_allocator;
304 std::map<deUint32, QueueData> m_queues;
305 deUint32 m_queueCount;
307 static SharedPtr<MultiQueues> m_multiQueues;
309 SharedPtr<MultiQueues> MultiQueues::m_multiQueues;
311 void createBarrierMultiQueue (const DeviceInterface& vk,
312 const VkCommandBuffer& cmdBuffer,
313 const SyncInfo& writeSync,
314 const SyncInfo& readSync,
315 const Resource& resource,
316 const deUint32 writeFamily,
317 const deUint32 readFamily,
318 const VkSharingMode sharingMode,
319 const bool secondQueue = false)
321 if (resource.getType() == RESOURCE_TYPE_IMAGE)
323 VkImageMemoryBarrier barrier = makeImageMemoryBarrier(secondQueue ? 0u : writeSync.accessMask, !secondQueue ? 0u : readSync.accessMask,
324 writeSync.imageLayout, readSync.imageLayout, resource.getImage().handle, resource.getImage().subresourceRange);
326 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
328 barrier.srcQueueFamilyIndex = writeFamily;
329 barrier.dstQueueFamilyIndex = readFamily;
330 vk.cmdPipelineBarrier(cmdBuffer, secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask,
331 !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL,
332 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
334 else if (!secondQueue)
336 vk.cmdPipelineBarrier(cmdBuffer, secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask,
337 !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL,
338 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
341 else if (resource.getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(resource.getType()))
343 VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(secondQueue ? 0u : writeSync.accessMask, !secondQueue ? 0u : readSync.accessMask,
344 resource.getBuffer().handle, resource.getBuffer().offset, resource.getBuffer().size);
346 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
348 barrier.srcQueueFamilyIndex = writeFamily;
349 barrier.dstQueueFamilyIndex = readFamily;
352 vk.cmdPipelineBarrier(cmdBuffer, secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask, !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, (const VkBufferMemoryBarrier*)&barrier, 0u, (const VkImageMemoryBarrier *)DE_NULL);
356 class BaseTestInstance : public TestInstance
359 BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, bool timelineSemaphore)
360 : TestInstance (context)
361 , m_queues (MultiQueues::getInstance(context, timelineSemaphore))
362 , m_opContext (new OperationContext(context, pipelineCacheData, m_queues->getDeviceInterface(), m_queues->getDevice(), m_queues->getAllocator()))
363 , m_resourceDesc (resourceDesc)
364 , m_writeOp (writeOp)
370 const SharedPtr<MultiQueues> m_queues;
371 const UniquePtr<OperationContext> m_opContext;
372 const ResourceDescription m_resourceDesc;
373 const OperationSupport& m_writeOp;
374 const OperationSupport& m_readOp;
377 class BinarySemaphoreTestInstance : public BaseTestInstance
380 BinarySemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
381 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData, false)
382 , m_sharingMode (sharingMode)
386 tcu::TestStatus iterate (void)
388 const DeviceInterface& vk = m_opContext->getDeviceInterface();
389 const VkDevice device = m_opContext->getDevice();
390 const std::vector<QueuePair> queuePairs = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
392 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
395 const UniquePtr<Resource> resource (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getOutResourceUsageFlags() | m_readOp.getInResourceUsageFlags()));
396 const UniquePtr<Operation> writeOp (m_writeOp.build(*m_opContext, *resource));
397 const UniquePtr<Operation> readOp (m_readOp.build (*m_opContext, *resource));
399 const Move<VkCommandPool> cmdPool[] =
401 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
402 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
404 const Move<VkCommandBuffer> ptrCmdBuffer[] =
406 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
407 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
409 const VkCommandBuffer cmdBuffers[] =
411 *ptrCmdBuffer[QUEUETYPE_WRITE],
412 *ptrCmdBuffer[QUEUETYPE_READ]
414 const Unique<VkSemaphore> semaphore (createSemaphore(vk, device));
415 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
416 const VkSubmitInfo submitInfo[] =
419 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
420 DE_NULL, // const void* pNext;
421 0u, // deUint32 waitSemaphoreCount;
422 DE_NULL, // const VkSemaphore* pWaitSemaphores;
423 (const VkPipelineStageFlags*)DE_NULL,
424 1u, // deUint32 commandBufferCount;
425 &cmdBuffers[QUEUETYPE_WRITE], // const VkCommandBuffer* pCommandBuffers;
426 1u, // deUint32 signalSemaphoreCount;
427 &semaphore.get(), // const VkSemaphore* pSignalSemaphores;
430 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
431 DE_NULL, // const void* pNext;
432 1u, // deUint32 waitSemaphoreCount;
433 &semaphore.get(), // const VkSemaphore* pWaitSemaphores;
434 stageBits, // const VkPipelineStageFlags* pWaitDstStageMask;
435 1u, // deUint32 commandBufferCount;
436 &cmdBuffers[QUEUETYPE_READ], // const VkCommandBuffer* pCommandBuffers;
437 0u, // deUint32 signalSemaphoreCount;
438 DE_NULL, // const VkSemaphore* pSignalSemaphores;
441 const SyncInfo writeSync = writeOp->getOutSyncInfo();
442 const SyncInfo readSync = readOp->getInSyncInfo();
444 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
445 writeOp->recordCommands (cmdBuffers[QUEUETYPE_WRITE]);
446 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
447 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
449 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
450 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
451 readOp->recordCommands (cmdBuffers[QUEUETYPE_READ]);
452 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
454 VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueWrite, 1u, &submitInfo[QUEUETYPE_WRITE], DE_NULL));
455 VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueRead, 1u, &submitInfo[QUEUETYPE_READ], DE_NULL));
456 VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueWrite));
457 VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueRead));
460 const Data expected = writeOp->getData();
461 const Data actual = readOp->getData();
463 if (isIndirectBuffer(m_resourceDesc.type))
465 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
466 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
468 if (actualValue < expectedValue)
469 return tcu::TestStatus::fail("Counter value is smaller than expected");
473 if (0 != deMemCmp(expected.data, actual.data, expected.size))
474 return tcu::TestStatus::fail("Memory contents don't match");
478 return tcu::TestStatus::pass("OK");
482 const VkSharingMode m_sharingMode;
486 inline SharedPtr<Move<T> > makeVkSharedPtr (Move<T> move)
488 return SharedPtr<Move<T> >(new Move<T>(move));
491 class TimelineSemaphoreTestInstance : public BaseTestInstance
494 TimelineSemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const SharedPtr<OperationSupport>& writeOp, const SharedPtr<OperationSupport>& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
495 : BaseTestInstance (context, resourceDesc, *writeOp, *readOp, pipelineCacheData, true)
496 , m_sharingMode (sharingMode)
498 deUint32 maxQueues = 0;
499 std::vector<deUint32> queueFamilies;
501 if (m_queues->totalQueueCount() < 2)
502 TCU_THROW(NotSupportedError, "Not enough queues");
504 for (deUint32 familyNdx = 0; familyNdx < m_queues->familyCount(); familyNdx++)
506 maxQueues = std::max(m_queues->queueFamilyCount(familyNdx), maxQueues);
507 queueFamilies.push_back(familyNdx);
510 // Create a chain of operations copying data from one resource
511 // to another across at least every single queue of the system
512 // at least once. Each of the operation will be executing with
513 // a dependency on the previous using timeline points.
514 m_opSupports.push_back(writeOp);
515 m_opQueues.push_back(m_queues->getDefaultQueue(writeOp->getOutResourceUsageFlags()));
517 for (deUint32 queueIdx = 0; queueIdx < maxQueues; queueIdx++)
519 for (deUint32 familyIdx = 0; familyIdx < m_queues->familyCount(); familyIdx++)
521 for (deUint32 copyOpIdx = 0; copyOpIdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpIdx++)
523 if (isResourceSupported(s_copyOps[copyOpIdx], resourceDesc))
525 SharedPtr<OperationSupport> opSupport (makeOperationSupport(s_copyOps[copyOpIdx], m_resourceDesc).release());
527 if (!checkQueueFlags(opSupport->getQueueFlags(*m_opContext), m_queues->getQueueFamilyFlags(familyIdx)))
530 m_opSupports.push_back(opSupport);
531 m_opQueues.push_back(m_queues->getQueue(familyIdx, queueIdx % m_queues->queueFamilyCount(familyIdx)));
538 m_opSupports.push_back(readOp);
539 m_opQueues.push_back(m_queues->getDefaultQueue(readOp->getInResourceUsageFlags()));
541 // Now create the resources with the usage associated to the
542 // operation performed on the resource.
543 for (deUint32 opIdx = 0; opIdx < (m_opSupports.size() - 1); opIdx++)
545 deUint32 usage = m_opSupports[opIdx]->getOutResourceUsageFlags() | m_opSupports[opIdx + 1]->getInResourceUsageFlags();
547 m_resources.push_back(SharedPtr<Resource>(new Resource(*m_opContext, m_resourceDesc, usage, m_sharingMode, queueFamilies)));
550 // Finally create the operations using the resources.
551 m_ops.push_back(SharedPtr<Operation>(m_opSupports[0]->build(*m_opContext, *m_resources[0]).release()));
552 for (deUint32 opIdx = 1; opIdx < (m_opSupports.size() - 1); opIdx++)
553 m_ops.push_back(SharedPtr<Operation>(m_opSupports[opIdx]->build(*m_opContext, *m_resources[opIdx - 1], *m_resources[opIdx]).release()));
554 m_ops.push_back(SharedPtr<Operation>(m_opSupports[m_opSupports.size() - 1]->build(*m_opContext, *m_resources.back()).release()));
557 tcu::TestStatus iterate (void)
559 const DeviceInterface& vk = m_opContext->getDeviceInterface();
560 const VkDevice device = m_opContext->getDevice();
561 de::Random rng (1234);
562 const Unique<VkSemaphore> semaphore (createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE_KHR));
563 std::vector<SharedPtr<Move<VkCommandPool> > > cmdPools;
564 std::vector<SharedPtr<Move<VkCommandBuffer> > > ptrCmdBuffers;
565 std::vector<VkCommandBuffer> cmdBuffers;
566 std::vector<deUint64> timelineValues;
568 cmdPools.resize(m_queues->familyCount());
569 for (deUint32 familyIdx = 0; familyIdx < m_queues->familyCount(); familyIdx++)
570 cmdPools[familyIdx] = makeVkSharedPtr(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, familyIdx));
572 ptrCmdBuffers.resize(m_ops.size());
573 cmdBuffers.resize(m_ops.size());
574 for (deUint32 opIdx = 0; opIdx < m_ops.size(); opIdx++)
576 deUint64 increment = 1 + rng.getUint8();
578 ptrCmdBuffers[opIdx] = makeVkSharedPtr(makeCommandBuffer(vk, device, **cmdPools[m_opQueues[opIdx].family]));
579 cmdBuffers[opIdx] = **ptrCmdBuffers[opIdx];
581 timelineValues.push_back(timelineValues.empty() ? increment : (timelineValues.back() + increment));
584 for (deUint32 opIdx = 0; opIdx < m_ops.size(); opIdx++)
586 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
587 const VkTimelineSemaphoreSubmitInfoKHR timelineSubmitInfo =
589 VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR, // VkStructureType sType;
590 DE_NULL, // const void* pNext;
591 opIdx == 0 ? 0u : 1u, // deUint32 waitSemaphoreValueCount
592 opIdx == 0 ? DE_NULL : &timelineValues[opIdx - 1], // const deUint64* pWaitSemaphoreValues
593 1u, // deUint32 signalSemaphoreValueCount
594 &timelineValues[opIdx], // const deUint64* pSignalSemaphoreValues
596 const VkSubmitInfo submitInfo =
598 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
599 &timelineSubmitInfo, // const void* pNext;
600 opIdx == 0 ? 0u : 1u, // deUint32 waitSemaphoreCount;
601 &semaphore.get(), // const VkSemaphore* pWaitSemaphores;
603 1u, // deUint32 commandBufferCount;
604 &cmdBuffers[opIdx], // const VkCommandBuffer* pCommandBuffers;
605 1u, // deUint32 signalSemaphoreCount;
606 &semaphore.get(), // const VkSemaphore* pSignalSemaphores;
609 beginCommandBuffer(vk, cmdBuffers[opIdx]);
613 const SyncInfo writeSync = m_ops[opIdx - 1]->getOutSyncInfo();
614 const SyncInfo readSync = m_ops[opIdx]->getInSyncInfo();
615 const Resource& resource = *m_resources[opIdx - 1].get();
617 createBarrierMultiQueue(vk, cmdBuffers[opIdx], writeSync, readSync, resource, m_opQueues[opIdx - 1].family, m_opQueues[opIdx].family, m_sharingMode, true);
620 m_ops[opIdx]->recordCommands(cmdBuffers[opIdx]);
622 if (opIdx < (m_ops.size() - 1))
624 const SyncInfo writeSync = m_ops[opIdx]->getOutSyncInfo();
625 const SyncInfo readSync = m_ops[opIdx + 1]->getInSyncInfo();
626 const Resource& resource = *m_resources[opIdx].get();
628 createBarrierMultiQueue(vk, cmdBuffers[opIdx], writeSync, readSync, resource, m_opQueues[opIdx].family, m_opQueues[opIdx + 1].family, m_sharingMode);
631 endCommandBuffer(vk, cmdBuffers[opIdx]);
633 VK_CHECK(vk.queueSubmit(m_opQueues[opIdx].queue, 1u, &submitInfo, DE_NULL));
637 VK_CHECK(vk.queueWaitIdle(m_opQueues.back().queue));
640 const Data expected = m_ops.front()->getData();
641 const Data actual = m_ops.back()->getData();
643 if (0 != deMemCmp(expected.data, actual.data, expected.size))
644 return tcu::TestStatus::fail("Memory contents don't match");
647 // Make the validation layers happy.
648 for (deUint32 opIdx = 0; opIdx < m_opQueues.size(); opIdx++)
649 VK_CHECK(vk.queueWaitIdle(m_opQueues[opIdx].queue));
651 return tcu::TestStatus::pass("OK");
655 const VkSharingMode m_sharingMode;
656 std::vector<SharedPtr<OperationSupport> > m_opSupports;
657 std::vector<SharedPtr<Operation> > m_ops;
658 std::vector<SharedPtr<Resource> > m_resources;
659 std::vector<Queue> m_opQueues;
662 class FenceTestInstance : public BaseTestInstance
665 FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
666 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData, false)
667 , m_sharingMode (sharingMode)
671 tcu::TestStatus iterate (void)
673 const DeviceInterface& vk = m_opContext->getDeviceInterface();
674 const VkDevice device = m_opContext->getDevice();
675 const std::vector<QueuePair> queuePairs = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
677 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
679 const UniquePtr<Resource> resource (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getOutResourceUsageFlags() | m_readOp.getInResourceUsageFlags()));
680 const UniquePtr<Operation> writeOp (m_writeOp.build(*m_opContext, *resource));
681 const UniquePtr<Operation> readOp (m_readOp.build(*m_opContext, *resource));
682 const Move<VkCommandPool> cmdPool[] =
684 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
685 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
687 const Move<VkCommandBuffer> ptrCmdBuffer[] =
689 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
690 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
692 const VkCommandBuffer cmdBuffers[] =
694 *ptrCmdBuffer[QUEUETYPE_WRITE],
695 *ptrCmdBuffer[QUEUETYPE_READ]
697 const SyncInfo writeSync = writeOp->getOutSyncInfo();
698 const SyncInfo readSync = readOp->getInSyncInfo();
700 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
701 writeOp->recordCommands (cmdBuffers[QUEUETYPE_WRITE]);
702 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
703 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_WRITE]);
705 submitCommandsAndWait (vk, device, queuePairs[pairNdx].queueWrite, cmdBuffers[QUEUETYPE_WRITE]);
707 beginCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
708 createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
709 readOp->recordCommands (cmdBuffers[QUEUETYPE_READ]);
710 endCommandBuffer (vk, cmdBuffers[QUEUETYPE_READ]);
712 submitCommandsAndWait (vk, device, queuePairs[pairNdx].queueRead, cmdBuffers[QUEUETYPE_READ]);
715 const Data expected = writeOp->getData();
716 const Data actual = readOp->getData();
718 if (isIndirectBuffer(m_resourceDesc.type))
720 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
721 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
723 if (actualValue < expectedValue)
724 return tcu::TestStatus::fail("Counter value is smaller than expected");
728 if (0 != deMemCmp(expected.data, actual.data, expected.size))
729 return tcu::TestStatus::fail("Memory contents don't match");
733 return tcu::TestStatus::pass("OK");
737 const VkSharingMode m_sharingMode;
740 class BaseTestCase : public TestCase
743 BaseTestCase (tcu::TestContext& testCtx,
744 const std::string& name,
745 const std::string& description,
746 const SyncPrimitive syncPrimitive,
747 const ResourceDescription resourceDesc,
748 const OperationName writeOp,
749 const OperationName readOp,
750 const VkSharingMode sharingMode,
751 PipelineCacheData& pipelineCacheData)
752 : TestCase (testCtx, name, description)
753 , m_resourceDesc (resourceDesc)
754 , m_writeOp (makeOperationSupport(writeOp, resourceDesc).release())
755 , m_readOp (makeOperationSupport(readOp, resourceDesc).release())
756 , m_syncPrimitive (syncPrimitive)
757 , m_sharingMode (sharingMode)
758 , m_pipelineCacheData (pipelineCacheData)
762 void initPrograms (SourceCollections& programCollection) const
764 m_writeOp->initPrograms(programCollection);
765 m_readOp->initPrograms(programCollection);
767 if (m_syncPrimitive == SYNC_PRIMITIVE_TIMELINE_SEMAPHORE)
769 for (deUint32 copyOpNdx = 0; copyOpNdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpNdx++)
771 if (isResourceSupported(s_copyOps[copyOpNdx], m_resourceDesc))
772 makeOperationSupport(s_copyOps[copyOpNdx], m_resourceDesc)->initPrograms(programCollection);
777 TestInstance* createInstance (Context& context) const
779 switch (m_syncPrimitive)
781 case SYNC_PRIMITIVE_FENCE:
782 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
783 case SYNC_PRIMITIVE_BINARY_SEMAPHORE:
784 return new BinarySemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
785 case SYNC_PRIMITIVE_TIMELINE_SEMAPHORE:
786 return new TimelineSemaphoreTestInstance(context, m_resourceDesc, m_writeOp, m_readOp, m_pipelineCacheData, m_sharingMode);
794 const ResourceDescription m_resourceDesc;
795 const SharedPtr<OperationSupport> m_writeOp;
796 const SharedPtr<OperationSupport> m_readOp;
797 const SyncPrimitive m_syncPrimitive;
798 const VkSharingMode m_sharingMode;
799 PipelineCacheData& m_pipelineCacheData;
802 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
804 tcu::TestContext& testCtx = group->getTestContext();
809 SyncPrimitive syncPrimitive;
813 { "fence", SYNC_PRIMITIVE_FENCE, 1 },
814 { "binary_semaphore", SYNC_PRIMITIVE_BINARY_SEMAPHORE, 1 },
815 { "timeline_semaphore", SYNC_PRIMITIVE_TIMELINE_SEMAPHORE, 1 }
818 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
820 MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
822 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
823 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
825 const OperationName writeOp = s_writeOps[writeOpNdx];
826 const OperationName readOp = s_readOps[readOpNdx];
827 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
830 MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
832 for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx)
833 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
835 const ResourceDescription& resource = s_resources[resourceNdx];
836 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
838 std::string name = getResourceName(resource);
839 VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE;
841 // queue family sharing mode used for resource
844 name += "_concurrent";
845 sharingMode = VK_SHARING_MODE_CONCURRENT;
848 name += "_exclusive";
850 opGroup->addChild(new BaseTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *pipelineCacheData));
855 synchGroup->addChild(opGroup.release());
857 group->addChild(synchGroup.release());
861 void cleanupGroup (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
864 DE_UNREF(pipelineCacheData);
865 // Destroy singleton object
866 MultiQueues::destroy();
871 tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
873 return createTestGroup(testCtx, "multi_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData, cleanupGroup);