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