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