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