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