Fixes sync test shader instance counts
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / synchronization / vktSynchronizationOperationSingleQueueTests.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 single queue
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktSynchronizationOperationSingleQueueTests.hpp"
25 #include "vkDefs.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vkRef.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "deUniquePtr.hpp"
38 #include "tcuTestLog.hpp"
39 #include "vktSynchronizationUtil.hpp"
40 #include "vktSynchronizationOperation.hpp"
41 #include "vktSynchronizationOperationTestData.hpp"
42 #include "vktSynchronizationOperationResources.hpp"
43
44 namespace vkt
45 {
46 namespace synchronization
47 {
48 namespace
49 {
50 using namespace vk;
51
52 class BaseTestInstance : public TestInstance
53 {
54 public:
55         BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
56                 : TestInstance  (context)
57                 , m_opContext   (context, pipelineCacheData)
58                 , m_resource    (new Resource(m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
59                 , m_writeOp             (writeOp.build(m_opContext, *m_resource))
60                 , m_readOp              (readOp.build(m_opContext, *m_resource))
61         {
62         }
63
64 protected:
65         OperationContext                                        m_opContext;
66         const de::UniquePtr<Resource>           m_resource;
67         const de::UniquePtr<Operation>          m_writeOp;
68         const de::UniquePtr<Operation>          m_readOp;
69 };
70
71 class EventTestInstance : public BaseTestInstance
72 {
73 public:
74         EventTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
75                 : BaseTestInstance              (context, resourceDesc, writeOp, readOp, pipelineCacheData)
76         {
77         }
78
79         tcu::TestStatus iterate (void)
80         {
81                 const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
82                 const VkDevice                                  device                          = m_context.getDevice();
83                 const VkQueue                                   queue                           = m_context.getUniversalQueue();
84                 const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
85                 const Unique<VkCommandPool>             cmdPool                         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
86                 const Unique<VkCommandBuffer>   cmdBuffer                       (makeCommandBuffer(vk, device, *cmdPool));
87                 const Unique<VkEvent>                   event                           (createEvent(vk, device));
88                 const SyncInfo                                  writeSync                       = m_writeOp->getSyncInfo();
89                 const SyncInfo                                  readSync                        = m_readOp->getSyncInfo();
90
91                 beginCommandBuffer(vk, *cmdBuffer);
92
93                 m_writeOp->recordCommands(*cmdBuffer);
94                 vk.cmdSetEvent(*cmdBuffer, *event, writeSync.stageMask);
95
96                 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
97                 {
98                         const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
99                                 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
100                         vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
101                 }
102                 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
103                 {
104                         const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
105                                 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
106                         vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
107                 }
108
109                 m_readOp->recordCommands(*cmdBuffer);
110
111                 endCommandBuffer(vk, *cmdBuffer);
112                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
113
114                 {
115                         const Data      expected = m_writeOp->getData();
116                         const Data      actual   = m_readOp->getData();
117
118                         if (isIndirectBuffer(m_resource->getType()))
119                         {
120                                 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
121                                 const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
122
123                                 if (actualValue < expectedValue)
124                                         return tcu::TestStatus::fail("Counter value is smaller than expected");
125                         }
126                         else
127                         {
128                                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
129                                         return tcu::TestStatus::fail("Memory contents don't match");
130                         }
131                 }
132
133                 return tcu::TestStatus::pass("OK");
134         }
135 };
136
137 class BarrierTestInstance : public BaseTestInstance
138 {
139 public:
140         BarrierTestInstance     (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
141                 : BaseTestInstance              (context, resourceDesc, writeOp, readOp, pipelineCacheData)
142         {
143         }
144
145         tcu::TestStatus iterate (void)
146         {
147                 const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
148                 const VkDevice                                  device                          = m_context.getDevice();
149                 const VkQueue                                   queue                           = m_context.getUniversalQueue();
150                 const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
151                 const Unique<VkCommandPool>             cmdPool                         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
152                 const Move<VkCommandBuffer>             cmdBuffer                       (makeCommandBuffer(vk, device, *cmdPool));
153                 const SyncInfo                                  writeSync                       = m_writeOp->getSyncInfo();
154                 const SyncInfo                                  readSync                        = m_readOp->getSyncInfo();
155
156                 beginCommandBuffer(vk, *cmdBuffer);
157
158                 m_writeOp->recordCommands(*cmdBuffer);
159
160                 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
161                 {
162                         const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
163                                 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
164                         vk.cmdPipelineBarrier(*cmdBuffer,  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
165                 }
166                 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
167                 {
168                         const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
169                                 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
170                         vk.cmdPipelineBarrier(*cmdBuffer,  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
171                 }
172
173                 m_readOp->recordCommands(*cmdBuffer);
174
175                 endCommandBuffer(vk, *cmdBuffer);
176
177                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
178
179                 {
180                         const Data      expected = m_writeOp->getData();
181                         const Data      actual   = m_readOp->getData();
182
183                         if (isIndirectBuffer(m_resource->getType()))
184                         {
185                                 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
186                                 const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
187
188                                 if (actualValue < expectedValue)
189                                         return tcu::TestStatus::fail("Counter value is smaller than expected");
190                         }
191                         else
192                         {
193                                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
194                                         return tcu::TestStatus::fail("Memory contents don't match");
195                         }
196                 }
197
198                 return tcu::TestStatus::pass("OK");
199         }
200 };
201
202 class SemaphoreTestInstance : public BaseTestInstance
203 {
204 public:
205         SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
206                 : BaseTestInstance      (context, resourceDesc, writeOp, readOp, pipelineCacheData)
207         {
208         }
209
210         tcu::TestStatus iterate (void)
211         {
212                 enum {WRITE=0, READ, COUNT};
213                 const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
214                 const VkDevice                                  device                          = m_context.getDevice();
215                 const VkQueue                                   queue                           = m_context.getUniversalQueue();
216                 const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
217                 const Unique<VkSemaphore>               semaphore                       (createSemaphore (vk, device));
218                 const Unique<VkCommandPool>             cmdPool                         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
219                 const Move<VkCommandBuffer>             ptrCmdBuffer[COUNT]     = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
220                 VkCommandBuffer                                 cmdBuffers[COUNT]       = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
221                 const VkPipelineStageFlags              stageBits[]                     = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
222                 const VkSubmitInfo                              submitInfo[2]           =
223                                                                                                                         {
224                                                                                                                                 {
225                                                                                                                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,          // VkStructureType                      sType;
226                                                                                                                                         DE_NULL,                                                        // const void*                          pNext;
227                                                                                                                                         0u,                                                                     // deUint32                                     waitSemaphoreCount;
228                                                                                                                                         DE_NULL,                                                        // const VkSemaphore*           pWaitSemaphores;
229                                                                                                                                         (const VkPipelineStageFlags*)DE_NULL,
230                                                                                                                                         1u,                                                                     // deUint32                                     commandBufferCount;
231                                                                                                                                         &cmdBuffers[WRITE],                                     // const VkCommandBuffer*       pCommandBuffers;
232                                                                                                                                         1u,                                                                     // deUint32                                     signalSemaphoreCount;
233                                                                                                                                         &semaphore.get(),                                       // const VkSemaphore*           pSignalSemaphores;
234                                                                                                                                 },
235                                                                                                                                 {
236                                                                                                                                         VK_STRUCTURE_TYPE_SUBMIT_INFO,          // VkStructureType                              sType;
237                                                                                                                                         DE_NULL,                                                        // const void*                                  pNext;
238                                                                                                                                         1u,                                                                     // deUint32                                             waitSemaphoreCount;
239                                                                                                                                         &semaphore.get(),                                       // const VkSemaphore*                   pWaitSemaphores;
240                                                                                                                                         stageBits,                                                      // const VkPipelineStageFlags*  pWaitDstStageMask;
241                                                                                                                                         1u,                                                                     // deUint32                                             commandBufferCount;
242                                                                                                                                         &cmdBuffers[READ],                                      // const VkCommandBuffer*               pCommandBuffers;
243                                                                                                                                         0u,                                                                     // deUint32                                             signalSemaphoreCount;
244                                                                                                                                         DE_NULL,                                                        // const VkSemaphore*                   pSignalSemaphores;
245                                                                                                                                 }
246                                                                                                                         };
247                 const SyncInfo                                  writeSync                       = m_writeOp->getSyncInfo();
248                 const SyncInfo                                  readSync                        = m_readOp->getSyncInfo();
249
250                 beginCommandBuffer(vk, cmdBuffers[WRITE]);
251
252                 m_writeOp->recordCommands(cmdBuffers[WRITE]);
253
254                 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
255                 {
256                         const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
257                                 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
258                         vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
259                 }
260                 else
261                 {
262                         const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
263                                 m_resource->getBuffer().handle, 0, VK_WHOLE_SIZE);
264                         vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
265                 }
266
267                 endCommandBuffer(vk, cmdBuffers[WRITE]);
268
269                 beginCommandBuffer(vk, cmdBuffers[READ]);
270
271                 m_readOp->recordCommands(cmdBuffers[READ]);
272
273                 endCommandBuffer(vk, cmdBuffers[READ]);
274
275                 VK_CHECK(vk.queueSubmit(queue, 2u, submitInfo, DE_NULL));
276                 VK_CHECK(vk.queueWaitIdle(queue));
277
278                 {
279                         const Data      expected = m_writeOp->getData();
280                         const Data      actual   = m_readOp->getData();
281
282                         if (isIndirectBuffer(m_resource->getType()))
283                         {
284                                 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
285                                 const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
286
287                                 if (actualValue < expectedValue)
288                                         return tcu::TestStatus::fail("Counter value is smaller than expected");
289                         }
290                         else
291                         {
292                                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
293                                         return tcu::TestStatus::fail("Memory contents don't match");
294                         }
295                 }
296
297                 return tcu::TestStatus::pass("OK");
298         }
299 };
300
301 class FenceTestInstance : public BaseTestInstance
302 {
303 public:
304         FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
305                 : BaseTestInstance      (context, resourceDesc, writeOp, readOp, pipelineCacheData)
306         {
307         }
308
309         tcu::TestStatus iterate (void)
310         {
311                 enum {WRITE=0, READ, COUNT};
312                 const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
313                 const VkDevice                                  device                          = m_context.getDevice();
314                 const VkQueue                                   queue                           = m_context.getUniversalQueue();
315                 const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
316                 const Unique<VkCommandPool>             cmdPool                         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
317                 const Move<VkCommandBuffer>             ptrCmdBuffer[COUNT]     = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
318                 VkCommandBuffer                                 cmdBuffers[COUNT]       = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
319                 const SyncInfo                                  writeSync                       = m_writeOp->getSyncInfo();
320                 const SyncInfo                                  readSync                        = m_readOp->getSyncInfo();
321
322                 beginCommandBuffer(vk, cmdBuffers[WRITE]);
323
324                 m_writeOp->recordCommands(cmdBuffers[WRITE]);
325
326                 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
327                 {
328                         const VkImageMemoryBarrier barrier =  makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
329                                 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
330                         vk.cmdPipelineBarrier(cmdBuffers[WRITE],  writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
331                 }
332
333                 endCommandBuffer(vk, cmdBuffers[WRITE]);
334
335                 submitCommandsAndWait(vk, device, queue, cmdBuffers[WRITE]);
336
337                 beginCommandBuffer(vk, cmdBuffers[READ]);
338
339                 m_readOp->recordCommands(cmdBuffers[READ]);
340
341                 endCommandBuffer(vk, cmdBuffers[READ]);
342
343                 submitCommandsAndWait(vk, device, queue, cmdBuffers[READ]);
344
345                 {
346                         const Data      expected = m_writeOp->getData();
347                         const Data      actual   = m_readOp->getData();
348
349                         if (isIndirectBuffer(m_resource->getType()))
350                         {
351                                 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
352                                 const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
353
354                                 if (actualValue < expectedValue)
355                                         return tcu::TestStatus::fail("Counter value is smaller than expected");
356                         }
357                         else
358                         {
359                                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
360                                         return tcu::TestStatus::fail("Memory contents don't match");
361                         }
362                 }
363
364                 return tcu::TestStatus::pass("OK");
365         }
366 };
367
368 class SyncTestCase : public TestCase
369 {
370 public:
371         SyncTestCase    (tcu::TestContext&                      testCtx,
372                                          const std::string&                     name,
373                                          const std::string&                     description,
374                                          const SyncPrimitive            syncPrimitive,
375                                          const ResourceDescription      resourceDesc,
376                                          const OperationName            writeOp,
377                                          const OperationName            readOp,
378                                          PipelineCacheData&                     pipelineCacheData)
379                 : TestCase                              (testCtx, name, description)
380                 , m_resourceDesc                (resourceDesc)
381                 , m_writeOp                             (makeOperationSupport(writeOp, resourceDesc))
382                 , m_readOp                              (makeOperationSupport(readOp, resourceDesc))
383                 , m_syncPrimitive               (syncPrimitive)
384                 , m_pipelineCacheData   (pipelineCacheData)
385         {
386         }
387
388         void initPrograms (SourceCollections& programCollection) const
389         {
390                 m_writeOp->initPrograms(programCollection);
391                 m_readOp->initPrograms(programCollection);
392         }
393
394         TestInstance* createInstance (Context& context) const
395         {
396                 switch (m_syncPrimitive)
397                 {
398                         case SYNC_PRIMITIVE_FENCE:
399                                 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
400                         case SYNC_PRIMITIVE_SEMAPHORE:
401                                 return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
402                         case SYNC_PRIMITIVE_BARRIER:
403                                 return new BarrierTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
404                         case SYNC_PRIMITIVE_EVENT:
405                                 return new EventTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
406                 }
407
408                 DE_ASSERT(0);
409                 return DE_NULL;
410         }
411
412 private:
413         const ResourceDescription                               m_resourceDesc;
414         const de::UniquePtr<OperationSupport>   m_writeOp;
415         const de::UniquePtr<OperationSupport>   m_readOp;
416         const SyncPrimitive                                             m_syncPrimitive;
417         PipelineCacheData&                                              m_pipelineCacheData;
418 };
419
420 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
421 {
422         tcu::TestContext& testCtx = group->getTestContext();
423
424         static const struct
425         {
426                 const char*             name;
427                 SyncPrimitive   syncPrimitive;
428                 int                             numOptions;
429         } groups[] =
430         {
431                 { "fence",              SYNC_PRIMITIVE_FENCE,           0, },
432                 { "semaphore",  SYNC_PRIMITIVE_SEMAPHORE,       0, },
433                 { "barrier",    SYNC_PRIMITIVE_BARRIER,         1, },
434                 { "event",              SYNC_PRIMITIVE_EVENT,           1, },
435         };
436
437         for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
438         {
439                 de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
440
441                 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
442                 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
443                 {
444                         const OperationName     writeOp         = s_writeOps[writeOpNdx];
445                         const OperationName     readOp          = s_readOps[readOpNdx];
446                         const std::string       opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
447                         bool                            empty           = true;
448
449                         de::MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
450
451                         for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
452                         {
453                                 const ResourceDescription&      resource        = s_resources[resourceNdx];
454                                 std::string                                     name            = getResourceName(resource);
455
456                                 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
457                                 {
458                                         opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, *pipelineCacheData));
459                                         empty = false;
460                                 }
461                         }
462                         if (!empty)
463                                 synchGroup->addChild(opGroup.release());
464                 }
465
466                 group->addChild(synchGroup.release());
467         }
468 }
469
470 } // anonymous
471
472 tcu::TestCaseGroup* createSynchronizedOperationSingleQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
473 {
474         return createTestGroup(testCtx, "single_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
475 }
476
477 } // synchronization
478 } // vkt