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