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