Fixes sync test shader instance counts
[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 "deUniquePtr.hpp"
37 #include "tcuTestLog.hpp"
38 #include "vktSynchronizationUtil.hpp"
39 #include "vktSynchronizationOperation.hpp"
40 #include "vktSynchronizationOperationTestData.hpp"
41 #include "vktSynchronizationOperationResources.hpp"
42 #include "vktTestGroupUtil.hpp"
43
44 namespace vkt
45 {
46 namespace synchronization
47 {
48 namespace
49 {
50 using namespace vk;
51 using de::MovePtr;
52 using de::UniquePtr;
53
54 enum QueueType
55 {
56         QUEUETYPE_WRITE,
57         QUEUETYPE_READ
58 };
59
60 struct QueuePair
61 {
62         QueuePair       (const deUint32 familyWrite, const deUint32 familyRead, const VkQueue write, const VkQueue read)
63                 : familyIndexWrite      (familyWrite)
64                 , familyIndexRead       (familyRead)
65                 , queueWrite            (write)
66                 , queueRead                     (read)
67         {}
68
69         deUint32        familyIndexWrite;
70         deUint32        familyIndexRead;
71         VkQueue         queueWrite;
72         VkQueue         queueRead;
73 };
74
75 bool checkQueueFlags (VkQueueFlags availableFlags, const VkQueueFlags neededFlags)
76 {
77         if ((availableFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) != 0)
78                 availableFlags |= VK_QUEUE_TRANSFER_BIT;
79
80         return (availableFlags & neededFlags) != 0;
81 }
82
83 class MultiQueues
84 {
85         struct QueueData
86         {
87                 VkQueueFlags                    flags;
88                 std::vector<VkQueue>    queue;
89         };
90
91 public:
92         MultiQueues     (const Context& context)
93         {
94                 const InstanceInterface&                                        instance                                = context.getInstanceInterface();
95                 const VkPhysicalDevice                                          physicalDevice                  = context.getPhysicalDevice();
96                 const std::vector<VkQueueFamilyProperties>      queueFamilyProperties   = getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice);
97
98                 for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx)
99                 {
100                         addQueueIndex(queuePropertiesNdx,
101                                                   std::min(2u, queueFamilyProperties[queuePropertiesNdx].queueCount),
102                                                   queueFamilyProperties[queuePropertiesNdx].queueFlags);
103                 }
104
105                 std::vector<VkDeviceQueueCreateInfo>    queueInfos;
106                 const float                                                             queuePriorities[2] = { 1.0f, 1.0f };    //get max 2 queues from one family
107
108                 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it!= m_queues.end(); ++it)
109                 {
110                         const VkDeviceQueueCreateInfo queueInfo =
111                         {
112                                 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,             //VkStructureType                       sType;
113                                 DE_NULL,                                                                                //const void*                           pNext;
114                                 (VkDeviceQueueCreateFlags)0u,                                   //VkDeviceQueueCreateFlags      flags;
115                                 it->first,                                                                              //deUint32                                      queueFamilyIndex;
116                                 static_cast<deUint32>(it->second.queue.size()), //deUint32                                      queueCount;
117                                 &queuePriorities[0]                                                             //const float*                          pQueuePriorities;
118                         };
119                         queueInfos.push_back(queueInfo);
120                 }
121
122                 {
123                         const VkDeviceCreateInfo                deviceInfo              =
124                         {
125                                 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                                                   //VkStructureType                                       sType;
126                                 DE_NULL,                                                                                                                //const void*                                           pNext;
127                                 0u,                                                                                                                             //VkDeviceCreateFlags                           flags;
128                                 static_cast<deUint32>(queueInfos.size()),                                               //deUint32                                                      queueCreateInfoCount;
129                                 &queueInfos[0],                                                                                                 //const VkDeviceQueueCreateInfo*        pQueueCreateInfos;
130                                 0u,                                                                                                                             //deUint32                                                      enabledLayerCount;
131                                 DE_NULL,                                                                                                                //const char* const*                            ppEnabledLayerNames;
132                                 0u,                                                                                                                             //deUint32                                                      enabledExtensionCount;
133                                 DE_NULL,                                                                                                                //const char* const*                            ppEnabledExtensionNames;
134                                 &context.getDeviceFeatures()                                                                    //const VkPhysicalDeviceFeatures*       pEnabledFeatures;
135                         };
136
137                         m_logicalDevice = createDevice(context.getPlatformInterface(), context.getInstance(), instance, physicalDevice, &deviceInfo);
138                         m_deviceDriver  = MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *m_logicalDevice));
139                         m_allocator             = MovePtr<Allocator>(new SimpleAllocator(*m_deviceDriver, *m_logicalDevice, getPhysicalDeviceMemoryProperties(instance, physicalDevice)));
140
141                         for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
142                         for (int queueNdx = 0; queueNdx < static_cast<int>(it->second.queue.size()); ++queueNdx)
143                                 m_deviceDriver->getDeviceQueue(*m_logicalDevice, it->first, queueNdx, &it->second.queue[queueNdx]);
144                 }
145         }
146
147         void addQueueIndex (const deUint32 queueFamilyIndex, const deUint32 count, const VkQueueFlags flags)
148         {
149                 QueueData dataToPush;
150                 dataToPush.flags = flags;
151                 dataToPush.queue.resize(count);
152                 m_queues[queueFamilyIndex] = dataToPush;
153         }
154
155         std::vector<QueuePair> getQueuesPairs (const VkQueueFlags flagsWrite, const VkQueueFlags flagsRead)
156         {
157                 std::map<deUint32, QueueData>   queuesWrite;
158                 std::map<deUint32, QueueData>   queuesRead;
159                 std::vector<QueuePair>                  queuesPairs;
160
161                 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it)
162                 {
163                         const bool writeQueue   = checkQueueFlags(it->second.flags, flagsWrite);
164                         const bool readQueue    = checkQueueFlags(it->second.flags, flagsRead);
165
166                         if (!(writeQueue || readQueue))
167                                 continue;
168
169                         if (writeQueue && readQueue)
170                         {
171                                 queuesWrite[it->first]  = it->second;
172                                 queuesRead[it->first]   = it->second;
173                         }
174                         else if (writeQueue)
175                                 queuesWrite[it->first]  = it->second;
176                         else if (readQueue)
177                                 queuesRead[it->first]   = it->second;
178                 }
179
180                 for (std::map<deUint32, QueueData>::iterator write = queuesWrite.begin(); write != queuesWrite.end(); ++write)
181                 for (std::map<deUint32, QueueData>::iterator read  = queuesRead.begin();  read  != queuesRead.end();  ++read)
182                 {
183                         const int writeSize     = static_cast<int>(write->second.queue.size());
184                         const int readSize      = static_cast<int>(read->second.queue.size());
185
186                         for (int writeNdx = 0; writeNdx < writeSize; ++writeNdx)
187                         for (int readNdx  = 0; readNdx  < readSize;  ++readNdx)
188                         {
189                                 if (write->second.queue[writeNdx] != read->second.queue[readNdx])
190                                 {
191                                         queuesPairs.push_back(QueuePair(write->first, read->first, write->second.queue[writeNdx], read->second.queue[readNdx]));
192                                         writeNdx = readNdx = std::max(writeSize, readSize);     //exit from the loops
193                                 }
194                         }
195                 }
196
197                 if (queuesPairs.empty())
198                         TCU_THROW(NotSupportedError, "Queue not found");
199
200                 return queuesPairs;
201         }
202
203         VkDevice getDevice (void) const
204         {
205                 return *m_logicalDevice;
206         }
207
208         const DeviceInterface& getDeviceInterface (void) const
209         {
210                 return *m_deviceDriver;
211         }
212
213         Allocator& getAllocator (void)
214         {
215                 return *m_allocator;
216         }
217
218 private:
219         Move<VkDevice>                                  m_logicalDevice;
220         MovePtr<DeviceDriver>                   m_deviceDriver;
221         MovePtr<Allocator>                              m_allocator;
222         std::map<deUint32, QueueData>   m_queues;
223 };
224
225 void createBarrierMultiQueue (const DeviceInterface&    vk,
226                                                           const VkCommandBuffer&        cmdBuffer,
227                                                           const SyncInfo&                       writeSync,
228                                                           const SyncInfo&                       readSync,
229                                                           const Resource&                       resource,
230                                                           const deUint32                        writeFamily,
231                                                           const deUint32                        readFamily,
232                                                           const VkSharingMode           sharingMode,
233                                                           const bool                            secondQueue = false)
234 {
235         if (resource.getType() == RESOURCE_TYPE_IMAGE)
236         {
237                 VkImageMemoryBarrier barrier = makeImageMemoryBarrier(secondQueue ? 0u : writeSync.accessMask, !secondQueue ? 0u : readSync.accessMask,
238                         writeSync.imageLayout, readSync.imageLayout, resource.getImage().handle, resource.getImage().subresourceRange);
239
240                 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
241                 {
242                         barrier.srcQueueFamilyIndex = writeFamily;
243                         barrier.dstQueueFamilyIndex = readFamily;
244                         vk.cmdPipelineBarrier(cmdBuffer, secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask,
245                                         !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL,
246                                         0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
247                 }
248                 else if (!secondQueue)
249                 {
250                         vk.cmdPipelineBarrier(cmdBuffer, secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask,
251                                         !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL,
252                                         0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
253                 }
254         }
255         else if (resource.getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(resource.getType()))
256         {
257                 VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(secondQueue ? 0u : writeSync.accessMask, !secondQueue ? 0u : readSync.accessMask,
258                         resource.getBuffer().handle, resource.getBuffer().offset, resource.getBuffer().size);
259
260                 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode)
261                 {
262                         barrier.srcQueueFamilyIndex = writeFamily;
263                         barrier.dstQueueFamilyIndex = readFamily;
264                 }
265
266                 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);
267         }
268 }
269
270 class BaseTestInstance : public TestInstance
271 {
272 public:
273         BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
274                 : TestInstance          (context)
275                 , m_queues                      (new MultiQueues(context))
276                 , m_opContext           (new OperationContext(context, pipelineCacheData, m_queues->getDeviceInterface(), m_queues->getDevice(), m_queues->getAllocator()))
277                 , m_resourceDesc        (resourceDesc)
278                 , m_writeOp                     (writeOp)
279                 , m_readOp                      (readOp)
280         {
281         }
282
283 protected:
284         const UniquePtr<MultiQueues>            m_queues;
285         const UniquePtr<OperationContext>       m_opContext;
286         const ResourceDescription                       m_resourceDesc;
287         const OperationSupport&                         m_writeOp;
288         const OperationSupport&                         m_readOp;
289 };
290
291 class SemaphoreTestInstance : public BaseTestInstance
292 {
293 public:
294         SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
295                 : BaseTestInstance      (context, resourceDesc, writeOp, readOp, pipelineCacheData)
296                 , m_sharingMode         (sharingMode)
297         {
298         }
299
300         tcu::TestStatus iterate (void)
301         {
302                 const DeviceInterface&                  vk                      = m_opContext->getDeviceInterface();
303                 const VkDevice                                  device          = m_opContext->getDevice();
304                 const std::vector<QueuePair>    queuePairs      = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
305
306                 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
307                 {
308
309                         const UniquePtr<Resource>               resource                (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getResourceUsageFlags() | m_readOp.getResourceUsageFlags()));
310                         const UniquePtr<Operation>              writeOp                 (m_writeOp.build(*m_opContext, *resource));
311                         const UniquePtr<Operation>              readOp                  (m_readOp.build (*m_opContext, *resource));
312
313                         const Move<VkCommandPool>               cmdPool[]               =
314                         {
315                                 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
316                                 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
317                         };
318                         const Move<VkCommandBuffer>             ptrCmdBuffer[]  =
319                         {
320                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
321                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
322                         };
323                         const VkCommandBuffer                   cmdBuffers[]    =
324                         {
325                                 *ptrCmdBuffer[QUEUETYPE_WRITE],
326                                 *ptrCmdBuffer[QUEUETYPE_READ]
327                         };
328                         const Unique<VkSemaphore>               semaphore               (createSemaphore(vk, device));
329                         const VkPipelineStageFlags              stageBits[]             = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
330                         const VkSubmitInfo                              submitInfo[]    =
331                         {
332                                 {
333                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,          // VkStructureType                      sType;
334                                         DE_NULL,                                                        // const void*                          pNext;
335                                         0u,                                                                     // deUint32                                     waitSemaphoreCount;
336                                         DE_NULL,                                                        // const VkSemaphore*           pWaitSemaphores;
337                                         (const VkPipelineStageFlags*)DE_NULL,
338                                         1u,                                                                     // deUint32                                     commandBufferCount;
339                                         &cmdBuffers[QUEUETYPE_WRITE],           // const VkCommandBuffer*       pCommandBuffers;
340                                         1u,                                                                     // deUint32                                     signalSemaphoreCount;
341                                         &semaphore.get(),                                       // const VkSemaphore*           pSignalSemaphores;
342                                 },
343                                 {
344                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,          // VkStructureType                              sType;
345                                         DE_NULL,                                                        // const void*                                  pNext;
346                                         1u,                                                                     // deUint32                                             waitSemaphoreCount;
347                                         &semaphore.get(),                                       // const VkSemaphore*                   pWaitSemaphores;
348                                         stageBits,                                                      // const VkPipelineStageFlags*  pWaitDstStageMask;
349                                         1u,                                                                     // deUint32                                             commandBufferCount;
350                                         &cmdBuffers[QUEUETYPE_READ],            // const VkCommandBuffer*               pCommandBuffers;
351                                         0u,                                                                     // deUint32                                             signalSemaphoreCount;
352                                         DE_NULL,                                                        // const VkSemaphore*                   pSignalSemaphores;
353                                 }
354                         };
355                         const SyncInfo                                  writeSync               = writeOp->getSyncInfo();
356                         const SyncInfo                                  readSync                = readOp->getSyncInfo();
357
358                         beginCommandBuffer              (vk, cmdBuffers[QUEUETYPE_WRITE]);
359                         writeOp->recordCommands (cmdBuffers[QUEUETYPE_WRITE]);
360                         createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
361                         endCommandBuffer                (vk, cmdBuffers[QUEUETYPE_WRITE]);
362
363                         beginCommandBuffer              (vk, cmdBuffers[QUEUETYPE_READ]);
364                         createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
365                         readOp->recordCommands  (cmdBuffers[QUEUETYPE_READ]);
366                         endCommandBuffer                (vk, cmdBuffers[QUEUETYPE_READ]);
367
368                         VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueWrite, 1u, &submitInfo[QUEUETYPE_WRITE], DE_NULL));
369                         VK_CHECK(vk.queueSubmit(queuePairs[pairNdx].queueRead, 1u, &submitInfo[QUEUETYPE_READ], DE_NULL));
370                         VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueWrite));
371                         VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueRead));
372
373                         {
374                                 const Data      expected        = writeOp->getData();
375                                 const Data      actual          = readOp->getData();
376
377                                 if (isIndirectBuffer(m_resourceDesc.type))
378                                 {
379                                         const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
380                                         const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
381
382                                         if (actualValue < expectedValue)
383                                                 return tcu::TestStatus::fail("Counter value is smaller than expected");
384                                 }
385                                 else
386                                 {
387                                         if (0 != deMemCmp(expected.data, actual.data, expected.size))
388                                                 return tcu::TestStatus::fail("Memory contents don't match");
389                                 }
390                         }
391                 }
392                 return tcu::TestStatus::pass("OK");
393         }
394
395 private:
396         const VkSharingMode     m_sharingMode;
397 };
398
399 class FenceTestInstance : public BaseTestInstance
400 {
401 public:
402         FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode)
403                 : BaseTestInstance      (context, resourceDesc, writeOp, readOp, pipelineCacheData)
404                 , m_sharingMode         (sharingMode)
405         {
406         }
407
408         tcu::TestStatus iterate (void)
409         {
410                 const DeviceInterface&                  vk                      = m_opContext->getDeviceInterface();
411                 const VkDevice                                  device          = m_opContext->getDevice();
412                 const std::vector<QueuePair>    queuePairs      = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext));
413
414                 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx)
415                 {
416                         const UniquePtr<Resource>               resource                (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getResourceUsageFlags() | m_readOp.getResourceUsageFlags()));
417                         const UniquePtr<Operation>              writeOp                 (m_writeOp.build(*m_opContext, *resource));
418                         const UniquePtr<Operation>              readOp                  (m_readOp.build(*m_opContext, *resource));
419                         const Move<VkCommandPool>               cmdPool[]               =
420                         {
421                                 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite),
422                                 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead)
423                         };
424                         const Move<VkCommandBuffer>             ptrCmdBuffer[]  =
425                         {
426                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]),
427                                 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ])
428                         };
429                         const VkCommandBuffer                   cmdBuffers[]    =
430                         {
431                                 *ptrCmdBuffer[QUEUETYPE_WRITE],
432                                 *ptrCmdBuffer[QUEUETYPE_READ]
433                         };
434                         const SyncInfo                                  writeSync               = writeOp->getSyncInfo();
435                         const SyncInfo                                  readSync                = readOp->getSyncInfo();
436
437                         beginCommandBuffer              (vk, cmdBuffers[QUEUETYPE_WRITE]);
438                         writeOp->recordCommands (cmdBuffers[QUEUETYPE_WRITE]);
439                         createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_WRITE], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode);
440                         endCommandBuffer                (vk, cmdBuffers[QUEUETYPE_WRITE]);
441
442                         submitCommandsAndWait   (vk, device, queuePairs[pairNdx].queueWrite, cmdBuffers[QUEUETYPE_WRITE]);
443
444                         beginCommandBuffer              (vk, cmdBuffers[QUEUETYPE_READ]);
445                         createBarrierMultiQueue (vk, cmdBuffers[QUEUETYPE_READ], writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true);
446                         readOp->recordCommands  (cmdBuffers[QUEUETYPE_READ]);
447                         endCommandBuffer                (vk, cmdBuffers[QUEUETYPE_READ]);
448
449                         submitCommandsAndWait   (vk, device, queuePairs[pairNdx].queueRead, cmdBuffers[QUEUETYPE_READ]);
450
451                         {
452                                 const Data      expected = writeOp->getData();
453                                 const Data      actual   = readOp->getData();
454
455                                 if (isIndirectBuffer(m_resourceDesc.type))
456                                 {
457                                         const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
458                                         const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
459
460                                         if (actualValue < expectedValue)
461                                                 return tcu::TestStatus::fail("Counter value is smaller than expected");
462                                 }
463                                 else
464                                 {
465                                         if (0 != deMemCmp(expected.data, actual.data, expected.size))
466                                                 return tcu::TestStatus::fail("Memory contents don't match");
467                                 }
468                         }
469                 }
470                 return tcu::TestStatus::pass("OK");
471         }
472
473 private:
474         const VkSharingMode     m_sharingMode;
475 };
476
477 class BaseTestCase : public TestCase
478 {
479 public:
480         BaseTestCase (tcu::TestContext&                 testCtx,
481                                   const std::string&            name,
482                                   const std::string&            description,
483                                   const SyncPrimitive           syncPrimitive,
484                                   const ResourceDescription     resourceDesc,
485                                   const OperationName           writeOp,
486                                   const OperationName           readOp,
487                                   const VkSharingMode           sharingMode,
488                                   PipelineCacheData&            pipelineCacheData)
489                 : TestCase                              (testCtx, name, description)
490                 , m_resourceDesc                (resourceDesc)
491                 , m_writeOp                             (makeOperationSupport(writeOp, resourceDesc))
492                 , m_readOp                              (makeOperationSupport(readOp, resourceDesc))
493                 , m_syncPrimitive               (syncPrimitive)
494                 , m_sharingMode                 (sharingMode)
495                 , m_pipelineCacheData   (pipelineCacheData)
496         {
497         }
498
499         void initPrograms (SourceCollections& programCollection) const
500         {
501                 m_writeOp->initPrograms(programCollection);
502                 m_readOp->initPrograms(programCollection);
503         }
504
505         TestInstance* createInstance (Context& context) const
506         {
507                 switch (m_syncPrimitive)
508                 {
509                         case SYNC_PRIMITIVE_FENCE:
510                                 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
511                         case SYNC_PRIMITIVE_SEMAPHORE:
512                                 return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode);
513                         default:
514                                 DE_ASSERT(0);
515                                 return DE_NULL;
516                 }
517         }
518
519 private:
520         const ResourceDescription                               m_resourceDesc;
521         const UniquePtr<OperationSupport>               m_writeOp;
522         const UniquePtr<OperationSupport>               m_readOp;
523         const SyncPrimitive                                             m_syncPrimitive;
524         const VkSharingMode                                             m_sharingMode;
525         PipelineCacheData&                                              m_pipelineCacheData;
526 };
527
528 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
529 {
530         tcu::TestContext& testCtx = group->getTestContext();
531
532         static const struct
533         {
534                 const char*             name;
535                 SyncPrimitive   syncPrimitive;
536                 int                             numOptions;
537         } groups[] =
538         {
539                 { "fence",              SYNC_PRIMITIVE_FENCE,           1 },
540                 { "semaphore",  SYNC_PRIMITIVE_SEMAPHORE,       1 }
541         };
542
543         for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
544         {
545                 MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
546
547                 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
548                 for (int readOpNdx  = 0; readOpNdx  < DE_LENGTH_OF_ARRAY(s_readOps);  ++readOpNdx)
549                 {
550                         const OperationName     writeOp         = s_writeOps[writeOpNdx];
551                         const OperationName     readOp          = s_readOps[readOpNdx];
552                         const std::string       opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
553                         bool                            empty           = true;
554
555                         MovePtr<tcu::TestCaseGroup> opGroup             (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
556
557                         for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx)
558                         for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
559                         {
560                                 const ResourceDescription&      resource        = s_resources[resourceNdx];
561                                 std::string                                     name            = getResourceName(resource);
562                                 VkSharingMode                           sharingMode = VK_SHARING_MODE_EXCLUSIVE;
563
564                                 // queue family sharing mode used for resource
565                                 if (optionNdx)
566                                 {
567                                         name += "_concurrent";
568                                         sharingMode = VK_SHARING_MODE_CONCURRENT;
569                                 }
570                                 else
571                                         name += "_exclusive";
572
573                                 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
574                                 {
575                                         opGroup->addChild(new BaseTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *pipelineCacheData));
576                                         empty = false;
577                                 }
578                         }
579                         if (!empty)
580                                 synchGroup->addChild(opGroup.release());
581                 }
582                 group->addChild(synchGroup.release());
583         }
584 }
585
586 } // anonymous
587
588 tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
589 {
590         return createTestGroup(testCtx, "multi_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
591 }
592
593 } // synchronization
594 } // vkt