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