• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*------------------------------------------------------------------------
3  * Vulkan Conformance Tests
4  * ------------------------
5  *
6  * Copyright (c) 2019 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Synchronization timeline semaphore tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktSynchronizationBasicSemaphoreTests.hpp"
26 #include "vktSynchronizationOperation.hpp"
27 #include "vktSynchronizationOperationTestData.hpp"
28 #include "vktSynchronizationOperationResources.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktSynchronizationUtil.hpp"
31 #include "vktExternalMemoryUtil.hpp"
32 #include "vktCustomInstancesDevices.hpp"
33 #include "vkBarrierUtil.hpp"
34 
35 #include "vkDefs.hpp"
36 #include "vkPlatform.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkRef.hpp"
42 #include "vkTypeUtil.hpp"
43 #include "vkBufferWithMemory.hpp"
44 #include "vkSafetyCriticalUtil.hpp"
45 
46 #include "tcuTestLog.hpp"
47 #include "tcuCommandLine.hpp"
48 
49 #include "deClock.h"
50 #include "deRandom.hpp"
51 #include "deThread.hpp"
52 #include "deUniquePtr.hpp"
53 
54 #include <limits>
55 #include <set>
56 #include <iterator>
57 #include <algorithm>
58 #include <sstream>
59 
60 namespace vkt
61 {
62 namespace synchronization
63 {
64 namespace
65 {
66 
67 using namespace vk;
68 using de::MovePtr;
69 using de::SharedPtr;
70 using tcu::TestLog;
71 
72 template <typename T>
makeVkSharedPtr(Move<T> move)73 inline SharedPtr<Move<T>> makeVkSharedPtr(Move<T> move)
74 {
75     return SharedPtr<Move<T>>(new Move<T>(move));
76 }
77 
78 template <typename T>
makeSharedPtr(de::MovePtr<T> move)79 inline SharedPtr<T> makeSharedPtr(de::MovePtr<T> move)
80 {
81     return SharedPtr<T>(move.release());
82 }
83 
84 template <typename T>
makeSharedPtr(T * ptr)85 inline SharedPtr<T> makeSharedPtr(T *ptr)
86 {
87     return SharedPtr<T>(ptr);
88 }
89 
getMaxTimelineSemaphoreValueDifference(const InstanceInterface & vk,const VkPhysicalDevice physicalDevice)90 uint64_t getMaxTimelineSemaphoreValueDifference(const InstanceInterface &vk, const VkPhysicalDevice physicalDevice)
91 {
92     VkPhysicalDeviceTimelineSemaphoreProperties timelineSemaphoreProperties;
93     VkPhysicalDeviceProperties2 properties;
94 
95     deMemset(&timelineSemaphoreProperties, 0, sizeof(timelineSemaphoreProperties));
96     timelineSemaphoreProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES;
97 
98     deMemset(&properties, 0, sizeof(properties));
99     properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
100     properties.pNext = &timelineSemaphoreProperties;
101 
102     vk.getPhysicalDeviceProperties2(physicalDevice, &properties);
103 
104     return timelineSemaphoreProperties.maxTimelineSemaphoreValueDifference;
105 }
106 
deviceSignal(const DeviceInterface & vk,const VkDevice device,const VkQueue queue,const VkFence fence,const SynchronizationType type,const VkSemaphore semaphore,const uint64_t timelineValue)107 void deviceSignal(const DeviceInterface &vk, const VkDevice device, const VkQueue queue, const VkFence fence,
108                   const SynchronizationType type, const VkSemaphore semaphore, const uint64_t timelineValue)
109 {
110     {
111         VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo =
112             makeCommonSemaphoreSubmitInfo(semaphore, timelineValue, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
113         SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(type, vk, true);
114         synchronizationWrapper->addSubmitInfo(
115             0u,                         // uint32_t                                waitSemaphoreInfoCount
116             nullptr,                    // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
117             0u,                         // uint32_t                                commandBufferInfoCount
118             nullptr,                    // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
119             1u,                         // uint32_t                                signalSemaphoreInfoCount
120             &signalSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
121             false, true);
122         VK_CHECK(synchronizationWrapper->queueSubmit(queue, VK_NULL_HANDLE));
123     }
124 
125     if (fence != VK_NULL_HANDLE)
126     {
127         SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(type, vk, 1u);
128         synchronizationWrapper->addSubmitInfo(0u,      // uint32_t                                waitSemaphoreInfoCount
129                                               nullptr, // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
130                                               0u,      // uint32_t                                commandBufferInfoCount
131                                               nullptr, // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
132                                               0u, // uint32_t                                signalSemaphoreInfoCount
133                                               nullptr // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
134         );
135         VK_CHECK(synchronizationWrapper->queueSubmit(queue, fence));
136         VK_CHECK(vk.waitForFences(device, 1u, &fence, VK_TRUE, ~(0ull)));
137     }
138 }
139 
hostSignal(const DeviceInterface & vk,const VkDevice & device,VkSemaphore semaphore,const uint64_t timelineValue)140 void hostSignal(const DeviceInterface &vk, const VkDevice &device, VkSemaphore semaphore, const uint64_t timelineValue)
141 {
142     VkSemaphoreSignalInfo ssi = {
143         VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, // VkStructureType sType;
144         nullptr,                                 // const void* pNext;
145         semaphore,                               // VkSemaphore semaphore;
146         timelineValue,                           // uint64_t value;
147     };
148 
149     VK_CHECK(vk.signalSemaphore(device, &ssi));
150 }
151 
152 class WaitTestInstance : public TestInstance
153 {
154 public:
WaitTestInstance(Context & context,SynchronizationType type,bool waitAll,bool signalFromDevice)155     WaitTestInstance(Context &context, SynchronizationType type, bool waitAll, bool signalFromDevice)
156         : TestInstance(context)
157         , m_type(type)
158         , m_waitAll(waitAll)
159         , m_signalFromDevice(signalFromDevice)
160     {
161     }
162 
iterate(void)163     tcu::TestStatus iterate(void)
164     {
165         const DeviceInterface &vk = m_context.getDeviceInterface();
166         const VkDevice &device    = m_context.getDevice();
167         const VkQueue queue       = m_context.getUniversalQueue();
168         Unique<VkFence> fence(createFence(vk, device));
169         std::vector<SharedPtr<Move<VkSemaphore>>> semaphorePtrs(createTimelineSemaphores(vk, device, 100));
170         de::Random rng(1234);
171         std::vector<VkSemaphore> semaphores;
172         std::vector<uint64_t> timelineValues;
173 
174         for (uint32_t i = 0; i < semaphorePtrs.size(); i++)
175         {
176             semaphores.push_back((*semaphorePtrs[i]).get());
177             timelineValues.push_back(rng.getInt(1, 10000));
178         }
179 
180         if (m_waitAll)
181         {
182 
183             for (uint32_t semIdx = 0; semIdx < semaphores.size(); semIdx++)
184             {
185                 if (m_signalFromDevice)
186                 {
187                     deviceSignal(vk, device, queue, *fence, m_type, semaphores[semIdx], timelineValues[semIdx]);
188                     VK_CHECK(vk.resetFences(device, 1, &fence.get()));
189                 }
190                 else
191                     hostSignal(vk, device, semaphores[semIdx], timelineValues[semIdx]);
192             }
193         }
194         else
195         {
196             uint32_t randomIdx = rng.getInt(0, (uint32_t)(semaphores.size() - 1));
197 
198             if (m_signalFromDevice)
199                 deviceSignal(vk, device, queue, *fence, m_type, semaphores[randomIdx], timelineValues[randomIdx]);
200             else
201                 hostSignal(vk, device, semaphores[randomIdx], timelineValues[randomIdx]);
202         }
203 
204         {
205             const VkSemaphoreWaitInfo waitInfo = {
206                 VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,                            // VkStructureType sType;
207                 nullptr,                                                          // const void* pNext;
208                 m_waitAll ? 0u : (VkSemaphoreWaitFlags)VK_SEMAPHORE_WAIT_ANY_BIT, // VkSemaphoreWaitFlagsKHR flags;
209                 (uint32_t)semaphores.size(),                                      // uint32_t semaphoreCount;
210                 &semaphores[0],                                                   // const VkSemaphore* pSemaphores;
211                 &timelineValues[0],                                               // const uint64_t* pValues;
212             };
213 
214             VkResult result = vk.waitSemaphores(device, &waitInfo, 0ull);
215             if (result != VK_SUCCESS)
216                 return tcu::TestStatus::fail("Wait failed");
217         }
218 
219         VK_CHECK(vk.deviceWaitIdle(device));
220 
221         return tcu::TestStatus::pass("Wait success");
222     }
223 
224 private:
createTimelineSemaphores(const DeviceInterface & vk,const VkDevice & device,uint32_t count)225     std::vector<SharedPtr<Move<VkSemaphore>>> createTimelineSemaphores(const DeviceInterface &vk,
226                                                                        const VkDevice &device, uint32_t count)
227     {
228         std::vector<SharedPtr<Move<VkSemaphore>>> semaphores;
229 
230         for (uint32_t i = 0; i < count; i++)
231             semaphores.push_back(makeVkSharedPtr(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE)));
232 
233         return semaphores;
234     }
235 
236     const SynchronizationType m_type;
237     bool m_waitAll;
238     bool m_signalFromDevice;
239 };
240 
241 class WaitTestCase : public TestCase
242 {
243 public:
WaitTestCase(tcu::TestContext & testCtx,const std::string & name,SynchronizationType type,bool waitAll,bool signalFromDevice)244     WaitTestCase(tcu::TestContext &testCtx, const std::string &name, SynchronizationType type, bool waitAll,
245                  bool signalFromDevice)
246         : TestCase(testCtx, name.c_str())
247         , m_type(type)
248         , m_waitAll(waitAll)
249         , m_signalFromDevice(signalFromDevice)
250     {
251     }
252 
checkSupport(Context & context) const253     void checkSupport(Context &context) const override
254     {
255         context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
256         if (m_type == SynchronizationType::SYNCHRONIZATION2)
257             context.requireDeviceFunctionality("VK_KHR_synchronization2");
258     }
259 
createInstance(Context & context) const260     TestInstance *createInstance(Context &context) const override
261     {
262         return new WaitTestInstance(context, m_type, m_waitAll, m_signalFromDevice);
263     }
264 
265 private:
266     const SynchronizationType m_type;
267     bool m_waitAll;
268     bool m_signalFromDevice;
269 };
270 
271 // This test verifies that waiting from the host on a timeline point
272 // that is itself waiting for signaling works properly.
273 class HostWaitBeforeSignalTestInstance : public TestInstance
274 {
275 public:
HostWaitBeforeSignalTestInstance(Context & context,SynchronizationType type)276     HostWaitBeforeSignalTestInstance(Context &context, SynchronizationType type) : TestInstance(context), m_type(type)
277     {
278     }
279 
iterate(void)280     tcu::TestStatus iterate(void)
281     {
282         const DeviceInterface &vk = m_context.getDeviceInterface();
283         const VkDevice &device    = m_context.getDevice();
284         const VkQueue queue       = m_context.getUniversalQueue();
285         Unique<VkSemaphore> semaphore(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE));
286         de::Random rng(1234);
287         std::vector<uint64_t> timelineValues;
288 
289         // Host value we signal at the end.
290         timelineValues.push_back(1 + rng.getInt(1, 10000));
291 
292         for (uint32_t i = 0; i < 12; i++)
293         {
294             const uint64_t newTimelineValue                  = (timelineValues.back() + rng.getInt(1, 10000));
295             VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(
296                 *semaphore, timelineValues.back(), VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
297             VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo =
298                 makeCommonSemaphoreSubmitInfo(*semaphore, newTimelineValue, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
299             SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_type, vk, true);
300 
301             synchronizationWrapper->addSubmitInfo(
302                 1u,                         // uint32_t                                waitSemaphoreInfoCount
303                 &waitSemaphoreSubmitInfo,   // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
304                 0u,                         // uint32_t                                commandBufferInfoCount
305                 nullptr,                    // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
306                 1u,                         // uint32_t                                signalSemaphoreInfoCount
307                 &signalSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
308                 true, true);
309 
310             VK_CHECK(synchronizationWrapper->queueSubmit(queue, VK_NULL_HANDLE));
311 
312             timelineValues.push_back(newTimelineValue);
313         }
314 
315         {
316             const VkSemaphoreWaitInfo waitInfo = {
317                 VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
318                 nullptr,                               // const void* pNext;
319                 0u,                                    // VkSemaphoreWaitFlagsKHR flags;
320                 (uint32_t)1u,                          // uint32_t semaphoreCount;
321                 &semaphore.get(),                      // const VkSemaphore* pSemaphores;
322                 &timelineValues[rng.getInt(0, static_cast<int>(timelineValues.size() - 1))], // const uint64_t* pValues;
323             };
324 
325             VkResult result = vk.waitSemaphores(device, &waitInfo, 0ull);
326             if (result != VK_TIMEOUT)
327                 return tcu::TestStatus::fail("Wait failed");
328         }
329 
330         hostSignal(vk, device, *semaphore, timelineValues.front());
331 
332         {
333             const VkSemaphoreWaitInfo waitInfo = {
334                 VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
335                 nullptr,                               // const void* pNext;
336                 0u,                                    // VkSemaphoreWaitFlagsKHR flags;
337                 (uint32_t)1u,                          // uint32_t semaphoreCount;
338                 &semaphore.get(),                      // const VkSemaphore* pSemaphores;
339                 &timelineValues.back(),                // const uint64_t* pValues;
340             };
341 
342             VkResult result = vk.waitSemaphores(device, &waitInfo, ~(0ull));
343             if (result != VK_SUCCESS)
344                 return tcu::TestStatus::fail("Wait failed");
345         }
346 
347         VK_CHECK(vk.deviceWaitIdle(device));
348 
349         return tcu::TestStatus::pass("Wait success");
350     }
351 
352 private:
createTimelineSemaphores(const DeviceInterface & vk,const VkDevice & device,uint32_t count)353     std::vector<SharedPtr<Move<VkSemaphore>>> createTimelineSemaphores(const DeviceInterface &vk,
354                                                                        const VkDevice &device, uint32_t count)
355     {
356         std::vector<SharedPtr<Move<VkSemaphore>>> semaphores;
357 
358         for (uint32_t i = 0; i < count; i++)
359             semaphores.push_back(makeVkSharedPtr(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE)));
360 
361         return semaphores;
362     }
363 
364 protected:
365     const SynchronizationType m_type;
366 };
367 
368 class HostWaitBeforeSignalTestCase : public TestCase
369 {
370 public:
HostWaitBeforeSignalTestCase(tcu::TestContext & testCtx,const std::string & name,SynchronizationType type)371     HostWaitBeforeSignalTestCase(tcu::TestContext &testCtx, const std::string &name, SynchronizationType type)
372         : TestCase(testCtx, name.c_str())
373         , m_type(type)
374     {
375     }
376 
checkSupport(Context & context) const377     void checkSupport(Context &context) const override
378     {
379         context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
380         if (m_type == SynchronizationType::SYNCHRONIZATION2)
381             context.requireDeviceFunctionality("VK_KHR_synchronization2");
382     }
383 
createInstance(Context & context) const384     TestInstance *createInstance(Context &context) const override
385     {
386         return new HostWaitBeforeSignalTestInstance(context, m_type);
387     }
388 
389 protected:
390     const SynchronizationType m_type;
391 };
392 
393 class PollTestInstance : public TestInstance
394 {
395 public:
PollTestInstance(Context & context,bool signalFromDevice)396     PollTestInstance(Context &context, bool signalFromDevice)
397         : TestInstance(context)
398         , m_signalFromDevice(signalFromDevice)
399     {
400     }
401 
iterate(void)402     tcu::TestStatus iterate(void)
403     {
404         const DeviceInterface &vk = m_context.getDeviceInterface();
405         const VkDevice &device    = m_context.getDevice();
406         const VkQueue queue       = m_context.getUniversalQueue();
407         Unique<VkFence> fence(createFence(vk, device));
408         std::vector<SharedPtr<Move<VkSemaphore>>> semaphorePtrs(createTimelineSemaphores(vk, device, 100));
409         de::Random rng(1234);
410         std::vector<VkSemaphore> semaphores;
411         std::vector<uint64_t> timelineValues;
412         const uint64_t secondInMicroSeconds = 1000ull * 1000ull * 1000ull;
413         uint64_t startTime;
414         VkResult result = VK_SUCCESS;
415 
416         for (uint32_t i = 0; i < semaphorePtrs.size(); i++)
417         {
418             semaphores.push_back((*semaphorePtrs[i]).get());
419             timelineValues.push_back(rng.getInt(1, 10000));
420         }
421 
422         for (uint32_t semIdx = 0; semIdx < semaphores.size(); semIdx++)
423         {
424             if (m_signalFromDevice)
425             {
426                 deviceSignal(vk, device, queue, semIdx == (semaphores.size() - 1) ? *fence : VK_NULL_HANDLE,
427                              SynchronizationType::LEGACY, semaphores[semIdx], timelineValues[semIdx]);
428             }
429             else
430                 hostSignal(vk, device, semaphores[semIdx], timelineValues[semIdx]);
431         }
432 
433         startTime = deGetMicroseconds();
434 
435         do
436         {
437             uint64_t value;
438 
439             result = vk.getSemaphoreCounterValue(device, semaphores.back(), &value);
440 
441             if (result != VK_SUCCESS)
442                 break;
443 
444             if (value == timelineValues.back())
445             {
446                 if (m_signalFromDevice)
447                     VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), VK_TRUE, ~(0ull)));
448                 VK_CHECK(vk.deviceWaitIdle(device));
449                 return tcu::TestStatus::pass("Poll on timeline value succeeded");
450             }
451 
452             if (value > timelineValues.back())
453             {
454                 result = VK_ERROR_UNKNOWN;
455                 break;
456             }
457         } while ((deGetMicroseconds() - startTime) < secondInMicroSeconds);
458 
459         VK_CHECK(vk.deviceWaitIdle(device));
460 
461         if (result != VK_SUCCESS)
462             return tcu::TestStatus::fail("Fail");
463         return tcu::TestStatus::fail("Timeout");
464     }
465 
466 private:
createTimelineSemaphores(const DeviceInterface & vk,const VkDevice & device,uint32_t count)467     std::vector<SharedPtr<Move<VkSemaphore>>> createTimelineSemaphores(const DeviceInterface &vk,
468                                                                        const VkDevice &device, uint32_t count)
469     {
470         std::vector<SharedPtr<Move<VkSemaphore>>> semaphores;
471 
472         for (uint32_t i = 0; i < count; i++)
473             semaphores.push_back(makeVkSharedPtr(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE)));
474 
475         return semaphores;
476     }
477 
478     bool m_signalFromDevice;
479 };
480 
481 class PollTestCase : public TestCase
482 {
483 public:
PollTestCase(tcu::TestContext & testCtx,const std::string & name,bool signalFromDevice)484     PollTestCase(tcu::TestContext &testCtx, const std::string &name, bool signalFromDevice)
485         : TestCase(testCtx, name.c_str())
486         , m_signalFromDevice(signalFromDevice)
487     {
488     }
489 
checkSupport(Context & context) const490     virtual void checkSupport(Context &context) const
491     {
492         context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
493     }
494 
createInstance(Context & context) const495     TestInstance *createInstance(Context &context) const
496     {
497         return new PollTestInstance(context, m_signalFromDevice);
498     }
499 
500 private:
501     bool m_signalFromDevice;
502 };
503 
504 class MonotonicallyIncrementChecker : public de::Thread
505 {
506 public:
MonotonicallyIncrementChecker(const DeviceInterface & vkd,VkDevice device,VkSemaphore semaphore)507     MonotonicallyIncrementChecker(const DeviceInterface &vkd, VkDevice device, VkSemaphore semaphore)
508         : de::Thread()
509         , m_vkd(vkd)
510         , m_device(device)
511         , m_semaphore(semaphore)
512         , m_running(true)
513         , m_status(tcu::TestStatus::incomplete())
514     {
515     }
516 
~MonotonicallyIncrementChecker(void)517     virtual ~MonotonicallyIncrementChecker(void)
518     {
519     }
520 
getStatus()521     tcu::TestStatus getStatus()
522     {
523         return m_status;
524     }
stop()525     void stop()
526     {
527         m_running = false;
528     }
run()529     virtual void run()
530     {
531         uint64_t lastValue = 0;
532 
533         while (m_running)
534         {
535             uint64_t value;
536 
537             VK_CHECK(m_vkd.getSemaphoreCounterValue(m_device, m_semaphore, &value));
538 
539             if (value < lastValue)
540             {
541                 m_status = tcu::TestStatus::fail("Value not monotonically increasing");
542                 return;
543             }
544 
545             lastValue = value;
546             deYield();
547         }
548 
549         m_status = tcu::TestStatus::pass("Value monotonically increasing");
550     }
551 
552 private:
553     const DeviceInterface &m_vkd;
554     VkDevice m_device;
555     VkSemaphore m_semaphore;
556     bool m_running;
557     tcu::TestStatus m_status;
558 };
559 
checkSupport(Context & context,SynchronizationType type)560 void checkSupport(Context &context, SynchronizationType type)
561 {
562     context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
563     if (type == SynchronizationType::SYNCHRONIZATION2)
564         context.requireDeviceFunctionality("VK_KHR_synchronization2");
565 }
566 
567 // Queue device signaling close to the edges of the
568 // maxTimelineSemaphoreValueDifference value and verify that the value
569 // of the semaphore never goes backwards.
maxDifferenceValueCase(Context & context,SynchronizationType type)570 tcu::TestStatus maxDifferenceValueCase(Context &context, SynchronizationType type)
571 {
572     const DeviceInterface &vk                 = context.getDeviceInterface();
573     const VkDevice &device                    = context.getDevice();
574     const VkQueue queue                       = context.getUniversalQueue();
575     const uint64_t requiredMinValueDifference = deIntMaxValue32(32);
576     const uint64_t maxTimelineValueDifference =
577         getMaxTimelineSemaphoreValueDifference(context.getInstanceInterface(), context.getPhysicalDevice());
578     const Unique<VkSemaphore> semaphore(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE));
579     const Unique<VkFence> fence(createFence(vk, device));
580     tcu::TestLog &log = context.getTestContext().getLog();
581     MonotonicallyIncrementChecker checkerThread(vk, device, *semaphore);
582     uint64_t iterations;
583     uint64_t timelineBackValue;
584     uint64_t timelineFrontValue;
585 
586     if (maxTimelineValueDifference < requiredMinValueDifference)
587         return tcu::TestStatus::fail("Timeline semaphore max value difference test failed");
588 
589     iterations = std::min<uint64_t>(std::numeric_limits<uint64_t>::max() / maxTimelineValueDifference, 100ull);
590 
591     log << TestLog::Message << " maxTimelineSemaphoreValueDifference=" << maxTimelineValueDifference
592         << " maxExpected=" << requiredMinValueDifference << " iterations=" << iterations << TestLog::EndMessage;
593 
594     checkerThread.start();
595 
596     timelineBackValue = timelineFrontValue = 1;
597     hostSignal(vk, device, *semaphore, timelineFrontValue);
598 
599     for (uint64_t i = 0; i < iterations; i++)
600     {
601         uint64_t fenceValue;
602 
603         for (uint32_t j = 1; j <= 10; j++)
604             deviceSignal(vk, device, queue, VK_NULL_HANDLE, type, *semaphore, ++timelineFrontValue);
605 
606         timelineFrontValue = timelineBackValue + maxTimelineValueDifference - 10;
607         fenceValue         = timelineFrontValue;
608         deviceSignal(vk, device, queue, *fence, type, *semaphore, fenceValue);
609         for (uint32_t j = 1; j < 10; j++)
610             deviceSignal(vk, device, queue, VK_NULL_HANDLE, type, *semaphore, ++timelineFrontValue);
611 
612         uint64_t value;
613         VK_CHECK(vk.getSemaphoreCounterValue(device, *semaphore, &value));
614 
615         VK_CHECK(vk.waitForFences(device, 1, &fence.get(), VK_TRUE, ~(0ull)));
616         VK_CHECK(vk.resetFences(device, 1, &fence.get()));
617 
618         timelineBackValue = fenceValue;
619     }
620 
621     VK_CHECK(vk.deviceWaitIdle(device));
622 
623     checkerThread.stop();
624     checkerThread.join();
625 
626     return checkerThread.getStatus();
627 }
628 
initialValueCase(Context & context,SynchronizationType type)629 tcu::TestStatus initialValueCase(Context &context, SynchronizationType type)
630 {
631     DE_UNREF(type);
632 
633     const DeviceInterface &vk = context.getDeviceInterface();
634     const VkDevice &device    = context.getDevice();
635     const VkQueue queue       = context.getUniversalQueue();
636     const uint64_t maxTimelineValueDifference =
637         getMaxTimelineSemaphoreValueDifference(context.getInstanceInterface(), context.getPhysicalDevice());
638     de::Random rng(1234);
639     const uint64_t nonZeroValue = 1 + rng.getUint64() % (maxTimelineValueDifference - 1);
640     const Unique<VkSemaphore> semaphoreDefaultValue(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE));
641     const Unique<VkSemaphore> semaphoreInitialValue(
642         createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE, 0, nonZeroValue));
643     uint64_t initialValue;
644     VkSemaphoreWaitInfo waitInfo = {
645         VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
646         nullptr,                               // const void* pNext;
647         0u,                                    // VkSemaphoreWaitFlagsKHR flags;
648         1u,                                    // uint32_t semaphoreCount;
649         nullptr,                               // const VkSemaphore* pSemaphores;
650         &initialValue,                         // const uint64_t* pValues;
651     };
652     uint64_t value;
653     VkResult result;
654 
655     waitInfo.pSemaphores = &semaphoreDefaultValue.get();
656     initialValue         = 0;
657     result               = vk.waitSemaphores(device, &waitInfo, 0ull);
658     if (result != VK_SUCCESS)
659         return tcu::TestStatus::fail("Wait zero initial value failed");
660 
661     {
662         VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(
663             *semaphoreDefaultValue, initialValue, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
664         SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(type, vk, true);
665 
666         synchronizationWrapper->addSubmitInfo(
667             1u,                       // uint32_t                                waitSemaphoreInfoCount
668             &waitSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
669             0u,                       // uint32_t                                commandBufferInfoCount
670             nullptr,                  // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
671             0u,                       // uint32_t                                signalSemaphoreInfoCount
672             nullptr,                  // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
673             true, false);
674 
675         VK_CHECK(synchronizationWrapper->queueSubmit(queue, VK_NULL_HANDLE));
676 
677         VK_CHECK(vk.deviceWaitIdle(device));
678     }
679 
680     VK_CHECK(vk.getSemaphoreCounterValue(device, *semaphoreDefaultValue, &value));
681 #ifdef CTS_USES_VULKANSC
682     if (context.getTestContext().getCommandLine().isSubProcess())
683 #endif // CTS_USES_VULKANSC
684     {
685         if (value != initialValue)
686             return tcu::TestStatus::fail("Invalid zero initial value");
687     }
688 
689     waitInfo.pSemaphores = &semaphoreInitialValue.get();
690     initialValue         = nonZeroValue;
691     result               = vk.waitSemaphores(device, &waitInfo, 0ull);
692     if (result != VK_SUCCESS)
693         return tcu::TestStatus::fail("Wait non zero initial value failed");
694 
695     VK_CHECK(vk.getSemaphoreCounterValue(device, *semaphoreInitialValue, &value));
696 #ifdef CTS_USES_VULKANSC
697     if (context.getTestContext().getCommandLine().isSubProcess())
698 #endif // CTS_USES_VULKANSC
699     {
700         if (value != nonZeroValue)
701             return tcu::TestStatus::fail("Invalid non zero initial value");
702     }
703 
704     if (maxTimelineValueDifference != std::numeric_limits<uint64_t>::max())
705     {
706         const uint64_t nonZeroMaxValue = maxTimelineValueDifference + 1;
707         const Unique<VkSemaphore> semaphoreMaxValue(
708             createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE, 0, nonZeroMaxValue));
709 
710         waitInfo.pSemaphores = &semaphoreMaxValue.get();
711         initialValue         = nonZeroMaxValue;
712         result               = vk.waitSemaphores(device, &waitInfo, 0ull);
713         if (result != VK_SUCCESS)
714             return tcu::TestStatus::fail("Wait max value failed");
715 
716         VK_CHECK(vk.getSemaphoreCounterValue(device, *semaphoreMaxValue, &value));
717 #ifdef CTS_USES_VULKANSC
718         if (context.getTestContext().getCommandLine().isSubProcess())
719 #endif // CTS_USES_VULKANSC
720         {
721             if (value != nonZeroMaxValue)
722                 return tcu::TestStatus::fail("Invalid max value initial value");
723         }
724     }
725 
726     return tcu::TestStatus::pass("Initial value correct");
727 }
728 
729 class WaitTests : public tcu::TestCaseGroup
730 {
731 public:
732     // Various wait cases of timeline semaphores
WaitTests(tcu::TestContext & testCtx,SynchronizationType type)733     WaitTests(tcu::TestContext &testCtx, SynchronizationType type) : tcu::TestCaseGroup(testCtx, "wait"), m_type(type)
734     {
735     }
736 
init(void)737     void init(void)
738     {
739         static const struct
740         {
741             std::string name;
742             bool waitAll;
743             bool signalFromDevice;
744         } waitCases[] = {
745             {"all_signal_from_device", true, true},
746             {"one_signal_from_device", false, true},
747             {"all_signal_from_host", true, false},
748             {"one_signal_from_host", false, false},
749         };
750 
751         for (uint32_t caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(waitCases); caseIdx++)
752             addChild(new WaitTestCase(m_testCtx, waitCases[caseIdx].name, m_type, waitCases[caseIdx].waitAll,
753                                       waitCases[caseIdx].signalFromDevice));
754         addChild(new HostWaitBeforeSignalTestCase(m_testCtx, "host_wait_before_signal", m_type));
755         addChild(new PollTestCase(m_testCtx, "poll_signal_from_device", true));
756         addChild(new PollTestCase(m_testCtx, "poll_signal_from_host", false));
757     }
758 
759 protected:
760     SynchronizationType m_type;
761 };
762 
763 struct TimelineIteration
764 {
TimelineIterationvkt::synchronization::__anoncf99eb0b0111::TimelineIteration765     TimelineIteration(OperationContext &opContext, const ResourceDescription &resourceDesc,
766                       const SharedPtr<OperationSupport> &writeOpSupport,
767                       const SharedPtr<OperationSupport> &readOpSupport, uint64_t lastValue, de::Random &rng)
768         : resource(makeSharedPtr(
769               new Resource(opContext, resourceDesc,
770                            writeOpSupport->getOutResourceUsageFlags() | readOpSupport->getInResourceUsageFlags())))
771         , writeOp(makeSharedPtr(writeOpSupport->build(opContext, *resource)))
772         , readOp(makeSharedPtr(readOpSupport->build(opContext, *resource)))
773     {
774         writeValue = lastValue + rng.getInt(1, 100);
775         readValue  = writeValue + rng.getInt(1, 100);
776         cpuValue   = readValue + rng.getInt(1, 100);
777     }
~TimelineIterationvkt::synchronization::__anoncf99eb0b0111::TimelineIteration778     ~TimelineIteration()
779     {
780     }
781 
782     SharedPtr<Resource> resource;
783 
784     SharedPtr<Operation> writeOp;
785     SharedPtr<Operation> readOp;
786 
787     uint64_t writeValue;
788     uint64_t readValue;
789     uint64_t cpuValue;
790 };
791 
792 class HostCopyThread : public de::Thread
793 {
794 public:
HostCopyThread(const DeviceInterface & vkd,VkDevice device,VkSemaphore semaphore,const std::vector<SharedPtr<TimelineIteration>> & iterations)795     HostCopyThread(const DeviceInterface &vkd, VkDevice device, VkSemaphore semaphore,
796                    const std::vector<SharedPtr<TimelineIteration>> &iterations)
797         : de::Thread()
798         , m_vkd(vkd)
799         , m_device(device)
800         , m_semaphore(semaphore)
801         , m_iterations(iterations)
802     {
803     }
~HostCopyThread(void)804     virtual ~HostCopyThread(void)
805     {
806     }
807 
run()808     virtual void run()
809     {
810         for (uint32_t iterIdx = 0; iterIdx < m_iterations.size(); iterIdx++)
811         {
812             // Wait on the GPU read operation.
813             {
814                 const VkSemaphoreWaitInfo waitInfo = {
815                     VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
816                     nullptr,                               // const void* pNext;
817                     0u,                                    // VkSemaphoreWaitFlagsKHR flags;
818                     1u,                                    // uint32_t                    semaphoreCount
819                     &m_semaphore,                          // VkSemaphore* pSemaphores;
820                     &m_iterations[iterIdx]->readValue,     // uint64_t* pValues;
821                 };
822                 VkResult result;
823 
824                 result = m_vkd.waitSemaphores(m_device, &waitInfo, ~(uint64_t)0u);
825                 if (result != VK_SUCCESS)
826                     return;
827             }
828 
829             // Copy the data read on the GPU into the next GPU write operation.
830             if (iterIdx < (m_iterations.size() - 1))
831                 m_iterations[iterIdx + 1]->writeOp->setData(m_iterations[iterIdx]->readOp->getData());
832 
833             // Signal the next GPU write operation.
834             {
835                 const VkSemaphoreSignalInfo signalInfo = {
836                     VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, // VkStructureType sType;
837                     nullptr,                                 // const void* pNext;
838                     m_semaphore,                             // VkSemaphore semaphore;
839                     m_iterations[iterIdx]->cpuValue,         // uint64_t value;
840                 };
841                 VkResult result;
842 
843                 result = m_vkd.signalSemaphore(m_device, &signalInfo);
844                 if (result != VK_SUCCESS)
845                     return;
846             }
847         }
848     }
849 
850 private:
851     const DeviceInterface &m_vkd;
852     VkDevice m_device;
853     VkSemaphore m_semaphore;
854     const std::vector<SharedPtr<TimelineIteration>> &m_iterations;
855 };
856 
randomizeData(std::vector<uint8_t> & outData,const ResourceDescription & desc)857 void randomizeData(std::vector<uint8_t> &outData, const ResourceDescription &desc)
858 {
859     de::Random rng(1234);
860 
861     if (desc.type == RESOURCE_TYPE_BUFFER)
862     {
863         for (uint32_t i = 0; i < outData.size(); i++)
864             outData[i] = rng.getUint8();
865     }
866     else
867     {
868         const PlanarFormatDescription planeDesc = getPlanarFormatDescription(desc.imageFormat);
869         tcu::PixelBufferAccess access(mapVkFormat(desc.imageFormat), desc.size.x(), desc.size.y(), desc.size.z(),
870                                       static_cast<void *>(&outData[0]));
871 
872         DE_ASSERT(desc.type == RESOURCE_TYPE_IMAGE);
873 
874         for (int z = 0; z < access.getDepth(); z++)
875         {
876             for (int y = 0; y < access.getHeight(); y++)
877             {
878                 for (int x = 0; x < access.getWidth(); x++)
879                 {
880                     if (isFloatFormat(desc.imageFormat))
881                     {
882                         tcu::Vec4 value(rng.getFloat(), rng.getFloat(), rng.getFloat(), 1.0f);
883                         access.setPixel(value, x, y, z);
884                     }
885                     else
886                     {
887                         tcu::IVec4 value(rng.getInt(0, deIntMaxValue32(planeDesc.channels[0].sizeBits)),
888                                          rng.getInt(0, deIntMaxValue32(planeDesc.channels[1].sizeBits)),
889                                          rng.getInt(0, deIntMaxValue32(planeDesc.channels[2].sizeBits)),
890                                          rng.getInt(0, deIntMaxValue32(planeDesc.channels[3].sizeBits)));
891                         access.setPixel(value, x, y, z);
892                     }
893                 }
894             }
895         }
896     }
897 }
898 
899 // Create a chain of operations with data copied over on the device
900 // and the host with each operation depending on the previous one and
901 // verifies that the data at the beginning & end of the chain is the
902 // same.
903 class DeviceHostTestInstance : public TestInstance
904 {
905 public:
DeviceHostTestInstance(Context & context,SynchronizationType type,const ResourceDescription & resourceDesc,const SharedPtr<OperationSupport> & writeOp,const SharedPtr<OperationSupport> & readOp,PipelineCacheData & pipelineCacheData)906     DeviceHostTestInstance(Context &context, SynchronizationType type, const ResourceDescription &resourceDesc,
907                            const SharedPtr<OperationSupport> &writeOp, const SharedPtr<OperationSupport> &readOp,
908                            PipelineCacheData &pipelineCacheData)
909         : TestInstance(context)
910         , m_type(type)
911         , m_opContext(context, type, pipelineCacheData)
912         , m_resourceDesc(resourceDesc)
913     {
914         de::Random rng(1234);
915 
916         // Create a dozen couple of operations and their associated
917         // resource.
918         for (uint32_t i = 0; i < 12; i++)
919         {
920             m_iterations.push_back(makeSharedPtr(new TimelineIteration(
921                 m_opContext, resourceDesc, writeOp, readOp, i == 0 ? 0 : m_iterations.back()->cpuValue, rng)));
922         }
923     }
924 
iterate(void)925     tcu::TestStatus iterate(void)
926     {
927         const DeviceInterface &vk       = m_context.getDeviceInterface();
928         const VkDevice device           = m_context.getDevice();
929         const VkQueue queue             = m_context.getUniversalQueue();
930         const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
931         const Unique<VkSemaphore> semaphore(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE));
932         const Unique<VkCommandPool> cmdPool(
933             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
934         HostCopyThread hostCopyThread(vk, device, *semaphore, m_iterations);
935         std::vector<SharedPtr<Move<VkCommandBuffer>>> ptrCmdBuffers;
936         std::vector<VkCommandBufferSubmitInfoKHR> commandBufferSubmitInfos(m_iterations.size() * 2,
937                                                                            makeCommonCommandBufferSubmitInfo(0));
938 
939         hostCopyThread.start();
940 
941         for (uint32_t opNdx = 0; opNdx < (m_iterations.size() * 2); opNdx++)
942         {
943             ptrCmdBuffers.push_back(makeVkSharedPtr(makeCommandBuffer(vk, device, *cmdPool)));
944             commandBufferSubmitInfos[opNdx].commandBuffer = **(ptrCmdBuffers.back());
945         }
946 
947         // Randomize the data copied over.
948         {
949             const Data startData = m_iterations.front()->writeOp->getData();
950             Data randomizedData;
951             std::vector<uint8_t> dataArray;
952 
953             dataArray.resize(startData.size);
954             randomizeData(dataArray, m_resourceDesc);
955             randomizedData.size = dataArray.size();
956             randomizedData.data = &dataArray[0];
957             m_iterations.front()->writeOp->setData(randomizedData);
958         }
959 
960         SynchronizationWrapperPtr synchronizationWrapper =
961             getSynchronizationWrapper(m_type, vk, true, (uint32_t)m_iterations.size() * 2u);
962         std::vector<VkSemaphoreSubmitInfoKHR> waitSemaphoreSubmitInfos(
963             m_iterations.size() * 2,
964             makeCommonSemaphoreSubmitInfo(*semaphore, 0u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR));
965         std::vector<VkSemaphoreSubmitInfoKHR> signalSemaphoreSubmitInfos(
966             m_iterations.size() * 2,
967             makeCommonSemaphoreSubmitInfo(*semaphore, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR));
968 
969         for (uint32_t iterIdx = 0; iterIdx < m_iterations.size(); iterIdx++)
970         {
971             // Write operation
972             {
973                 uint32_t wIdx = 2 * iterIdx;
974 
975                 waitSemaphoreSubmitInfos[wIdx].value   = wIdx == 0 ? 0u : m_iterations[iterIdx - 1]->cpuValue;
976                 signalSemaphoreSubmitInfos[wIdx].value = m_iterations[iterIdx]->writeValue;
977 
978                 synchronizationWrapper->addSubmitInfo(
979                     wIdx == 0 ? 0u : 1u,             // uint32_t                                waitSemaphoreInfoCount
980                     &waitSemaphoreSubmitInfos[wIdx], // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
981                     1u,                              // uint32_t                                commandBufferInfoCount
982                     &commandBufferSubmitInfos[wIdx], // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
983                     1u,                              // uint32_t                                signalSemaphoreInfoCount
984                     &signalSemaphoreSubmitInfos[wIdx], // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
985                     wIdx == 0 ? false : true, true);
986 
987                 VkCommandBuffer cmdBuffer = commandBufferSubmitInfos[wIdx].commandBuffer;
988                 beginCommandBuffer(vk, cmdBuffer);
989                 m_iterations[iterIdx]->writeOp->recordCommands(cmdBuffer);
990 
991                 {
992                     const SyncInfo writeSync = m_iterations[iterIdx]->writeOp->getOutSyncInfo();
993                     const SyncInfo readSync  = m_iterations[iterIdx]->readOp->getInSyncInfo();
994                     const Resource &resource = *(m_iterations[iterIdx]->resource);
995 
996                     if (resource.getType() == RESOURCE_TYPE_IMAGE)
997                     {
998                         DE_ASSERT(writeSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
999                         DE_ASSERT(readSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
1000 
1001                         const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
1002                             writeSync.stageMask,                 // VkPipelineStageFlags2KHR            srcStageMask
1003                             writeSync.accessMask,                // VkAccessFlags2KHR                srcAccessMask
1004                             readSync.stageMask,                  // VkPipelineStageFlags2KHR            dstStageMask
1005                             readSync.accessMask,                 // VkAccessFlags2KHR                dstAccessMask
1006                             writeSync.imageLayout,               // VkImageLayout                    oldLayout
1007                             readSync.imageLayout,                // VkImageLayout                    newLayout
1008                             resource.getImage().handle,          // VkImage                            image
1009                             resource.getImage().subresourceRange // VkImageSubresourceRange            subresourceRange
1010                         );
1011                         VkDependencyInfoKHR dependencyInfo =
1012                             makeCommonDependencyInfo(nullptr, nullptr, &imageMemoryBarrier2);
1013                         synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
1014                     }
1015                     else
1016                     {
1017                         const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
1018                             writeSync.stageMask,         // VkPipelineStageFlags2KHR            srcStageMask
1019                             writeSync.accessMask,        // VkAccessFlags2KHR                srcAccessMask
1020                             readSync.stageMask,          // VkPipelineStageFlags2KHR            dstStageMask
1021                             readSync.accessMask,         // VkAccessFlags2KHR                dstAccessMask
1022                             resource.getBuffer().handle, // VkBuffer                            buffer
1023                             0,                           // VkDeviceSize                        offset
1024                             VK_WHOLE_SIZE                // VkDeviceSize                        size
1025                         );
1026                         VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(nullptr, &bufferMemoryBarrier2);
1027                         synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
1028                     }
1029                 }
1030 
1031                 endCommandBuffer(vk, cmdBuffer);
1032             }
1033 
1034             // Read operation
1035             {
1036                 uint32_t rIdx = 2 * iterIdx + 1;
1037 
1038                 waitSemaphoreSubmitInfos[rIdx].value   = m_iterations[iterIdx]->writeValue;
1039                 signalSemaphoreSubmitInfos[rIdx].value = m_iterations[iterIdx]->readValue;
1040 
1041                 synchronizationWrapper->addSubmitInfo(
1042                     1u,                              // uint32_t                                waitSemaphoreInfoCount
1043                     &waitSemaphoreSubmitInfos[rIdx], // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
1044                     1u,                              // uint32_t                                commandBufferInfoCount
1045                     &commandBufferSubmitInfos[rIdx], // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
1046                     1u,                              // uint32_t                                signalSemaphoreInfoCount
1047                     &signalSemaphoreSubmitInfos[rIdx], // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
1048                     rIdx == 0 ? false : true, true);
1049 
1050                 VkCommandBuffer cmdBuffer = commandBufferSubmitInfos[rIdx].commandBuffer;
1051                 beginCommandBuffer(vk, cmdBuffer);
1052                 m_iterations[iterIdx]->readOp->recordCommands(cmdBuffer);
1053                 endCommandBuffer(vk, cmdBuffer);
1054             }
1055         }
1056 
1057         VK_CHECK(synchronizationWrapper->queueSubmit(queue, VK_NULL_HANDLE));
1058 
1059         VK_CHECK(vk.deviceWaitIdle(device));
1060 
1061         hostCopyThread.join();
1062 
1063         {
1064             const Data expected = m_iterations.front()->writeOp->getData();
1065             const Data actual   = m_iterations.back()->readOp->getData();
1066 
1067             if (0 != deMemCmp(expected.data, actual.data, expected.size))
1068                 return tcu::TestStatus::fail("Memory contents don't match");
1069         }
1070 
1071         return tcu::TestStatus::pass("OK");
1072     }
1073 
1074 protected:
1075     const SynchronizationType m_type;
1076     OperationContext m_opContext;
1077     const ResourceDescription m_resourceDesc;
1078     std::vector<SharedPtr<TimelineIteration>> m_iterations;
1079 };
1080 
1081 class DeviceHostSyncTestCase : public TestCase
1082 {
1083 public:
DeviceHostSyncTestCase(tcu::TestContext & testCtx,const std::string & name,SynchronizationType type,const ResourceDescription resourceDesc,const OperationName writeOp,const OperationName readOp,PipelineCacheData & pipelineCacheData)1084     DeviceHostSyncTestCase(tcu::TestContext &testCtx, const std::string &name, SynchronizationType type,
1085                            const ResourceDescription resourceDesc, const OperationName writeOp,
1086                            const OperationName readOp, PipelineCacheData &pipelineCacheData)
1087         : TestCase(testCtx, name)
1088         , m_type(type)
1089         , m_resourceDesc(resourceDesc)
1090         , m_writeOp(makeOperationSupport(writeOp, resourceDesc).release())
1091         , m_readOp(makeOperationSupport(readOp, resourceDesc).release())
1092         , m_pipelineCacheData(pipelineCacheData)
1093     {
1094     }
1095 
checkSupport(Context & context) const1096     void checkSupport(Context &context) const override
1097     {
1098         context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
1099         if (m_type == SynchronizationType::SYNCHRONIZATION2)
1100             context.requireDeviceFunctionality("VK_KHR_synchronization2");
1101     }
1102 
initPrograms(SourceCollections & programCollection) const1103     void initPrograms(SourceCollections &programCollection) const override
1104     {
1105         m_writeOp->initPrograms(programCollection);
1106         m_readOp->initPrograms(programCollection);
1107     }
1108 
createInstance(Context & context) const1109     TestInstance *createInstance(Context &context) const override
1110     {
1111         return new DeviceHostTestInstance(context, m_type, m_resourceDesc, m_writeOp, m_readOp, m_pipelineCacheData);
1112     }
1113 
1114 private:
1115     const SynchronizationType m_type;
1116     const ResourceDescription m_resourceDesc;
1117     const SharedPtr<OperationSupport> m_writeOp;
1118     const SharedPtr<OperationSupport> m_readOp;
1119     PipelineCacheData &m_pipelineCacheData;
1120 };
1121 
1122 class DeviceHostTestsBase : public tcu::TestCaseGroup
1123 {
1124 public:
1125     // Synchronization of serialized device/host operations
DeviceHostTestsBase(tcu::TestContext & testCtx,SynchronizationType type)1126     DeviceHostTestsBase(tcu::TestContext &testCtx, SynchronizationType type)
1127         : tcu::TestCaseGroup(testCtx, "device_host")
1128         , m_type(type)
1129     {
1130     }
1131 
initCommonTests(void)1132     void initCommonTests(void)
1133     {
1134         static const OperationName writeOps[] = {
1135             OPERATION_NAME_WRITE_COPY_BUFFER,
1136             OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE,
1137             OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER,
1138             OPERATION_NAME_WRITE_COPY_IMAGE,
1139             OPERATION_NAME_WRITE_BLIT_IMAGE,
1140             OPERATION_NAME_WRITE_SSBO_VERTEX,
1141             OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL,
1142             OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION,
1143             OPERATION_NAME_WRITE_SSBO_GEOMETRY,
1144             OPERATION_NAME_WRITE_SSBO_FRAGMENT,
1145             OPERATION_NAME_WRITE_SSBO_COMPUTE,
1146             OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT,
1147             OPERATION_NAME_WRITE_IMAGE_VERTEX,
1148             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL,
1149             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION,
1150             OPERATION_NAME_WRITE_IMAGE_GEOMETRY,
1151             OPERATION_NAME_WRITE_IMAGE_FRAGMENT,
1152             OPERATION_NAME_WRITE_IMAGE_COMPUTE,
1153             OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT,
1154         };
1155         static const OperationName readOps[] = {
1156             OPERATION_NAME_READ_COPY_BUFFER,
1157             OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE,
1158             OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER,
1159             OPERATION_NAME_READ_COPY_IMAGE,
1160             OPERATION_NAME_READ_BLIT_IMAGE,
1161             OPERATION_NAME_READ_UBO_VERTEX,
1162             OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL,
1163             OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION,
1164             OPERATION_NAME_READ_UBO_GEOMETRY,
1165             OPERATION_NAME_READ_UBO_FRAGMENT,
1166             OPERATION_NAME_READ_UBO_COMPUTE,
1167             OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT,
1168             OPERATION_NAME_READ_SSBO_VERTEX,
1169             OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL,
1170             OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION,
1171             OPERATION_NAME_READ_SSBO_GEOMETRY,
1172             OPERATION_NAME_READ_SSBO_FRAGMENT,
1173             OPERATION_NAME_READ_SSBO_COMPUTE,
1174             OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT,
1175             OPERATION_NAME_READ_IMAGE_VERTEX,
1176             OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL,
1177             OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION,
1178             OPERATION_NAME_READ_IMAGE_GEOMETRY,
1179             OPERATION_NAME_READ_IMAGE_FRAGMENT,
1180             OPERATION_NAME_READ_IMAGE_COMPUTE,
1181             OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT,
1182             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW,
1183             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED,
1184             OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH,
1185             OPERATION_NAME_READ_VERTEX_INPUT,
1186         };
1187 
1188         for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(writeOps); ++writeOpNdx)
1189             for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(readOps); ++readOpNdx)
1190             {
1191                 const OperationName writeOp   = writeOps[writeOpNdx];
1192                 const OperationName readOp    = readOps[readOpNdx];
1193                 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
1194                 bool empty                    = true;
1195 
1196                 de::MovePtr<tcu::TestCaseGroup> opGroup(new tcu::TestCaseGroup(m_testCtx, opGroupName.c_str()));
1197 
1198                 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
1199                 {
1200                     const ResourceDescription &resource = s_resources[resourceNdx];
1201                     std::string name                    = getResourceName(resource);
1202 
1203                     if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1204                     {
1205                         opGroup->addChild(new DeviceHostSyncTestCase(m_testCtx, name, m_type, resource, writeOp, readOp,
1206                                                                      m_pipelineCacheData));
1207                         empty = false;
1208                     }
1209                 }
1210                 if (!empty)
1211                     addChild(opGroup.release());
1212             }
1213     }
1214 
1215 protected:
1216     SynchronizationType m_type;
1217 
1218 private:
1219     // synchronization.op tests share pipeline cache data to speed up test
1220     // execution.
1221     PipelineCacheData m_pipelineCacheData;
1222 };
1223 
1224 class LegacyDeviceHostTests : public DeviceHostTestsBase
1225 {
1226 public:
LegacyDeviceHostTests(tcu::TestContext & testCtx)1227     LegacyDeviceHostTests(tcu::TestContext &testCtx) : DeviceHostTestsBase(testCtx, SynchronizationType::LEGACY)
1228     {
1229     }
1230 
init(void)1231     void init(void)
1232     {
1233         initCommonTests();
1234 
1235         de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(m_testCtx, "misc"));
1236         // Timeline semaphore properties test
1237         addFunctionCase(miscGroup.get(), "max_difference_value", checkSupport, maxDifferenceValueCase, m_type);
1238         // Timeline semaphore initial value test
1239         addFunctionCase(miscGroup.get(), "initial_value", checkSupport, initialValueCase, m_type);
1240         addChild(miscGroup.release());
1241     }
1242 };
1243 
1244 class Sytnchronization2DeviceHostTests : public DeviceHostTestsBase
1245 {
1246 public:
Sytnchronization2DeviceHostTests(tcu::TestContext & testCtx)1247     Sytnchronization2DeviceHostTests(tcu::TestContext &testCtx)
1248         : DeviceHostTestsBase(testCtx, SynchronizationType::SYNCHRONIZATION2)
1249     {
1250     }
1251 
init(void)1252     void init(void)
1253     {
1254         initCommonTests();
1255 
1256         de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(m_testCtx, "misc"));
1257         // Timeline semaphore properties test
1258         addFunctionCase(miscGroup.get(), "max_difference_value", checkSupport, maxDifferenceValueCase, m_type);
1259         addChild(miscGroup.release());
1260     }
1261 };
1262 
1263 struct QueueTimelineIteration
1264 {
QueueTimelineIterationvkt::synchronization::__anoncf99eb0b0111::QueueTimelineIteration1265     QueueTimelineIteration(const SharedPtr<OperationSupport> &_opSupport, uint64_t lastValue, VkQueue _queue,
1266                            uint32_t _queueFamilyIdx, de::Random &rng)
1267         : opSupport(_opSupport)
1268         , queue(_queue)
1269         , queueFamilyIdx(_queueFamilyIdx)
1270     {
1271         timelineValue = lastValue + rng.getInt(1, 100);
1272     }
~QueueTimelineIterationvkt::synchronization::__anoncf99eb0b0111::QueueTimelineIteration1273     ~QueueTimelineIteration()
1274     {
1275     }
1276 
1277     SharedPtr<OperationSupport> opSupport;
1278     VkQueue queue;
1279     uint32_t queueFamilyIdx;
1280     uint64_t timelineValue;
1281     SharedPtr<Operation> op;
1282 };
1283 
getQueueCreateInfo(const std::vector<VkQueueFamilyProperties> queueFamilyProperties)1284 std::vector<VkDeviceQueueCreateInfo> getQueueCreateInfo(
1285     const std::vector<VkQueueFamilyProperties> queueFamilyProperties)
1286 {
1287     std::vector<VkDeviceQueueCreateInfo> infos;
1288 
1289     for (uint32_t i = 0; i < queueFamilyProperties.size(); i++)
1290     {
1291         VkDeviceQueueCreateInfo info = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, nullptr, 0, i,
1292                                         queueFamilyProperties[i].queueCount,        nullptr};
1293         infos.push_back(info);
1294     }
1295 
1296     return infos;
1297 }
1298 
createTestDevice(Context & context,const VkInstance & instance,const InstanceInterface & vki,SynchronizationType type)1299 Move<VkDevice> createTestDevice(Context &context, const VkInstance &instance, const InstanceInterface &vki,
1300                                 SynchronizationType type)
1301 {
1302     const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
1303     const std::vector<VkQueueFamilyProperties> queueFamilyProperties =
1304         getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
1305     std::vector<VkDeviceQueueCreateInfo> queueCreateInfos = getQueueCreateInfo(queueFamilyProperties);
1306     VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features{
1307         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, nullptr, true};
1308     VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures{
1309         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, nullptr, true};
1310     VkPhysicalDeviceFeatures2 createPhysicalFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1311                                                      &timelineSemaphoreFeatures, context.getDeviceFeatures()};
1312     void **nextPtr = &timelineSemaphoreFeatures.pNext;
1313 
1314     std::vector<const char *> deviceExtensions;
1315 
1316     if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_timeline_semaphore"))
1317         deviceExtensions.push_back("VK_KHR_timeline_semaphore");
1318     if (type == SynchronizationType::SYNCHRONIZATION2)
1319     {
1320         deviceExtensions.push_back("VK_KHR_synchronization2");
1321         addToChainVulkanStructure(&nextPtr, synchronization2Features);
1322     }
1323 
1324     void *pNext = &createPhysicalFeatures;
1325 #ifdef CTS_USES_VULKANSC
1326     VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ?
1327                                                                  context.getResourceInterface()->getStatMax() :
1328                                                                  resetDeviceObjectReservationCreateInfo();
1329     memReservationInfo.pNext                               = pNext;
1330     pNext                                                  = &memReservationInfo;
1331 
1332     VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
1333     sc10Features.pNext                              = pNext;
1334     pNext                                           = &sc10Features;
1335 
1336     VkPipelineCacheCreateInfo pcCI;
1337     std::vector<VkPipelinePoolSize> poolSizes;
1338     if (context.getTestContext().getCommandLine().isSubProcess())
1339     {
1340         if (context.getResourceInterface()->getCacheDataSize() > 0)
1341         {
1342             pcCI = {
1343                 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
1344                 nullptr,                                      // const void* pNext;
1345                 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
1346                     VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
1347                 context.getResourceInterface()->getCacheDataSize(),       // uintptr_t initialDataSize;
1348                 context.getResourceInterface()->getCacheData()            // const void* pInitialData;
1349             };
1350             memReservationInfo.pipelineCacheCreateInfoCount = 1;
1351             memReservationInfo.pPipelineCacheCreateInfos    = &pcCI;
1352         }
1353 
1354         poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
1355         if (!poolSizes.empty())
1356         {
1357             memReservationInfo.pipelinePoolSizeCount = uint32_t(poolSizes.size());
1358             memReservationInfo.pPipelinePoolSizes    = poolSizes.data();
1359         }
1360     }
1361 #endif // CTS_USES_VULKANSC
1362 
1363     const VkDeviceCreateInfo deviceInfo = {
1364         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,           //VkStructureType sType;
1365         pNext,                                          //const void* pNext;
1366         0u,                                             //VkDeviceCreateFlags flags;
1367         static_cast<uint32_t>(queueCreateInfos.size()), //uint32_t queueCreateInfoCount;
1368         &queueCreateInfos[0],                           //const VkDeviceQueueCreateInfo* pQueueCreateInfos;
1369         0u,                                             //uint32_t enabledLayerCount;
1370         nullptr,                                        //const char* const* ppEnabledLayerNames;
1371         static_cast<uint32_t>(deviceExtensions.size()), //uint32_t enabledExtensionCount;
1372         deviceExtensions.data(),                        //const char* const* ppEnabledExtensionNames;
1373         0u                                              //const VkPhysicalDeviceFeatures* pEnabledFeatures;
1374     };
1375     std::vector<SharedPtr<std::vector<float>>> queuePriorities;
1376 
1377     for (auto &queueCreateInfo : queueCreateInfos)
1378     {
1379         MovePtr<std::vector<float>> priorities(new std::vector<float>);
1380 
1381         for (uint32_t i = 0; i < queueCreateInfo.queueCount; i++)
1382             priorities->push_back(1.0f);
1383 
1384         queuePriorities.push_back(makeSharedPtr(priorities));
1385 
1386         queueCreateInfo.pQueuePriorities = &(*queuePriorities.back().get())[0];
1387     }
1388 
1389     const auto validation = context.getTestContext().getCommandLine().isValidationEnabled();
1390 
1391     return createCustomDevice(validation, context.getPlatformInterface(), instance, vki, physicalDevice, &deviceInfo);
1392 }
1393 
1394 // Class to wrap a singleton instance and device
1395 class SingletonDevice
1396 {
SingletonDevice(Context & context,SynchronizationType type)1397     SingletonDevice(Context &context, SynchronizationType type)
1398         : m_logicalDevice(createTestDevice(context, context.getInstance(), context.getInstanceInterface(), type))
1399     {
1400     }
1401 
1402 public:
getDevice(Context & context,SynchronizationType type)1403     static const Unique<vk::VkDevice> &getDevice(Context &context, SynchronizationType type)
1404     {
1405         if (!m_singletonDevice)
1406             m_singletonDevice = SharedPtr<SingletonDevice>(new SingletonDevice(context, type));
1407 
1408         DE_ASSERT(m_singletonDevice);
1409         return m_singletonDevice->m_logicalDevice;
1410     }
1411 
destroy()1412     static void destroy()
1413     {
1414         m_singletonDevice.clear();
1415     }
1416 
1417 private:
1418     const Unique<vk::VkDevice> m_logicalDevice;
1419 
1420     static SharedPtr<SingletonDevice> m_singletonDevice;
1421 };
1422 SharedPtr<SingletonDevice> SingletonDevice::m_singletonDevice;
1423 
cleanupGroup()1424 static void cleanupGroup()
1425 {
1426     // Destroy singleton object
1427     SingletonDevice::destroy();
1428 }
1429 
1430 // Create a chain of operations with data copied across queues & host
1431 // and submit the operations out of order to verify that the queues
1432 // are properly unblocked as the work progresses.
1433 class WaitBeforeSignalTestInstance : public TestInstance
1434 {
1435 public:
WaitBeforeSignalTestInstance(Context & context,SynchronizationType type,const ResourceDescription & resourceDesc,const SharedPtr<OperationSupport> & writeOp,const SharedPtr<OperationSupport> & readOp,PipelineCacheData & pipelineCacheData)1436     WaitBeforeSignalTestInstance(Context &context, SynchronizationType type, const ResourceDescription &resourceDesc,
1437                                  const SharedPtr<OperationSupport> &writeOp, const SharedPtr<OperationSupport> &readOp,
1438                                  PipelineCacheData &pipelineCacheData)
1439         : TestInstance(context)
1440         , m_type(type)
1441         , m_resourceDesc(resourceDesc)
1442         , m_device(SingletonDevice::getDevice(context, type))
1443         , m_context(context)
1444 #ifndef CTS_USES_VULKANSC
1445         , m_deviceDriver(de::MovePtr<DeviceDriver>(
1446               new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *m_device,
1447                                context.getUsedApiVersion(), context.getTestContext().getCommandLine())))
1448 #else
1449         , m_deviceDriver(de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
1450               new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *m_device,
1451                                  context.getTestContext().getCommandLine(), context.getResourceInterface(),
1452                                  m_context.getDeviceVulkanSC10Properties(), m_context.getDeviceProperties(),
1453                                  context.getUsedApiVersion()),
1454               vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *m_device)))
1455 #endif // CTS_USES_VULKANSC
1456         , m_allocator(new SimpleAllocator(
1457               *m_deviceDriver, *m_device,
1458               getPhysicalDeviceMemoryProperties(context.getInstanceInterface(),
1459                                                 chooseDevice(context.getInstanceInterface(), context.getInstance(),
1460                                                              context.getTestContext().getCommandLine()))))
1461         , m_opContext(context, type, *m_deviceDriver, *m_device, *m_allocator, pipelineCacheData)
1462     {
1463         const auto &vki                       = m_context.getInstanceInterface();
1464         const auto instance                   = m_context.getInstance();
1465         const DeviceInterface &vk             = *m_deviceDriver;
1466         const VkDevice device                 = *m_device;
1467         const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
1468         const std::vector<VkQueueFamilyProperties> queueFamilyProperties =
1469             getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
1470         const uint32_t universalQueueFamilyIndex = context.getUniversalQueueFamilyIndex();
1471         de::Random rng(1234);
1472         uint32_t lastCopyOpIdx = 0;
1473         std::set<std::pair<uint32_t, uint32_t>> used_queues;
1474 
1475         m_hostTimelineValue = rng.getInt(0, 1000);
1476 
1477         m_iterations.push_back(makeSharedPtr(new QueueTimelineIteration(
1478             writeOp, m_hostTimelineValue, getDeviceQueue(vk, device, universalQueueFamilyIndex, 0),
1479             universalQueueFamilyIndex, rng)));
1480         used_queues.insert(std::make_pair(universalQueueFamilyIndex, 0));
1481 
1482         // Go through all the queues and try to use all the ones that
1483         // support the type of resource we're dealing with.
1484         for (uint32_t familyIdx = 0; familyIdx < queueFamilyProperties.size(); familyIdx++)
1485         {
1486             for (uint32_t instanceIdx = 0; instanceIdx < queueFamilyProperties[familyIdx].queueCount; instanceIdx++)
1487             {
1488                 // Only add each queue once.
1489                 if (used_queues.find(std::make_pair(familyIdx, instanceIdx)) != used_queues.end())
1490                     continue;
1491 
1492                 // Find an operation compatible with the queue
1493                 for (uint32_t copyOpIdx = 0; copyOpIdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpIdx++)
1494                 {
1495                     OperationName copyOpName = s_copyOps[(lastCopyOpIdx + copyOpIdx) % DE_LENGTH_OF_ARRAY(s_copyOps)];
1496 
1497                     if (isResourceSupported(copyOpName, resourceDesc))
1498                     {
1499                         SharedPtr<OperationSupport> copyOpSupport(
1500                             makeOperationSupport(copyOpName, resourceDesc).release());
1501                         VkQueueFlags copyOpQueueFlags = copyOpSupport->getQueueFlags(m_opContext);
1502 
1503                         if ((copyOpQueueFlags & queueFamilyProperties[familyIdx].queueFlags) != copyOpQueueFlags)
1504                             continue;
1505 
1506                         // Barriers use VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT pipeline stage so queue must have VK_QUEUE_GRAPHICS_BIT
1507                         if ((copyOpQueueFlags & VK_QUEUE_GRAPHICS_BIT) == 0u)
1508                             continue;
1509 
1510                         m_iterations.push_back(makeSharedPtr(new QueueTimelineIteration(
1511                             copyOpSupport, m_iterations.back()->timelineValue,
1512                             getDeviceQueue(vk, device, familyIdx, instanceIdx), familyIdx, rng)));
1513                         used_queues.insert(std::make_pair(familyIdx, instanceIdx));
1514                         break;
1515                     }
1516                 }
1517             }
1518         }
1519 
1520         // Add the read operation on the universal queue, it should be
1521         // submitted in order with regard to the write operation.
1522         m_iterations.push_back(makeSharedPtr(new QueueTimelineIteration(
1523             readOp, m_iterations.back()->timelineValue, getDeviceQueue(vk, device, universalQueueFamilyIndex, 0),
1524             universalQueueFamilyIndex, rng)));
1525 
1526         // Now create the resources with the usage associated to the
1527         // operation performed on the resource.
1528         for (uint32_t opIdx = 0; opIdx < (m_iterations.size() - 1); opIdx++)
1529         {
1530             uint32_t usage = m_iterations[opIdx]->opSupport->getOutResourceUsageFlags() |
1531                              m_iterations[opIdx + 1]->opSupport->getInResourceUsageFlags();
1532 
1533             m_resources.push_back(makeSharedPtr(new Resource(m_opContext, resourceDesc, usage)));
1534         }
1535 
1536         m_iterations.front()->op =
1537             makeSharedPtr(m_iterations.front()->opSupport->build(m_opContext, *m_resources.front()).release());
1538         for (uint32_t opIdx = 1; opIdx < (m_iterations.size() - 1); opIdx++)
1539         {
1540             m_iterations[opIdx]->op =
1541                 makeSharedPtr(m_iterations[opIdx]
1542                                   ->opSupport->build(m_opContext, *m_resources[opIdx - 1], *m_resources[opIdx])
1543                                   .release());
1544         }
1545         m_iterations.back()->op =
1546             makeSharedPtr(m_iterations.back()->opSupport->build(m_opContext, *m_resources.back()).release());
1547     }
1548 
~WaitBeforeSignalTestInstance()1549     ~WaitBeforeSignalTestInstance()
1550     {
1551     }
1552 
iterate(void)1553     tcu::TestStatus iterate(void)
1554     {
1555         const DeviceInterface &vk = *m_deviceDriver;
1556         const VkDevice device     = *m_device;
1557         const Unique<VkSemaphore> semaphore(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE));
1558         std::vector<SharedPtr<Move<VkCommandPool>>> cmdPools;
1559         std::vector<SharedPtr<Move<VkCommandBuffer>>> ptrCmdBuffers;
1560         std::vector<VkCommandBufferSubmitInfoKHR> commandBufferSubmitInfos(m_iterations.size(),
1561                                                                            makeCommonCommandBufferSubmitInfo(0));
1562         VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo =
1563             makeCommonSemaphoreSubmitInfo(*semaphore, 0u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
1564         VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo =
1565             makeCommonSemaphoreSubmitInfo(*semaphore, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
1566 
1567         for (uint32_t opNdx = 0; opNdx < m_iterations.size(); opNdx++)
1568         {
1569             cmdPools.push_back(makeVkSharedPtr(createCommandPool(
1570                 vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_iterations[opNdx]->queueFamilyIdx)));
1571             ptrCmdBuffers.push_back(makeVkSharedPtr(makeCommandBuffer(vk, device, **cmdPools.back())));
1572             commandBufferSubmitInfos[opNdx].commandBuffer = **(ptrCmdBuffers.back());
1573         }
1574 
1575         // Randomize the data copied over.
1576         {
1577             const Data startData = m_iterations.front()->op->getData();
1578             Data randomizedData;
1579             std::vector<uint8_t> dataArray;
1580 
1581             dataArray.resize(startData.size);
1582             randomizeData(dataArray, m_resourceDesc);
1583             randomizedData.size = dataArray.size();
1584             randomizedData.data = &dataArray[0];
1585             m_iterations.front()->op->setData(randomizedData);
1586         }
1587 
1588         for (uint32_t _iterIdx = 0; _iterIdx < (m_iterations.size() - 1); _iterIdx++)
1589         {
1590             // Submit in reverse order of the dependency order to
1591             // exercise the wait-before-submit behavior.
1592             uint32_t iterIdx                                 = (uint32_t)(m_iterations.size() - 2 - _iterIdx);
1593             VkCommandBuffer cmdBuffer                        = commandBufferSubmitInfos[iterIdx].commandBuffer;
1594             SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_type, vk, true);
1595 
1596             waitSemaphoreSubmitInfo.value =
1597                 iterIdx == 0 ? m_hostTimelineValue : m_iterations[iterIdx - 1]->timelineValue;
1598             signalSemaphoreSubmitInfo.value = m_iterations[iterIdx]->timelineValue;
1599 
1600             synchronizationWrapper->addSubmitInfo(
1601                 1u,                                 // uint32_t                                waitSemaphoreInfoCount
1602                 &waitSemaphoreSubmitInfo,           // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
1603                 1u,                                 // uint32_t                                commandBufferInfoCount
1604                 &commandBufferSubmitInfos[iterIdx], // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
1605                 1u,                                 // uint32_t                                signalSemaphoreInfoCount
1606                 &signalSemaphoreSubmitInfo,         // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
1607                 true, true);
1608 
1609             beginCommandBuffer(vk, cmdBuffer);
1610             if (iterIdx > 0)
1611             {
1612                 const SyncInfo readSync      = m_iterations[iterIdx]->op->getInSyncInfo();
1613                 const Resource &readResource = *m_resources[iterIdx - 1];
1614 
1615                 if (readResource.getType() == RESOURCE_TYPE_IMAGE)
1616                 {
1617                     DE_ASSERT(readSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
1618 
1619                     const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
1620                         VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,        // VkPipelineStageFlags2KHR            srcStageMask
1621                         VK_ACCESS_2_NONE,                         // VkAccessFlags2KHR                srcAccessMask
1622                         readSync.stageMask,                       // VkPipelineStageFlags2KHR            dstStageMask
1623                         readSync.accessMask,                      // VkAccessFlags2KHR                dstAccessMask
1624                         VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout                    oldLayout
1625                         readSync.imageLayout,                     // VkImageLayout                    newLayout
1626                         readResource.getImage().handle,           // VkImage                            image
1627                         readResource.getImage().subresourceRange, // VkImageSubresourceRange            subresourceRange
1628                         m_iterations[iterIdx]
1629                             ->queueFamilyIdx, // uint32_t                            srcQueueFamilyIndex
1630                         m_iterations[iterIdx + 1]
1631                             ->queueFamilyIdx // uint32_t                            destQueueFamilyIndex
1632                     );
1633                     VkDependencyInfoKHR dependencyInfo =
1634                         makeCommonDependencyInfo(nullptr, nullptr, &imageMemoryBarrier2);
1635                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
1636                 }
1637             }
1638             m_iterations[iterIdx]->op->recordCommands(cmdBuffer);
1639 
1640             {
1641                 const SyncInfo writeSync = m_iterations[iterIdx]->op->getOutSyncInfo();
1642                 const SyncInfo readSync  = m_iterations[iterIdx + 1]->op->getInSyncInfo();
1643                 const Resource &resource = *m_resources[iterIdx];
1644 
1645                 if (resource.getType() == RESOURCE_TYPE_IMAGE)
1646                 {
1647                     DE_ASSERT(writeSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
1648                     DE_ASSERT(readSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
1649 
1650                     const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
1651                         writeSync.stageMask,                  // VkPipelineStageFlags2KHR            srcStageMask
1652                         writeSync.accessMask,                 // VkAccessFlags2KHR                srcAccessMask
1653                         readSync.stageMask,                   // VkPipelineStageFlags2KHR            dstStageMask
1654                         readSync.accessMask,                  // VkAccessFlags2KHR                dstAccessMask
1655                         writeSync.imageLayout,                // VkImageLayout                    oldLayout
1656                         readSync.imageLayout,                 // VkImageLayout                    newLayout
1657                         resource.getImage().handle,           // VkImage                            image
1658                         resource.getImage().subresourceRange, // VkImageSubresourceRange            subresourceRange
1659                         m_iterations[iterIdx]
1660                             ->queueFamilyIdx, // uint32_t                            srcQueueFamilyIndex
1661                         m_iterations[iterIdx + 1]
1662                             ->queueFamilyIdx // uint32_t                            destQueueFamilyIndex
1663                     );
1664                     VkDependencyInfoKHR dependencyInfo =
1665                         makeCommonDependencyInfo(nullptr, nullptr, &imageMemoryBarrier2);
1666                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
1667                 }
1668                 else
1669                 {
1670                     const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
1671                         writeSync.stageMask,         // VkPipelineStageFlags2KHR            srcStageMask
1672                         writeSync.accessMask,        // VkAccessFlags2KHR                srcAccessMask
1673                         readSync.stageMask,          // VkPipelineStageFlags2KHR            dstStageMask
1674                         readSync.accessMask,         // VkAccessFlags2KHR                dstAccessMask
1675                         resource.getBuffer().handle, // VkBuffer                            buffer
1676                         0,                           // VkDeviceSize                        offset
1677                         VK_WHOLE_SIZE,               // VkDeviceSize                        size
1678                         m_iterations[iterIdx]
1679                             ->queueFamilyIdx, // uint32_t                            srcQueueFamilyIndex
1680                         m_iterations[iterIdx + 1]
1681                             ->queueFamilyIdx // uint32_t                            dstQueueFamilyIndex
1682                     );
1683                     VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(nullptr, &bufferMemoryBarrier2);
1684                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
1685                 }
1686             }
1687 
1688             endCommandBuffer(vk, cmdBuffer);
1689 
1690             VK_CHECK(synchronizationWrapper->queueSubmit(m_iterations[iterIdx]->queue, VK_NULL_HANDLE));
1691         }
1692 
1693         // Submit the last read operation in order.
1694         {
1695             const uint32_t iterIdx                           = (uint32_t)(m_iterations.size() - 1);
1696             SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_type, vk, true);
1697 
1698             waitSemaphoreSubmitInfo.value   = m_iterations[iterIdx - 1]->timelineValue;
1699             signalSemaphoreSubmitInfo.value = m_iterations[iterIdx]->timelineValue;
1700 
1701             synchronizationWrapper->addSubmitInfo(
1702                 1u,                                 // uint32_t                                waitSemaphoreInfoCount
1703                 &waitSemaphoreSubmitInfo,           // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
1704                 1u,                                 // uint32_t                                commandBufferInfoCount
1705                 &commandBufferSubmitInfos[iterIdx], // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
1706                 1u,                                 // uint32_t                                signalSemaphoreInfoCount
1707                 &signalSemaphoreSubmitInfo,         // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
1708                 true, true);
1709 
1710             VkCommandBuffer cmdBuffer = commandBufferSubmitInfos[iterIdx].commandBuffer;
1711             beginCommandBuffer(vk, cmdBuffer);
1712             m_iterations[iterIdx]->op->recordCommands(cmdBuffer);
1713             endCommandBuffer(vk, cmdBuffer);
1714 
1715             VK_CHECK(synchronizationWrapper->queueSubmit(m_iterations[iterIdx]->queue, VK_NULL_HANDLE));
1716         }
1717 
1718         {
1719             // Kick off the whole chain from the host.
1720             hostSignal(vk, device, *semaphore, m_hostTimelineValue);
1721             VK_CHECK(vk.deviceWaitIdle(device));
1722         }
1723 
1724         {
1725             const Data expected = m_iterations.front()->op->getData();
1726             const Data actual   = m_iterations.back()->op->getData();
1727 
1728             if (0 != deMemCmp(expected.data, actual.data, expected.size))
1729                 return tcu::TestStatus::fail("Memory contents don't match");
1730         }
1731 
1732         return tcu::TestStatus::pass("OK");
1733     }
1734 
1735 protected:
1736     const SynchronizationType m_type;
1737     const ResourceDescription m_resourceDesc;
1738     const Unique<VkDevice> &m_device;
1739     const Context &m_context;
1740 #ifndef CTS_USES_VULKANSC
1741     de::MovePtr<vk::DeviceDriver> m_deviceDriver;
1742 #else
1743     de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter> m_deviceDriver;
1744 #endif // CTS_USES_VULKANSC
1745     MovePtr<Allocator> m_allocator;
1746     OperationContext m_opContext;
1747     std::vector<SharedPtr<QueueTimelineIteration>> m_iterations;
1748     std::vector<SharedPtr<Resource>> m_resources;
1749     uint64_t m_hostTimelineValue;
1750 };
1751 
1752 class WaitBeforeSignalTestCase : public TestCase
1753 {
1754 public:
WaitBeforeSignalTestCase(tcu::TestContext & testCtx,const std::string & name,SynchronizationType type,const ResourceDescription resourceDesc,const OperationName writeOp,const OperationName readOp,PipelineCacheData & pipelineCacheData)1755     WaitBeforeSignalTestCase(tcu::TestContext &testCtx, const std::string &name, SynchronizationType type,
1756                              const ResourceDescription resourceDesc, const OperationName writeOp,
1757                              const OperationName readOp, PipelineCacheData &pipelineCacheData)
1758         : TestCase(testCtx, name)
1759         , m_type(type)
1760         , m_resourceDesc(resourceDesc)
1761         , m_writeOp(makeOperationSupport(writeOp, resourceDesc).release())
1762         , m_readOp(makeOperationSupport(readOp, resourceDesc).release())
1763         , m_pipelineCacheData(pipelineCacheData)
1764     {
1765     }
1766 
checkSupport(Context & context) const1767     void checkSupport(Context &context) const override
1768     {
1769         context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
1770         if (m_type == SynchronizationType::SYNCHRONIZATION2)
1771             context.requireDeviceFunctionality("VK_KHR_synchronization2");
1772     }
1773 
initPrograms(SourceCollections & programCollection) const1774     void initPrograms(SourceCollections &programCollection) const override
1775     {
1776         m_writeOp->initPrograms(programCollection);
1777         m_readOp->initPrograms(programCollection);
1778 
1779         for (uint32_t copyOpNdx = 0; copyOpNdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpNdx++)
1780         {
1781             if (isResourceSupported(s_copyOps[copyOpNdx], m_resourceDesc))
1782                 makeOperationSupport(s_copyOps[copyOpNdx], m_resourceDesc)->initPrograms(programCollection);
1783         }
1784     }
1785 
createInstance(Context & context) const1786     TestInstance *createInstance(Context &context) const override
1787     {
1788         return new WaitBeforeSignalTestInstance(context, m_type, m_resourceDesc, m_writeOp, m_readOp,
1789                                                 m_pipelineCacheData);
1790     }
1791 
1792 private:
1793     SynchronizationType m_type;
1794     const ResourceDescription m_resourceDesc;
1795     const SharedPtr<OperationSupport> m_writeOp;
1796     const SharedPtr<OperationSupport> m_readOp;
1797     PipelineCacheData &m_pipelineCacheData;
1798 };
1799 
1800 class WaitBeforeSignalTests : public tcu::TestCaseGroup
1801 {
1802 public:
1803     // Synchronization of out of order submissions to queues
WaitBeforeSignalTests(tcu::TestContext & testCtx,SynchronizationType type)1804     WaitBeforeSignalTests(tcu::TestContext &testCtx, SynchronizationType type)
1805         : tcu::TestCaseGroup(testCtx, "wait_before_signal")
1806         , m_type(type)
1807     {
1808     }
1809 
init(void)1810     void init(void)
1811     {
1812         static const OperationName writeOps[] = {
1813             OPERATION_NAME_WRITE_COPY_BUFFER,
1814             OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE,
1815             OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER,
1816             OPERATION_NAME_WRITE_COPY_IMAGE,
1817             OPERATION_NAME_WRITE_BLIT_IMAGE,
1818             OPERATION_NAME_WRITE_SSBO_VERTEX,
1819             OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL,
1820             OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION,
1821             OPERATION_NAME_WRITE_SSBO_GEOMETRY,
1822             OPERATION_NAME_WRITE_SSBO_FRAGMENT,
1823             OPERATION_NAME_WRITE_SSBO_COMPUTE,
1824             OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT,
1825             OPERATION_NAME_WRITE_IMAGE_VERTEX,
1826             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL,
1827             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION,
1828             OPERATION_NAME_WRITE_IMAGE_GEOMETRY,
1829             OPERATION_NAME_WRITE_IMAGE_FRAGMENT,
1830             OPERATION_NAME_WRITE_IMAGE_COMPUTE,
1831             OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT,
1832         };
1833         static const OperationName readOps[] = {
1834             OPERATION_NAME_READ_COPY_BUFFER,
1835             OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE,
1836             OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER,
1837             OPERATION_NAME_READ_COPY_IMAGE,
1838             OPERATION_NAME_READ_BLIT_IMAGE,
1839             OPERATION_NAME_READ_UBO_VERTEX,
1840             OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL,
1841             OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION,
1842             OPERATION_NAME_READ_UBO_GEOMETRY,
1843             OPERATION_NAME_READ_UBO_FRAGMENT,
1844             OPERATION_NAME_READ_UBO_COMPUTE,
1845             OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT,
1846             OPERATION_NAME_READ_SSBO_VERTEX,
1847             OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL,
1848             OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION,
1849             OPERATION_NAME_READ_SSBO_GEOMETRY,
1850             OPERATION_NAME_READ_SSBO_FRAGMENT,
1851             OPERATION_NAME_READ_SSBO_COMPUTE,
1852             OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT,
1853             OPERATION_NAME_READ_IMAGE_VERTEX,
1854             OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL,
1855             OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION,
1856             OPERATION_NAME_READ_IMAGE_GEOMETRY,
1857             OPERATION_NAME_READ_IMAGE_FRAGMENT,
1858             OPERATION_NAME_READ_IMAGE_COMPUTE,
1859             OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT,
1860             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW,
1861             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED,
1862             OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH,
1863             OPERATION_NAME_READ_VERTEX_INPUT,
1864         };
1865 
1866         for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(writeOps); ++writeOpNdx)
1867             for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(readOps); ++readOpNdx)
1868             {
1869                 const OperationName writeOp   = writeOps[writeOpNdx];
1870                 const OperationName readOp    = readOps[readOpNdx];
1871                 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
1872                 bool empty                    = true;
1873 
1874                 de::MovePtr<tcu::TestCaseGroup> opGroup(new tcu::TestCaseGroup(m_testCtx, opGroupName.c_str()));
1875 
1876                 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
1877                 {
1878                     const ResourceDescription &resource = s_resources[resourceNdx];
1879                     std::string name                    = getResourceName(resource);
1880 
1881                     if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1882                     {
1883                         opGroup->addChild(new WaitBeforeSignalTestCase(m_testCtx, name, m_type, resource, writeOp,
1884                                                                        readOp, m_pipelineCacheData));
1885                         empty = false;
1886                     }
1887                 }
1888                 if (!empty)
1889                     addChild(opGroup.release());
1890             }
1891     }
1892 
deinit(void)1893     void deinit(void)
1894     {
1895         cleanupGroup();
1896     }
1897 
1898 private:
1899     SynchronizationType m_type;
1900 
1901     // synchronization.op tests share pipeline cache data to speed up test
1902     // execution.
1903     PipelineCacheData m_pipelineCacheData;
1904 };
1905 
1906 // Creates a tree of operations like this :
1907 //
1908 // WriteOp1-Queue0 --> CopyOp2-Queue1 --> ReadOp-Queue4
1909 //                 |
1910 //                 --> CopyOp3-Queue3 --> ReadOp-Queue5
1911 //
1912 // Verifies that we get the data propagated properly.
1913 class OneToNTestInstance : public TestInstance
1914 {
1915 public:
OneToNTestInstance(Context & context,SynchronizationType type,const ResourceDescription & resourceDesc,const SharedPtr<OperationSupport> & writeOp,const SharedPtr<OperationSupport> & readOp,PipelineCacheData & pipelineCacheData)1916     OneToNTestInstance(Context &context, SynchronizationType type, const ResourceDescription &resourceDesc,
1917                        const SharedPtr<OperationSupport> &writeOp, const SharedPtr<OperationSupport> &readOp,
1918                        PipelineCacheData &pipelineCacheData)
1919         : TestInstance(context)
1920         , m_type(type)
1921         , m_resourceDesc(resourceDesc)
1922         , m_device(SingletonDevice::getDevice(context, type))
1923         , m_context(context)
1924 #ifndef CTS_USES_VULKANSC
1925         , m_deviceDriver(de::MovePtr<DeviceDriver>(
1926               new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *m_device,
1927                                context.getUsedApiVersion(), context.getTestContext().getCommandLine())))
1928 #else
1929         , m_deviceDriver(de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
1930               new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *m_device,
1931                                  context.getTestContext().getCommandLine(), context.getResourceInterface(),
1932                                  m_context.getDeviceVulkanSC10Properties(), m_context.getDeviceProperties(),
1933                                  context.getUsedApiVersion()),
1934               vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *m_device)))
1935 #endif // CTS_USES_VULKANSC
1936         , m_allocator(new SimpleAllocator(
1937               *m_deviceDriver, *m_device,
1938               getPhysicalDeviceMemoryProperties(context.getInstanceInterface(),
1939                                                 chooseDevice(context.getInstanceInterface(), context.getInstance(),
1940                                                              context.getTestContext().getCommandLine()))))
1941         , m_opContext(context, type, *m_deviceDriver, *m_device, *m_allocator, pipelineCacheData)
1942     {
1943         const auto &vki                       = m_context.getInstanceInterface();
1944         const auto instance                   = m_context.getInstance();
1945         const DeviceInterface &vk             = *m_deviceDriver;
1946         const VkDevice device                 = *m_device;
1947         const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
1948         const std::vector<VkQueueFamilyProperties> queueFamilyProperties =
1949             getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
1950         const uint32_t universalQueueFamilyIndex = context.getUniversalQueueFamilyIndex();
1951         de::Random rng(1234);
1952         uint32_t lastCopyOpIdx = 0;
1953         uint64_t lastSubmitValue;
1954 
1955         m_hostTimelineValue = rng.getInt(0, 1000);
1956 
1957         m_writeIteration = makeSharedPtr(new QueueTimelineIteration(
1958             writeOp, m_hostTimelineValue, getDeviceQueue(vk, device, universalQueueFamilyIndex, 0),
1959             universalQueueFamilyIndex, rng));
1960         lastSubmitValue  = m_writeIteration->timelineValue;
1961 
1962         // Go through all the queues and try to use all the ones that
1963         // support the type of resource we're dealing with.
1964         for (uint32_t familyIdx = 0; familyIdx < queueFamilyProperties.size(); familyIdx++)
1965         {
1966             for (uint32_t instanceIdx = 0; instanceIdx < queueFamilyProperties[familyIdx].queueCount; instanceIdx++)
1967             {
1968                 // Find an operation compatible with the queue
1969                 for (uint32_t copyOpIdx = 0; copyOpIdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpIdx++)
1970                 {
1971                     OperationName copyOpName = s_copyOps[(lastCopyOpIdx + copyOpIdx) % DE_LENGTH_OF_ARRAY(s_copyOps)];
1972 
1973                     if (isResourceSupported(copyOpName, resourceDesc))
1974                     {
1975                         SharedPtr<OperationSupport> copyOpSupport(
1976                             makeOperationSupport(copyOpName, resourceDesc).release());
1977                         VkQueueFlags copyOpQueueFlags = copyOpSupport->getQueueFlags(m_opContext);
1978 
1979                         if ((copyOpQueueFlags & queueFamilyProperties[familyIdx].queueFlags) != copyOpQueueFlags)
1980                             continue;
1981 
1982                         VkShaderStageFlagBits writeStage = writeOp->getShaderStage();
1983                         if (writeStage != VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM &&
1984                             !isStageSupported(writeStage, copyOpQueueFlags))
1985                         {
1986                             continue;
1987                         }
1988                         VkShaderStageFlagBits readStage = readOp->getShaderStage();
1989                         if (readStage != VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM &&
1990                             !isStageSupported(readStage, copyOpQueueFlags))
1991                         {
1992                             continue;
1993                         }
1994 
1995                         m_copyIterations.push_back(makeSharedPtr(new QueueTimelineIteration(
1996                             copyOpSupport, lastSubmitValue, getDeviceQueue(vk, device, familyIdx, instanceIdx),
1997                             familyIdx, rng)));
1998                         lastSubmitValue = m_copyIterations.back()->timelineValue;
1999                         break;
2000                     }
2001                 }
2002             }
2003         }
2004 
2005         for (uint32_t copyOpIdx = 0; copyOpIdx < m_copyIterations.size(); copyOpIdx++)
2006         {
2007             bool added = false;
2008 
2009             for (uint32_t familyIdx = 0; familyIdx < queueFamilyProperties.size() && !added; familyIdx++)
2010             {
2011                 for (uint32_t instanceIdx = 0; instanceIdx < queueFamilyProperties[familyIdx].queueCount && !added;
2012                      instanceIdx++)
2013                 {
2014                     VkQueueFlags readOpQueueFlags = readOp->getQueueFlags(m_opContext);
2015                     // Explicitly check if the readOp requires a graphics queue
2016                     if ((readOpQueueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
2017                     {
2018                         // If none of the queue families support graphics, report unsupported
2019                         bool graphicsSupported = false;
2020                         for (const auto &prop : queueFamilyProperties)
2021                         {
2022                             if ((prop.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
2023                             {
2024                                 graphicsSupported = true;
2025                                 break;
2026                             }
2027                         }
2028                         if (!graphicsSupported)
2029                         {
2030                             TCU_THROW(NotSupportedError, "Graphics queue required but not supported by the driver");
2031                         }
2032                     }
2033                     // If the readOpQueueFlags contain the transfer bit set then check if the queue supports graphics or compute operations before skipping this iteration.
2034                     // Because reporting transfer functionality is optional if a queue supports graphics or compute operations.
2035                     if (((readOpQueueFlags & queueFamilyProperties[familyIdx].queueFlags) != readOpQueueFlags) &&
2036                         (((readOpQueueFlags & VK_QUEUE_TRANSFER_BIT) == 0) ||
2037                          ((queueFamilyProperties[familyIdx].queueFlags &
2038                            (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) == 0)))
2039                         continue;
2040 
2041                     // Add the read operation on the universal queue, it should be
2042                     // submitted in order with regard to the write operation.
2043                     m_readIterations.push_back(makeSharedPtr(new QueueTimelineIteration(
2044                         readOp, lastSubmitValue, getDeviceQueue(vk, device, universalQueueFamilyIndex, 0),
2045                         universalQueueFamilyIndex, rng)));
2046                     lastSubmitValue = m_readIterations.back()->timelineValue;
2047 
2048                     added = true;
2049                 }
2050             }
2051 
2052             DE_ASSERT(added);
2053         }
2054 
2055         DE_ASSERT(m_copyIterations.size() == m_readIterations.size());
2056 
2057         // Now create the resources with the usage associated to the
2058         // operation performed on the resource.
2059         {
2060             uint32_t writeUsage = writeOp->getOutResourceUsageFlags();
2061 
2062             for (uint32_t copyOpIdx = 0; copyOpIdx < m_copyIterations.size(); copyOpIdx++)
2063             {
2064                 writeUsage |= m_copyIterations[copyOpIdx]->opSupport->getInResourceUsageFlags();
2065             }
2066             m_writeResource      = makeSharedPtr(new Resource(m_opContext, resourceDesc, writeUsage));
2067             m_writeIteration->op = makeSharedPtr(writeOp->build(m_opContext, *m_writeResource).release());
2068 
2069             for (uint32_t copyOpIdx = 0; copyOpIdx < m_copyIterations.size(); copyOpIdx++)
2070             {
2071                 uint32_t usage = m_copyIterations[copyOpIdx]->opSupport->getOutResourceUsageFlags() |
2072                                  m_readIterations[copyOpIdx]->opSupport->getInResourceUsageFlags();
2073 
2074                 m_copyResources.push_back(makeSharedPtr(new Resource(m_opContext, resourceDesc, usage)));
2075 
2076                 m_copyIterations[copyOpIdx]->op =
2077                     makeSharedPtr(m_copyIterations[copyOpIdx]
2078                                       ->opSupport->build(m_opContext, *m_writeResource, *m_copyResources[copyOpIdx])
2079                                       .release());
2080                 m_readIterations[copyOpIdx]->op =
2081                     makeSharedPtr(readOp->build(m_opContext, *m_copyResources[copyOpIdx]).release());
2082             }
2083         }
2084     }
2085 
~OneToNTestInstance()2086     ~OneToNTestInstance()
2087     {
2088     }
2089 
recordBarrier(const DeviceInterface & vk,VkCommandBuffer cmdBuffer,const QueueTimelineIteration & inIter,const QueueTimelineIteration & outIter,const Resource & resource,bool originalLayout)2090     void recordBarrier(const DeviceInterface &vk, VkCommandBuffer cmdBuffer, const QueueTimelineIteration &inIter,
2091                        const QueueTimelineIteration &outIter, const Resource &resource, bool originalLayout)
2092     {
2093         const SyncInfo writeSync                         = inIter.op->getOutSyncInfo();
2094         const SyncInfo readSync                          = outIter.op->getInSyncInfo();
2095         SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_type, vk, true);
2096 
2097         if (resource.getType() == RESOURCE_TYPE_IMAGE)
2098         {
2099             DE_ASSERT(writeSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
2100             DE_ASSERT(readSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
2101 
2102             const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
2103                 writeSync.stageMask,  // VkPipelineStageFlags2KHR            srcStageMask
2104                 writeSync.accessMask, // VkAccessFlags2KHR                srcAccessMask
2105                 readSync.stageMask,   // VkPipelineStageFlags2KHR            dstStageMask
2106                 readSync.accessMask,  // VkAccessFlags2KHR                dstAccessMask
2107                 originalLayout ? writeSync.imageLayout :
2108                                  readSync.imageLayout, // VkImageLayout                    oldLayout
2109                 readSync.imageLayout,                  // VkImageLayout                    newLayout
2110                 resource.getImage().handle,            // VkImage                            image
2111                 resource.getImage().subresourceRange,  // VkImageSubresourceRange            subresourceRange
2112                 inIter.queueFamilyIdx,                 // uint32_t                            srcQueueFamilyIndex
2113                 outIter.queueFamilyIdx                 // uint32_t                            destQueueFamilyIndex
2114             );
2115             VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(nullptr, nullptr, &imageMemoryBarrier2);
2116             synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
2117         }
2118         else
2119         {
2120             const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
2121                 writeSync.stageMask,         // VkPipelineStageFlags2KHR            srcStageMask
2122                 writeSync.accessMask,        // VkAccessFlags2KHR                srcAccessMask
2123                 readSync.stageMask,          // VkPipelineStageFlags2KHR            dstStageMask
2124                 readSync.accessMask,         // VkAccessFlags2KHR                dstAccessMask
2125                 resource.getBuffer().handle, // VkBuffer                            buffer
2126                 0,                           // VkDeviceSize                        offset
2127                 VK_WHOLE_SIZE,               // VkDeviceSize                        size
2128                 inIter.queueFamilyIdx,       // uint32_t                            srcQueueFamilyIndex
2129                 outIter.queueFamilyIdx       // uint32_t                            dstQueueFamilyIndex
2130             );
2131             VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(nullptr, &bufferMemoryBarrier2);
2132             synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo);
2133         }
2134     }
2135 
submit(const DeviceInterface & vk,VkCommandBuffer cmdBuffer,const QueueTimelineIteration & iter,VkSemaphore semaphore,const uint64_t * waitValues,const uint32_t waitValuesCount)2136     void submit(const DeviceInterface &vk, VkCommandBuffer cmdBuffer, const QueueTimelineIteration &iter,
2137                 VkSemaphore semaphore, const uint64_t *waitValues, const uint32_t waitValuesCount)
2138     {
2139         VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo[] = {
2140             makeCommonSemaphoreSubmitInfo(semaphore, waitValues[0], VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR),
2141             makeCommonSemaphoreSubmitInfo(semaphore, waitValues[1], VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR)};
2142         VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo =
2143             makeCommonSemaphoreSubmitInfo(semaphore, iter.timelineValue, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
2144 
2145         VkCommandBufferSubmitInfoKHR commandBufferSubmitInfo = makeCommonCommandBufferSubmitInfo(cmdBuffer);
2146         SynchronizationWrapperPtr synchronizationWrapper     = getSynchronizationWrapper(m_type, vk, true);
2147 
2148         synchronizationWrapper->addSubmitInfo(
2149             waitValuesCount,            // uint32_t                                waitSemaphoreInfoCount
2150             waitSemaphoreSubmitInfo,    // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
2151             1u,                         // uint32_t                                commandBufferInfoCount
2152             &commandBufferSubmitInfo,   // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
2153             1u,                         // uint32_t                                signalSemaphoreInfoCount
2154             &signalSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
2155             true, true);
2156 
2157         VK_CHECK(synchronizationWrapper->queueSubmit(iter.queue, VK_NULL_HANDLE));
2158     }
2159 
iterate(void)2160     tcu::TestStatus iterate(void)
2161     {
2162         const DeviceInterface &vk = *m_deviceDriver;
2163         const VkDevice device     = *m_device;
2164         const Unique<VkSemaphore> semaphore(createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE));
2165         Unique<VkCommandPool> writeCmdPool(createCommandPool(
2166             vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2167         Unique<VkCommandBuffer> writeCmdBuffer(makeCommandBuffer(vk, device, *writeCmdPool));
2168         std::vector<SharedPtr<Move<VkCommandPool>>> copyCmdPools;
2169         std::vector<SharedPtr<Move<VkCommandBuffer>>> copyPtrCmdBuffers;
2170         std::vector<SharedPtr<Move<VkCommandPool>>> readCmdPools;
2171         std::vector<SharedPtr<Move<VkCommandBuffer>>> readPtrCmdBuffers;
2172 
2173         for (uint32_t copyOpNdx = 0; copyOpNdx < m_copyIterations.size(); copyOpNdx++)
2174         {
2175             copyCmdPools.push_back(
2176                 makeVkSharedPtr(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
2177                                                   m_copyIterations[copyOpNdx]->queueFamilyIdx)));
2178             copyPtrCmdBuffers.push_back(makeVkSharedPtr(makeCommandBuffer(vk, device, **copyCmdPools.back())));
2179 
2180             readCmdPools.push_back(
2181                 makeVkSharedPtr(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
2182                                                   m_readIterations[copyOpNdx]->queueFamilyIdx)));
2183             readPtrCmdBuffers.push_back(makeVkSharedPtr(makeCommandBuffer(vk, device, **readCmdPools.back())));
2184         }
2185 
2186         // Randomize the data copied over.
2187         {
2188             const Data startData = m_writeIteration->op->getData();
2189             Data randomizedData;
2190             std::vector<uint8_t> dataArray;
2191 
2192             dataArray.resize(startData.size);
2193             randomizeData(dataArray, m_resourceDesc);
2194             randomizedData.size = dataArray.size();
2195             randomizedData.data = &dataArray[0];
2196             m_writeIteration->op->setData(randomizedData);
2197         }
2198 
2199         // Record command buffers
2200         {
2201             beginCommandBuffer(vk, *writeCmdBuffer);
2202             m_writeIteration->op->recordCommands(*writeCmdBuffer);
2203             endCommandBuffer(vk, *writeCmdBuffer);
2204 
2205             for (uint32_t copyOpIdx = 0; copyOpIdx < m_copyIterations.size(); copyOpIdx++)
2206             {
2207                 beginCommandBuffer(vk, **copyPtrCmdBuffers[copyOpIdx]);
2208                 recordBarrier(vk, **copyPtrCmdBuffers[copyOpIdx], *m_writeIteration, *m_copyIterations[copyOpIdx],
2209                               *m_writeResource, copyOpIdx == 0);
2210                 m_copyIterations[copyOpIdx]->op->recordCommands(**copyPtrCmdBuffers[copyOpIdx]);
2211                 endCommandBuffer(vk, **copyPtrCmdBuffers[copyOpIdx]);
2212             }
2213 
2214             for (uint32_t readOpIdx = 0; readOpIdx < m_readIterations.size(); readOpIdx++)
2215             {
2216                 beginCommandBuffer(vk, **readPtrCmdBuffers[readOpIdx]);
2217                 recordBarrier(vk, **readPtrCmdBuffers[readOpIdx], *m_copyIterations[readOpIdx],
2218                               *m_readIterations[readOpIdx], *m_copyResources[readOpIdx], true);
2219                 m_readIterations[readOpIdx]->op->recordCommands(**readPtrCmdBuffers[readOpIdx]);
2220                 endCommandBuffer(vk, **readPtrCmdBuffers[readOpIdx]);
2221             }
2222         }
2223 
2224         // Submit
2225         {
2226             submit(vk, *writeCmdBuffer, *m_writeIteration, *semaphore, &m_hostTimelineValue, 1);
2227             for (uint32_t copyOpIdx = 0; copyOpIdx < m_copyIterations.size(); copyOpIdx++)
2228             {
2229                 uint64_t waitValues[2] = {
2230                     m_writeIteration->timelineValue,
2231                     copyOpIdx > 0 ? m_copyIterations[copyOpIdx - 1]->timelineValue : 0,
2232                 };
2233 
2234                 submit(vk, **copyPtrCmdBuffers[copyOpIdx], *m_copyIterations[copyOpIdx], *semaphore, waitValues,
2235                        copyOpIdx > 0 ? 2 : 1);
2236             }
2237             for (uint32_t readOpIdx = 0; readOpIdx < m_readIterations.size(); readOpIdx++)
2238             {
2239                 uint64_t waitValues[2] = {
2240                     m_copyIterations[readOpIdx]->timelineValue,
2241                     readOpIdx > 0 ? m_readIterations[readOpIdx - 1]->timelineValue :
2242                                     m_copyIterations.back()->timelineValue,
2243                 };
2244 
2245                 submit(vk, **readPtrCmdBuffers[readOpIdx], *m_readIterations[readOpIdx], *semaphore, waitValues, 2);
2246             }
2247 
2248             // Kick off the whole chain from the host.
2249             hostSignal(vk, device, *semaphore, m_hostTimelineValue);
2250             VK_CHECK(vk.deviceWaitIdle(device));
2251         }
2252 
2253         {
2254             const Data expected = m_writeIteration->op->getData();
2255 
2256             for (uint32_t readOpIdx = 0; readOpIdx < m_readIterations.size(); readOpIdx++)
2257             {
2258                 const Data actual = m_readIterations[readOpIdx]->op->getData();
2259 
2260                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
2261                     return tcu::TestStatus::fail("Memory contents don't match");
2262             }
2263         }
2264 
2265         return tcu::TestStatus::pass("OK");
2266     }
2267 
2268 protected:
2269     SynchronizationType m_type;
2270     ResourceDescription m_resourceDesc;
2271     const Unique<VkDevice> &m_device;
2272     const Context &m_context;
2273 #ifndef CTS_USES_VULKANSC
2274     de::MovePtr<vk::DeviceDriver> m_deviceDriver;
2275 #else
2276     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> m_deviceDriver;
2277 #endif // CTS_USES_VULKANSC
2278     MovePtr<Allocator> m_allocator;
2279     OperationContext m_opContext;
2280     SharedPtr<QueueTimelineIteration> m_writeIteration;
2281     std::vector<SharedPtr<QueueTimelineIteration>> m_copyIterations;
2282     std::vector<SharedPtr<QueueTimelineIteration>> m_readIterations;
2283     SharedPtr<Resource> m_writeResource;
2284     std::vector<SharedPtr<Resource>> m_copyResources;
2285     uint64_t m_hostTimelineValue;
2286 };
2287 
2288 class OneToNTestCase : public TestCase
2289 {
2290 public:
OneToNTestCase(tcu::TestContext & testCtx,const std::string & name,SynchronizationType type,const ResourceDescription resourceDesc,const OperationName writeOp,const OperationName readOp,PipelineCacheData & pipelineCacheData)2291     OneToNTestCase(tcu::TestContext &testCtx, const std::string &name, SynchronizationType type,
2292                    const ResourceDescription resourceDesc, const OperationName writeOp, const OperationName readOp,
2293                    PipelineCacheData &pipelineCacheData)
2294         : TestCase(testCtx, name)
2295         , m_type(type)
2296         , m_resourceDesc(resourceDesc)
2297         , m_writeOp(makeOperationSupport(writeOp, resourceDesc).release())
2298         , m_readOp(makeOperationSupport(readOp, resourceDesc).release())
2299         , m_pipelineCacheData(pipelineCacheData)
2300     {
2301     }
2302 
checkSupport(Context & context) const2303     void checkSupport(Context &context) const override
2304     {
2305         context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
2306         if (m_type == SynchronizationType::SYNCHRONIZATION2)
2307             context.requireDeviceFunctionality("VK_KHR_synchronization2");
2308     }
2309 
initPrograms(SourceCollections & programCollection) const2310     void initPrograms(SourceCollections &programCollection) const override
2311     {
2312         m_writeOp->initPrograms(programCollection);
2313         m_readOp->initPrograms(programCollection);
2314 
2315         for (uint32_t copyOpNdx = 0; copyOpNdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpNdx++)
2316         {
2317             if (isResourceSupported(s_copyOps[copyOpNdx], m_resourceDesc))
2318                 makeOperationSupport(s_copyOps[copyOpNdx], m_resourceDesc)->initPrograms(programCollection);
2319         }
2320     }
2321 
createInstance(Context & context) const2322     TestInstance *createInstance(Context &context) const override
2323     {
2324         return new OneToNTestInstance(context, m_type, m_resourceDesc, m_writeOp, m_readOp, m_pipelineCacheData);
2325     }
2326 
2327 private:
2328     SynchronizationType m_type;
2329     const ResourceDescription m_resourceDesc;
2330     const SharedPtr<OperationSupport> m_writeOp;
2331     const SharedPtr<OperationSupport> m_readOp;
2332     PipelineCacheData &m_pipelineCacheData;
2333 };
2334 
2335 class OneToNTests : public tcu::TestCaseGroup
2336 {
2337 public:
OneToNTests(tcu::TestContext & testCtx,SynchronizationType type)2338     OneToNTests(tcu::TestContext &testCtx, SynchronizationType type)
2339         : tcu::TestCaseGroup(testCtx, "one_to_n")
2340         , m_type(type)
2341     {
2342     }
2343 
init(void)2344     void init(void)
2345     {
2346         static const OperationName writeOps[] = {
2347             OPERATION_NAME_WRITE_COPY_BUFFER,
2348             OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE,
2349             OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER,
2350             OPERATION_NAME_WRITE_COPY_IMAGE,
2351             OPERATION_NAME_WRITE_BLIT_IMAGE,
2352             OPERATION_NAME_WRITE_SSBO_VERTEX,
2353             OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL,
2354             OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION,
2355             OPERATION_NAME_WRITE_SSBO_GEOMETRY,
2356             OPERATION_NAME_WRITE_SSBO_FRAGMENT,
2357             OPERATION_NAME_WRITE_SSBO_COMPUTE,
2358             OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT,
2359             OPERATION_NAME_WRITE_IMAGE_VERTEX,
2360             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL,
2361             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION,
2362             OPERATION_NAME_WRITE_IMAGE_GEOMETRY,
2363             OPERATION_NAME_WRITE_IMAGE_FRAGMENT,
2364             OPERATION_NAME_WRITE_IMAGE_COMPUTE,
2365             OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT,
2366         };
2367         static const OperationName readOps[] = {
2368             OPERATION_NAME_READ_COPY_BUFFER,
2369             OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE,
2370             OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER,
2371             OPERATION_NAME_READ_COPY_IMAGE,
2372             OPERATION_NAME_READ_BLIT_IMAGE,
2373             OPERATION_NAME_READ_UBO_VERTEX,
2374             OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL,
2375             OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION,
2376             OPERATION_NAME_READ_UBO_GEOMETRY,
2377             OPERATION_NAME_READ_UBO_FRAGMENT,
2378             OPERATION_NAME_READ_UBO_COMPUTE,
2379             OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT,
2380             OPERATION_NAME_READ_SSBO_VERTEX,
2381             OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL,
2382             OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION,
2383             OPERATION_NAME_READ_SSBO_GEOMETRY,
2384             OPERATION_NAME_READ_SSBO_FRAGMENT,
2385             OPERATION_NAME_READ_SSBO_COMPUTE,
2386             OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT,
2387             OPERATION_NAME_READ_IMAGE_VERTEX,
2388             OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL,
2389             OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION,
2390             OPERATION_NAME_READ_IMAGE_GEOMETRY,
2391             OPERATION_NAME_READ_IMAGE_FRAGMENT,
2392             OPERATION_NAME_READ_IMAGE_COMPUTE,
2393             OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT,
2394             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW,
2395             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED,
2396             OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH,
2397             OPERATION_NAME_READ_VERTEX_INPUT,
2398         };
2399 
2400         for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(writeOps); ++writeOpNdx)
2401             for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(readOps); ++readOpNdx)
2402             {
2403                 const OperationName writeOp   = writeOps[writeOpNdx];
2404                 const OperationName readOp    = readOps[readOpNdx];
2405                 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
2406                 bool empty                    = true;
2407 
2408                 de::MovePtr<tcu::TestCaseGroup> opGroup(new tcu::TestCaseGroup(m_testCtx, opGroupName.c_str()));
2409 
2410                 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
2411                 {
2412                     const ResourceDescription &resource = s_resources[resourceNdx];
2413                     std::string name                    = getResourceName(resource);
2414 
2415                     if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
2416                     {
2417                         opGroup->addChild(new OneToNTestCase(m_testCtx, name, m_type, resource, writeOp, readOp,
2418                                                              m_pipelineCacheData));
2419                         empty = false;
2420                     }
2421                 }
2422                 if (!empty)
2423                     addChild(opGroup.release());
2424             }
2425     }
2426 
deinit(void)2427     void deinit(void)
2428     {
2429         cleanupGroup();
2430     }
2431 
2432 private:
2433     SynchronizationType m_type;
2434 
2435     // synchronization.op tests share pipeline cache data to speed up test
2436     // execution.
2437     PipelineCacheData m_pipelineCacheData;
2438 };
2439 
2440 #ifndef CTS_USES_VULKANSC
2441 
2442 // Make a nonzero initial value for a semaphore. semId is assigned to each semaphore by callers.
getInitialValue(uint32_t semId)2443 uint64_t getInitialValue(uint32_t semId)
2444 {
2445     return (semId + 1ull) * 1000ull;
2446 }
2447 
2448 struct SparseBindParams
2449 {
2450     uint32_t numWaitSems;
2451     uint32_t numSignalSems;
2452 };
2453 
2454 class SparseBindCase : public vkt::TestCase
2455 {
2456 public:
2457     SparseBindCase(tcu::TestContext &testCtx, const std::string &name, const SparseBindParams &params);
~SparseBindCase(void)2458     virtual ~SparseBindCase(void)
2459     {
2460     }
2461 
2462     virtual TestInstance *createInstance(Context &context) const;
2463     virtual void checkSupport(Context &context) const;
2464 
2465 private:
2466     SparseBindParams m_params;
2467 };
2468 
2469 class SparseBindInstance : public vkt::TestInstance
2470 {
2471 public:
2472     SparseBindInstance(Context &context, const SparseBindParams &params);
~SparseBindInstance(void)2473     virtual ~SparseBindInstance(void)
2474     {
2475     }
2476 
2477     virtual tcu::TestStatus iterate(void);
2478 
2479 private:
2480     SparseBindParams m_params;
2481 };
2482 
SparseBindCase(tcu::TestContext & testCtx,const std::string & name,const SparseBindParams & params)2483 SparseBindCase::SparseBindCase(tcu::TestContext &testCtx, const std::string &name, const SparseBindParams &params)
2484     : vkt::TestCase(testCtx, name)
2485     , m_params(params)
2486 {
2487 }
2488 
createInstance(Context & context) const2489 TestInstance *SparseBindCase::createInstance(Context &context) const
2490 {
2491     return new SparseBindInstance(context, m_params);
2492 }
2493 
checkSupport(Context & context) const2494 void SparseBindCase::checkSupport(Context &context) const
2495 {
2496     // Check support for sparse binding and timeline semaphores.
2497     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING);
2498     context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
2499 }
2500 
SparseBindInstance(Context & context,const SparseBindParams & params)2501 SparseBindInstance::SparseBindInstance(Context &context, const SparseBindParams &params)
2502     : vkt::TestInstance(context)
2503     , m_params(params)
2504 {
2505 }
2506 
queueBindSparse(const vk::DeviceInterface & vkd,vk::VkQueue queue,uint32_t bindInfoCount,const vk::VkBindSparseInfo * pBindInfo)2507 void queueBindSparse(const vk::DeviceInterface &vkd, vk::VkQueue queue, uint32_t bindInfoCount,
2508                      const vk::VkBindSparseInfo *pBindInfo)
2509 {
2510     VK_CHECK(vkd.queueBindSparse(queue, bindInfoCount, pBindInfo, VK_NULL_HANDLE));
2511 }
2512 
2513 #endif // CTS_USES_VULKANSC
2514 
2515 struct SemaphoreWithInitial
2516 {
2517     vk::Move<vk::VkSemaphore> semaphore;
2518     uint64_t initialValue;
2519 
SemaphoreWithInitialvkt::synchronization::__anoncf99eb0b0111::SemaphoreWithInitial2520     SemaphoreWithInitial(vk::Move<vk::VkSemaphore> &&sem, uint64_t initVal) : semaphore(sem), initialValue(initVal)
2521     {
2522     }
2523 
SemaphoreWithInitialvkt::synchronization::__anoncf99eb0b0111::SemaphoreWithInitial2524     SemaphoreWithInitial(SemaphoreWithInitial &&other) : semaphore(other.semaphore), initialValue(other.initialValue)
2525     {
2526     }
2527 };
2528 
2529 using SemaphoreVec = std::vector<SemaphoreWithInitial>;
2530 using PlainSemVec  = std::vector<vk::VkSemaphore>;
2531 using ValuesVec    = std::vector<uint64_t>;
2532 
2533 #ifndef CTS_USES_VULKANSC
2534 
getHandles(const SemaphoreVec & semVec)2535 PlainSemVec getHandles(const SemaphoreVec &semVec)
2536 {
2537     PlainSemVec handlesVec;
2538     handlesVec.reserve(semVec.size());
2539 
2540     const auto conversion = [](const SemaphoreWithInitial &s) { return s.semaphore.get(); };
2541     std::transform(begin(semVec), end(semVec), std::back_inserter(handlesVec), conversion);
2542 
2543     return handlesVec;
2544 }
2545 
getInitialValues(const SemaphoreVec & semVec)2546 ValuesVec getInitialValues(const SemaphoreVec &semVec)
2547 {
2548     ValuesVec initialValues;
2549     initialValues.reserve(semVec.size());
2550 
2551     const auto conversion = [](const SemaphoreWithInitial &s) { return s.initialValue; };
2552     std::transform(begin(semVec), end(semVec), std::back_inserter(initialValues), conversion);
2553 
2554     return initialValues;
2555 }
2556 
2557 // Increases values in the vector by one.
getNextValues(const ValuesVec & values)2558 ValuesVec getNextValues(const ValuesVec &values)
2559 {
2560     ValuesVec nextValues;
2561     nextValues.reserve(values.size());
2562 
2563     std::transform(begin(values), end(values), std::back_inserter(nextValues), [](uint64_t v) { return v + 1ull; });
2564     return nextValues;
2565 }
2566 
createTimelineSemaphore(const vk::DeviceInterface & vkd,vk::VkDevice device,uint32_t semId)2567 SemaphoreWithInitial createTimelineSemaphore(const vk::DeviceInterface &vkd, vk::VkDevice device, uint32_t semId)
2568 {
2569     const auto initialValue = getInitialValue(semId);
2570     return SemaphoreWithInitial(createSemaphoreType(vkd, device, vk::VK_SEMAPHORE_TYPE_TIMELINE, 0u, initialValue),
2571                                 initialValue);
2572 }
2573 
2574 // Signal the given semaphores with the corresponding values.
hostSignal(const vk::DeviceInterface & vkd,vk::VkDevice device,const PlainSemVec & semaphores,const ValuesVec & signalValues)2575 void hostSignal(const vk::DeviceInterface &vkd, vk::VkDevice device, const PlainSemVec &semaphores,
2576                 const ValuesVec &signalValues)
2577 {
2578     DE_ASSERT(semaphores.size() == signalValues.size());
2579 
2580     for (size_t i = 0; i < semaphores.size(); ++i)
2581         hostSignal(vkd, device, semaphores[i], signalValues[i]);
2582 }
2583 
2584 // Wait for the given semaphores and their corresponding values.
hostWait(const vk::DeviceInterface & vkd,vk::VkDevice device,const PlainSemVec & semaphores,const ValuesVec & waitValues)2585 void hostWait(const vk::DeviceInterface &vkd, vk::VkDevice device, const PlainSemVec &semaphores,
2586               const ValuesVec &waitValues)
2587 {
2588     DE_ASSERT(semaphores.size() == waitValues.size() && !semaphores.empty());
2589 
2590     constexpr uint64_t kTimeout = 10000000000ull; // 10 seconds in nanoseconds.
2591 
2592     const vk::VkSemaphoreWaitInfo waitInfo = {
2593         vk::VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
2594         nullptr,                                   // const void* pNext;
2595         0u,                                        // VkSemaphoreWaitFlags flags;
2596         static_cast<uint32_t>(semaphores.size()),  // uint32_t semaphoreCount;
2597         semaphores.data(),                         // const VkSemaphore* pSemaphores;
2598         waitValues.data(),                         // const uint64_t* pValues;
2599     };
2600     VK_CHECK(vkd.waitSemaphores(device, &waitInfo, kTimeout));
2601 }
2602 
iterate(void)2603 tcu::TestStatus SparseBindInstance::iterate(void)
2604 {
2605     const auto &vkd   = m_context.getDeviceInterface();
2606     const auto device = m_context.getDevice();
2607     const auto queue  = m_context.getSparseQueue();
2608 
2609     SemaphoreVec waitSemaphores;
2610     SemaphoreVec signalSemaphores;
2611 
2612     // Create as many semaphores as needed to wait and signal.
2613     for (uint32_t i = 0; i < m_params.numWaitSems; ++i)
2614         waitSemaphores.emplace_back(createTimelineSemaphore(vkd, device, i));
2615     for (uint32_t i = 0; i < m_params.numSignalSems; ++i)
2616         signalSemaphores.emplace_back(createTimelineSemaphore(vkd, device, i + m_params.numWaitSems));
2617 
2618     // Get handles for all semaphores.
2619     const auto waitSemHandles   = getHandles(waitSemaphores);
2620     const auto signalSemHandles = getHandles(signalSemaphores);
2621 
2622     // Get initial values for all semaphores.
2623     const auto waitSemValues   = getInitialValues(waitSemaphores);
2624     const auto signalSemValues = getInitialValues(signalSemaphores);
2625 
2626     // Get next expected values for all semaphores.
2627     const auto waitNextValues   = getNextValues(waitSemValues);
2628     const auto signalNextValues = getNextValues(signalSemValues);
2629 
2630     const vk::VkTimelineSemaphoreSubmitInfo timeLineSubmitInfo = {
2631         vk::VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,           // VkStructureType sType;
2632         nullptr,                                                        // const void* pNext;
2633         static_cast<uint32_t>(waitNextValues.size()),                   // uint32_t waitSemaphoreValueCount;
2634         (waitNextValues.empty() ? nullptr : waitNextValues.data()),     // const uint64_t* pWaitSemaphoreValues;
2635         static_cast<uint32_t>(signalNextValues.size()),                 // uint32_t signalSemaphoreValueCount;
2636         (signalNextValues.empty() ? nullptr : signalNextValues.data()), // const uint64_t* pSignalSemaphoreValues;
2637     };
2638 
2639     const vk::VkBindSparseInfo bindInfo = {
2640         vk::VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,                     // VkStructureType sType;
2641         &timeLineSubmitInfo,                                        // const void* pNext;
2642         static_cast<uint32_t>(waitSemHandles.size()),               // uint32_t waitSemaphoreCount;
2643         (waitSemHandles.empty() ? nullptr : waitSemHandles.data()), // const VkSemaphore* pWaitSemaphores;
2644         0u,                                                         // uint32_t bufferBindCount;
2645         nullptr,                                                    // const VkSparseBufferMemoryBindInfo* pBufferBinds;
2646         0u,                                                         // uint32_t imageOpaqueBindCount;
2647         nullptr,                                        // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
2648         0u,                                             // uint32_t imageBindCount;
2649         nullptr,                                        // const VkSparseImageMemoryBindInfo* pImageBinds;
2650         static_cast<uint32_t>(signalSemHandles.size()), // uint32_t signalSemaphoreCount;
2651         (signalSemHandles.empty() ? nullptr : signalSemHandles.data()), // const VkSemaphore* pSignalSemaphores;
2652     };
2653     queueBindSparse(vkd, queue, 1u, &bindInfo);
2654 
2655     // If the device needs to wait and signal, check the signal semaphores have not been signaled yet.
2656     if (!waitSemaphores.empty() && !signalSemaphores.empty())
2657     {
2658         uint64_t value;
2659         for (size_t i = 0; i < signalSemaphores.size(); ++i)
2660         {
2661             value = 0;
2662             VK_CHECK(vkd.getSemaphoreCounterValue(device, signalSemHandles[i], &value));
2663 
2664             if (!value)
2665                 TCU_FAIL("Invalid value obtained from vkGetSemaphoreCounterValue()");
2666 
2667             if (value != signalSemValues[i])
2668             {
2669                 std::ostringstream msg;
2670                 msg << "vkQueueBindSparse() may not have waited before signaling semaphore " << i << " (expected value "
2671                     << signalSemValues[i] << " but obtained " << value << ")";
2672                 TCU_FAIL(msg.str());
2673             }
2674         }
2675     }
2676 
2677     // Signal semaphores the sparse bind command is waiting on.
2678     hostSignal(vkd, device, waitSemHandles, waitNextValues);
2679 
2680     // Wait for semaphores the sparse bind command is supposed to signal.
2681     if (!signalSemaphores.empty())
2682         hostWait(vkd, device, signalSemHandles, signalNextValues);
2683 
2684     VK_CHECK(vkd.deviceWaitIdle(device));
2685     return tcu::TestStatus::pass("Pass");
2686 }
2687 
2688 class SparseBindGroup : public tcu::TestCaseGroup
2689 {
2690 public:
2691     // vkQueueBindSparse combined with timeline semaphores
SparseBindGroup(tcu::TestContext & testCtx)2692     SparseBindGroup(tcu::TestContext &testCtx) : tcu::TestCaseGroup(testCtx, "sparse_bind")
2693     {
2694     }
2695 
init(void)2696     virtual void init(void)
2697     {
2698         static const struct
2699         {
2700             uint32_t waitSems;
2701             uint32_t sigSems;
2702             std::string name;
2703         } kSparseBindCases[] = {
2704             // No semaphores to wait for or signal
2705             {0u, 0u, "no_sems"},
2706             // Signal semaphore without waiting for any other
2707             {0u, 1u, "no_wait_sig"},
2708             // Wait for semaphore but do not signal any other
2709             {1u, 0u, "wait_no_sig"},
2710             // Wait for semaphore and signal a second one
2711             {1u, 1u, "wait_and_sig"},
2712             // Wait for two semaphores and signal two other ones
2713             {2u, 2u, "wait_and_sig_2"},
2714         };
2715 
2716         for (int i = 0; i < DE_LENGTH_OF_ARRAY(kSparseBindCases); ++i)
2717             addChild(new SparseBindCase(m_testCtx, kSparseBindCases[i].name,
2718                                         SparseBindParams{kSparseBindCases[i].waitSems, kSparseBindCases[i].sigSems}));
2719     }
2720 };
2721 
2722 #endif // CTS_USES_VULKANSC
2723 
2724 } // namespace
2725 
createTimelineSemaphoreTests(tcu::TestContext & testCtx)2726 tcu::TestCaseGroup *createTimelineSemaphoreTests(tcu::TestContext &testCtx)
2727 {
2728     const SynchronizationType type(SynchronizationType::LEGACY);
2729     de::MovePtr<tcu::TestCaseGroup> basicTests(new tcu::TestCaseGroup(testCtx, "timeline_semaphore"));
2730 
2731     basicTests->addChild(new LegacyDeviceHostTests(testCtx));
2732     basicTests->addChild(new OneToNTests(testCtx, type));
2733     basicTests->addChild(new WaitBeforeSignalTests(testCtx, type));
2734     basicTests->addChild(new WaitTests(testCtx, type));
2735 #ifndef CTS_USES_VULKANSC
2736     basicTests->addChild(new SparseBindGroup(testCtx));
2737 #endif // CTS_USES_VULKANSC
2738 
2739     return basicTests.release();
2740 }
2741 
createSynchronization2TimelineSemaphoreTests(tcu::TestContext & testCtx)2742 tcu::TestCaseGroup *createSynchronization2TimelineSemaphoreTests(tcu::TestContext &testCtx)
2743 {
2744     const SynchronizationType type(SynchronizationType::SYNCHRONIZATION2);
2745     de::MovePtr<tcu::TestCaseGroup> basicTests(new tcu::TestCaseGroup(testCtx, "timeline_semaphore"));
2746 
2747     basicTests->addChild(new Sytnchronization2DeviceHostTests(testCtx));
2748     basicTests->addChild(new OneToNTests(testCtx, type));
2749     basicTests->addChild(new WaitBeforeSignalTests(testCtx, type));
2750     basicTests->addChild(new WaitTests(testCtx, type));
2751 
2752     return basicTests.release();
2753 }
2754 
2755 } // namespace synchronization
2756 } // namespace vkt
2757