Check timeline semaphore features only when used.
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / synchronization / vktSynchronizationOperationMultiQueueTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Synchronization primitive tests with multi queue
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktSynchronizationOperationMultiQueueTests.hpp"
25 #include "vkDefs.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vkRef.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkMemUtil.hpp"
31 #include "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"
45
46 #include <set>
47
48 namespace vkt
49 {
50 namespace synchronization
51 {
52 namespace
53 {
54 using namespace vk;
55 using de::MovePtr;
56 using de::SharedPtr;
57 using de::UniquePtr;
58 using de::SharedPtr;
59
60 enum QueueType
61 {
62         QUEUETYPE_WRITE,
63         QUEUETYPE_READ
64 };
65
66 struct QueuePair
67 {
68         QueuePair       (const deUint32 familyWrite, const deUint32 familyRead, const VkQueue write, const VkQueue read)
69                 : familyIndexWrite      (familyWrite)
70                 , familyIndexRead       (familyRead)
71                 , queueWrite            (write)
72                 , queueRead                     (read)
73         {}
74
75         deUint32        familyIndexWrite;
76         deUint32        familyIndexRead;
77         VkQueue         queueWrite;
78         VkQueue         queueRead;
79 };
80
81 struct Queue
82 {
83         Queue   (const deUint32 familyOp, const VkQueue queueOp)
84                 :       family  (familyOp)
85                 ,       queue   (queueOp)
86         {}
87
88         deUint32        family;
89         VkQueue         queue;
90 };
91
92 bool checkQueueFlags (VkQueueFlags availableFlags, const VkQueueFlags neededFlags)
93 {
94         if ((availableFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) != 0)
95                 availableFlags |= VK_QUEUE_TRANSFER_BIT;
96
97         return (availableFlags & neededFlags) != 0;
98 }
99
100 class MultiQueues
101 {
102         struct QueueData
103         {
104                 VkQueueFlags                    flags;
105                 std::vector<VkQueue>    queue;
106         };
107
108         MultiQueues     (const Context& context, bool timelineSemaphore)
109                 : m_queueCount  (0)
110         {
111                 const InstanceInterface&                                        instance                                = context.getInstanceInterface();
112                 const VkPhysicalDevice                                          physicalDevice                  = context.getPhysicalDevice();
113                 const std::vector<VkQueueFamilyProperties>      queueFamilyProperties   = getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice);
114
115                 for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
116                 {
117                         addQueueIndex(queuePropertiesNdx,
118                                                   std::min(2u, queueFamilyProperties[queuePropertiesNdx].queueCount),
119                                                   queueFamilyProperties[queuePropertiesNdx].queueFlags);
120                 }
121
122                 std::vector<VkDeviceQueueCreateInfo>    queueInfos;
123                 const float                                                             queuePriorities[2] = { 1.0f, 1.0f };    //get max 2 queues from one family
124
125                 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
126                 {
127                         const VkDeviceQueueCreateInfo queueInfo =
128                         {
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;
135                         };
136                         queueInfos.push_back(queueInfo);
137                 }
138
139                 {
140                         const char *                                    extensions[]    =
141                         {
142                                 "VK_KHR_timeline_semaphore"
143                         };
144                         const VkDeviceCreateInfo                deviceInfo              =
145                         {
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;
156                         };
157
158                         if (timelineSemaphore && !context.getTimelineSemaphoreFeatures().timelineSemaphore)
159                                 TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
160
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)));
164
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]);
168                 }
169         }
170
171         void addQueueIndex (const deUint32 queueFamilyIndex, const deUint32 count, const VkQueueFlags flags)
172         {
173                 QueueData dataToPush;
174                 dataToPush.flags = flags;
175                 dataToPush.queue.resize(count);
176                 m_queues[queueFamilyIndex] = dataToPush;
177
178                 m_queueCount++;
179         }
180
181 public:
182         std::vector<QueuePair> getQueuesPairs (const VkQueueFlags flagsWrite, const VkQueueFlags flagsRead) const
183         {
184                 std::map<deUint32, QueueData>   queuesWrite;
185                 std::map<deUint32, QueueData>   queuesRead;
186                 std::vector<QueuePair>                  queuesPairs;
187
188                 for (std::map<deUint32, QueueData>::const_iterator it = m_queues.begin(); it != m_queues.end(); ++it)
189                 {
190                         const bool writeQueue   = checkQueueFlags(it->second.flags, flagsWrite);
191                         const bool readQueue    = checkQueueFlags(it->second.flags, flagsRead);
192
193                         if (!(writeQueue || readQueue))
194                                 continue;
195
196                         if (writeQueue && readQueue)
197                         {
198                                 queuesWrite[it->first]  = it->second;
199                                 queuesRead[it->first]   = it->second;
200                         }
201                         else if (writeQueue)
202                                 queuesWrite[it->first]  = it->second;
203                         else if (readQueue)
204                                 queuesRead[it->first]   = it->second;
205                 }
206
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)
209                 {
210                         const int writeSize     = static_cast<int>(write->second.queue.size());
211                         const int readSize      = static_cast<int>(read->second.queue.size());
212
213                         for (int writeNdx = 0; writeNdx < writeSize; ++writeNdx)
214                         for (int readNdx  = 0; readNdx  < readSize;  ++readNdx)
215                         {
216                                 if (write->second.queue[writeNdx] != read->second.queue[readNdx])
217                                 {
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
220                                 }
221                         }
222                 }
223
224                 if (queuesPairs.empty())
225                         TCU_THROW(NotSupportedError, "Queue not found");
226
227                 return queuesPairs;
228         }
229
230         Queue getDefaultQueue(const VkQueueFlags flagsOp) const
231         {
232                 for (std::map<deUint32, QueueData>::const_iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
233                 {
234                         if (checkQueueFlags(it->second.flags, flagsOp))
235                                 return Queue(it->first, it->second.queue[0]);
236                 }
237
238                 TCU_THROW(NotSupportedError, "Queue not found");
239         }
240
241         Queue getQueue (const deUint32 familyIdx, const deUint32 queueIdx)
242         {
243                 return Queue(familyIdx, m_queues[familyIdx].queue[queueIdx]);
244         }
245
246         VkQueueFlags getQueueFamilyFlags (const deUint32 familyIdx)
247         {
248                 return m_queues[familyIdx].flags;
249         }
250
251         deUint32 queueFamilyCount (const deUint32 familyIdx)
252         {
253                 return (deUint32) m_queues[familyIdx].queue.size();
254         }
255
256         deUint32 familyCount (void) const
257         {
258                 return (deUint32) m_queues.size();
259         }
260
261         deUint32 totalQueueCount (void)
262         {
263                 deUint32        count   = 0;
264
265                 for (deUint32 familyIdx = 0; familyIdx < familyCount(); familyIdx++)
266                 {
267                         count   += queueFamilyCount(familyIdx);
268                 }
269
270                 return count;
271         }
272
273         VkDevice getDevice (void) const
274         {
275                 return *m_logicalDevice;
276         }
277
278         const DeviceInterface& getDeviceInterface (void) const
279         {
280                 return *m_deviceDriver;
281         }
282
283         Allocator& getAllocator (void)
284         {
285                 return *m_allocator;
286         }
287
288         static SharedPtr<MultiQueues> getInstance(const Context& context, bool timelineSemaphore)
289         {
290                 if (!m_multiQueues)
291                         m_multiQueues = SharedPtr<MultiQueues>(new MultiQueues(context, timelineSemaphore));
292
293                 return m_multiQueues;
294         }
295         static void destroy()
296         {
297                 m_multiQueues.clear();
298         }
299
300 private:
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;
306
307         static SharedPtr<MultiQueues>   m_multiQueues;
308 };
309 SharedPtr<MultiQueues>                          MultiQueues::m_multiQueues;
310
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)
320 {
321         if (resource.getType() == RESOURCE_TYPE_IMAGE)
322         {
323                 VkImageMemoryBarrier barrier = makeImageMemoryBarrier(secondQueue ? 0u : writeSync.accessMask, !secondQueue ? 0u : readSync.accessMask,
324                         writeSync.imageLayout, readSync.imageLayout, resource.getImage().handle, resource.getImage().subresourceRange);
325
326                 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
327                 {
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);
333                 }
334                 else if (!secondQueue)
335                 {
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);
339                 }
340         }
341         else if (resource.getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(resource.getType()))
342         {
343                 VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(secondQueue ? 0u : writeSync.accessMask, !secondQueue ? 0u : readSync.accessMask,
344                         resource.getBuffer().handle, resource.getBuffer().offset, resource.getBuffer().size);
345
346                 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
347                 {
348                         barrier.srcQueueFamilyIndex = writeFamily;
349                         barrier.dstQueueFamilyIndex = readFamily;
350                 }
351
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);
353         }
354 }
355
356 class BaseTestInstance : public TestInstance
357 {
358 public:
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)
365                 , m_readOp                      (readOp)
366         {
367         }
368
369 protected:
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;
375 };
376
377 class BinarySemaphoreTestInstance : public BaseTestInstance
378 {
379 public:
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)
383         {
384         }
385
386         tcu::TestStatus iterate (void)
387         {
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));
391
392                 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
393                 {
394
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));
398
399                         const Move<VkCommandPool>               cmdPool[]               =
400                         {
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)
403                         };
404                         const Move<VkCommandBuffer>             ptrCmdBuffer[]  =
405                         {
406                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
407                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
408                         };
409                         const VkCommandBuffer                   cmdBuffers[]    =
410                         {
411                                 *ptrCmdBuffer[QUEUETYPE_WRITE],
412                                 *ptrCmdBuffer[QUEUETYPE_READ]
413                         };
414                         const Unique<VkSemaphore>               semaphore               (createSemaphore(vk, device));
415                         const VkPipelineStageFlags              stageBits[]             = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
416                         const VkSubmitInfo                              submitInfo[]    =
417                         {
418                                 {
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;
428                                 },
429                                 {
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;
439                                 }
440                         };
441                         const SyncInfo                                  writeSync               = writeOp->getOutSyncInfo();
442                         const SyncInfo                                  readSync                = readOp->getInSyncInfo();
443
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]);
448
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]);
453
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));
458
459                         {
460                                 const Data      expected        = writeOp->getData();
461                                 const Data      actual          = readOp->getData();
462
463                                 if (isIndirectBuffer(m_resourceDesc.type))
464                                 {
465                                         const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
466                                         const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
467
468                                         if (actualValue < expectedValue)
469                                                 return tcu::TestStatus::fail("Counter value is smaller than expected");
470                                 }
471                                 else
472                                 {
473                                         if (0 != deMemCmp(expected.data, actual.data, expected.size))
474                                                 return tcu::TestStatus::fail("Memory contents don't match");
475                                 }
476                         }
477                 }
478                 return tcu::TestStatus::pass("OK");
479         }
480
481 private:
482         const VkSharingMode     m_sharingMode;
483 };
484
485 template<typename T>
486 inline SharedPtr<Move<T> > makeVkSharedPtr (Move<T> move)
487 {
488         return SharedPtr<Move<T> >(new Move<T>(move));
489 }
490
491 class TimelineSemaphoreTestInstance : public BaseTestInstance
492 {
493 public:
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)
497         {
498                 deUint32                                maxQueues               = 0;
499                 std::vector<deUint32>   queueFamilies;
500
501                 if (m_queues->totalQueueCount() < 2)
502                         TCU_THROW(NotSupportedError, "Not enough queues");
503
504                 for (deUint32 familyNdx = 0; familyNdx < m_queues->familyCount(); familyNdx++)
505                 {
506                         maxQueues = std::max(m_queues->queueFamilyCount(familyNdx), maxQueues);
507                         queueFamilies.push_back(familyNdx);
508                 }
509
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()));
516
517                 for (deUint32 queueIdx = 0; queueIdx < maxQueues; queueIdx++)
518                 {
519                         for (deUint32 familyIdx = 0; familyIdx < m_queues->familyCount(); familyIdx++)
520                         {
521                                 for (deUint32 copyOpIdx = 0; copyOpIdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpIdx++)
522                                 {
523                                         if (isResourceSupported(s_copyOps[copyOpIdx], resourceDesc))
524                                         {
525                                                 SharedPtr<OperationSupport>     opSupport       (makeOperationSupport(s_copyOps[copyOpIdx], m_resourceDesc).release());
526
527                                                 if (!checkQueueFlags(opSupport->getQueueFlags(*m_opContext), m_queues->getQueueFamilyFlags(familyIdx)))
528                                                         continue;
529
530                                                 m_opSupports.push_back(opSupport);
531                                                 m_opQueues.push_back(m_queues->getQueue(familyIdx, queueIdx % m_queues->queueFamilyCount(familyIdx)));
532                                                 break;
533                                         }
534                                 }
535                         }
536                 }
537
538                 m_opSupports.push_back(readOp);
539                 m_opQueues.push_back(m_queues->getDefaultQueue(readOp->getInResourceUsageFlags()));
540
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++)
544                 {
545                         deUint32 usage = m_opSupports[opIdx]->getOutResourceUsageFlags() | m_opSupports[opIdx + 1]->getInResourceUsageFlags();
546
547                         m_resources.push_back(SharedPtr<Resource>(new Resource(*m_opContext, m_resourceDesc, usage, m_sharingMode, queueFamilies)));
548                 }
549
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()));
555         }
556
557         tcu::TestStatus iterate (void)
558         {
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;
567
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));
571
572                 ptrCmdBuffers.resize(m_ops.size());
573                 cmdBuffers.resize(m_ops.size());
574                 for (deUint32 opIdx = 0; opIdx < m_ops.size(); opIdx++)
575                 {
576                         deUint64        increment       = 1 + rng.getUint8();
577
578                         ptrCmdBuffers[opIdx] = makeVkSharedPtr(makeCommandBuffer(vk, device, **cmdPools[m_opQueues[opIdx].family]));
579                         cmdBuffers[opIdx] = **ptrCmdBuffers[opIdx];
580
581                         timelineValues.push_back(timelineValues.empty() ? increment : (timelineValues.back() + increment));
582                 }
583
584                 for (deUint32 opIdx = 0; opIdx < m_ops.size(); opIdx++)
585                 {
586                         const VkPipelineStageFlags                              stageBits[]                             = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
587                         const VkTimelineSemaphoreSubmitInfo             timelineSubmitInfo              =
588                         {
589                                 VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,               // 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
595                         };
596                         const VkSubmitInfo                                              submitInfo                              =
597                         {
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;
602                                 stageBits,
603                                 1u,                                                                     // deUint32                                     commandBufferCount;
604                                 &cmdBuffers[opIdx],                                     // const VkCommandBuffer*       pCommandBuffers;
605                                 1u,                                                                     // deUint32                                     signalSemaphoreCount;
606                                 &semaphore.get(),                                       // const VkSemaphore*           pSignalSemaphores;
607                         };
608
609                         beginCommandBuffer(vk, cmdBuffers[opIdx]);
610
611                         if (opIdx > 0)
612                         {
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();
616
617                                 createBarrierMultiQueue(vk, cmdBuffers[opIdx], writeSync, readSync, resource, m_opQueues[opIdx - 1].family, m_opQueues[opIdx].family, m_sharingMode, true);
618                         }
619
620                         m_ops[opIdx]->recordCommands(cmdBuffers[opIdx]);
621
622                         if (opIdx < (m_ops.size() - 1))
623                         {
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();
627
628                                 createBarrierMultiQueue(vk, cmdBuffers[opIdx], writeSync, readSync, resource, m_opQueues[opIdx].family, m_opQueues[opIdx + 1].family, m_sharingMode);
629                         }
630
631                         endCommandBuffer(vk, cmdBuffers[opIdx]);
632
633                         VK_CHECK(vk.queueSubmit(m_opQueues[opIdx].queue, 1u, &submitInfo, DE_NULL));
634                 }
635
636
637                 VK_CHECK(vk.queueWaitIdle(m_opQueues.back().queue));
638
639                 {
640                         const Data      expected        = m_ops.front()->getData();
641                         const Data      actual          = m_ops.back()->getData();
642
643                         if (0 != deMemCmp(expected.data, actual.data, expected.size))
644                                 return tcu::TestStatus::fail("Memory contents don't match");
645                 }
646
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));
650
651                 return tcu::TestStatus::pass("OK");
652         }
653
654 private:
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;
660 };
661
662 class FenceTestInstance : public BaseTestInstance
663 {
664 public:
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)
668         {
669         }
670
671         tcu::TestStatus iterate (void)
672         {
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));
676
677                 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
678                 {
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[]               =
683                         {
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)
686                         };
687                         const Move<VkCommandBuffer>             ptrCmdBuffer[]  =
688                         {
689                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
690                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
691                         };
692                         const VkCommandBuffer                   cmdBuffers[]    =
693                         {
694                                 *ptrCmdBuffer[QUEUETYPE_WRITE],
695                                 *ptrCmdBuffer[QUEUETYPE_READ]
696                         };
697                         const SyncInfo                                  writeSync               = writeOp->getOutSyncInfo();
698                         const SyncInfo                                  readSync                = readOp->getInSyncInfo();
699
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]);
704
705                         submitCommandsAndWait   (vk, device, queuePairs[pairNdx].queueWrite, cmdBuffers[QUEUETYPE_WRITE]);
706
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]);
711
712                         submitCommandsAndWait   (vk, device, queuePairs[pairNdx].queueRead, cmdBuffers[QUEUETYPE_READ]);
713
714                         {
715                                 const Data      expected = writeOp->getData();
716                                 const Data      actual   = readOp->getData();
717
718                                 if (isIndirectBuffer(m_resourceDesc.type))
719                                 {
720                                         const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
721                                         const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
722
723                                         if (actualValue < expectedValue)
724                                                 return tcu::TestStatus::fail("Counter value is smaller than expected");
725                                 }
726                                 else
727                                 {
728                                         if (0 != deMemCmp(expected.data, actual.data, expected.size))
729                                                 return tcu::TestStatus::fail("Memory contents don't match");
730                                 }
731                         }
732                 }
733                 return tcu::TestStatus::pass("OK");
734         }
735
736 private:
737         const VkSharingMode     m_sharingMode;
738 };
739
740 class BaseTestCase : public TestCase
741 {
742 public:
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)
759         {
760         }
761
762         void initPrograms (SourceCollections& programCollection) const
763         {
764                 m_writeOp->initPrograms(programCollection);
765                 m_readOp->initPrograms(programCollection);
766
767                 if (m_syncPrimitive == SYNC_PRIMITIVE_TIMELINE_SEMAPHORE)
768                 {
769                         for (deUint32 copyOpNdx = 0; copyOpNdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpNdx++)
770                         {
771                                 if (isResourceSupported(s_copyOps[copyOpNdx], m_resourceDesc))
772                                         makeOperationSupport(s_copyOps[copyOpNdx], m_resourceDesc)->initPrograms(programCollection);
773                         }
774                 }
775         }
776
777         TestInstance* createInstance (Context& context) const
778         {
779                 switch (m_syncPrimitive)
780                 {
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);
787                         default:
788                                 DE_ASSERT(0);
789                                 return DE_NULL;
790                 }
791         }
792
793 private:
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;
800 };
801
802 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
803 {
804         tcu::TestContext& testCtx = group->getTestContext();
805
806         static const struct
807         {
808                 const char*             name;
809                 SyncPrimitive   syncPrimitive;
810                 int                             numOptions;
811         } groups[] =
812         {
813                 { "fence",                              SYNC_PRIMITIVE_FENCE,                           1 },
814                 { "binary_semaphore",   SYNC_PRIMITIVE_BINARY_SEMAPHORE,        1 },
815                 { "timeline_semaphore", SYNC_PRIMITIVE_TIMELINE_SEMAPHORE,      1 }
816         };
817
818         for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
819         {
820                 MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
821
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)
824                 {
825                         const OperationName     writeOp         = s_writeOps[writeOpNdx];
826                         const OperationName     readOp          = s_readOps[readOpNdx];
827                         const std::string       opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
828                         bool                            empty           = true;
829
830                         MovePtr<tcu::TestCaseGroup> opGroup             (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
831
832                         for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx)
833                         for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
834                         {
835                                 const ResourceDescription&      resource        = s_resources[resourceNdx];
836                                 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
837                                 {
838                                         std::string                                     name            = getResourceName(resource);
839                                         VkSharingMode                           sharingMode = VK_SHARING_MODE_EXCLUSIVE;
840
841                                         // queue family sharing mode used for resource
842                                         if (optionNdx)
843                                         {
844                                                 name += "_concurrent";
845                                                 sharingMode = VK_SHARING_MODE_CONCURRENT;
846                                         }
847                                         else
848                                                 name += "_exclusive";
849
850                                         opGroup->addChild(new BaseTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *pipelineCacheData));
851                                         empty = false;
852                                 }
853                         }
854                         if (!empty)
855                                 synchGroup->addChild(opGroup.release());
856                 }
857                 group->addChild(synchGroup.release());
858         }
859 }
860
861 void cleanupGroup (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
862 {
863         DE_UNREF(group);
864         DE_UNREF(pipelineCacheData);
865         // Destroy singleton object
866         MultiQueues::destroy();
867 }
868
869 } // anonymous
870
871 tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
872 {
873         return createTestGroup(testCtx, "multi_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData, cleanupGroup);
874 }
875
876 } // synchronization
877 } // vkt