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