• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Queue bind sparse tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSparseResourcesQueueBindSparseTests.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestGroupUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 
35 #include "deUniquePtr.hpp"
36 #include "deSharedPtr.hpp"
37 
38 #include <string>
39 #include <vector>
40 
41 using namespace vk;
42 using de::MovePtr;
43 
44 namespace vkt
45 {
46 namespace sparse
47 {
48 namespace
49 {
50 
51 typedef de::SharedPtr<Unique<VkSemaphore> >	SemaphoreSp;
52 typedef de::SharedPtr<Unique<VkFence> >		FenceSp;
53 
54 struct TestParams
55 {
56 	deUint32	numQueues;					//! use 2 or more to sync between different queues
57 	deUint32	numWaitSemaphores;
58 	deUint32	numSignalSemaphores;
59 	bool		emptySubmission;			//! will make an empty bind sparse submission
60 	bool		bindSparseUseFence;
61 };
62 
63 struct QueueSubmission
64 {
65 	union InfoUnion
66 	{
67 		VkSubmitInfo		regular;
68 		VkBindSparseInfo	sparse;
69 	};
70 
71 	const Queue*			queue;
72 	bool					isSparseBinding;
73 	InfoUnion				info;
74 };
75 
makeSubmissionRegular(const Queue * queue,const deUint32 numWaitSemaphores,const VkSemaphore * pWaitSemaphore,const VkPipelineStageFlags * pWaitDstStageMask,const deUint32 numSignalSemaphores,const VkSemaphore * pSignalSemaphore)76 QueueSubmission makeSubmissionRegular	(const Queue*					queue,
77 										 const deUint32					numWaitSemaphores,
78 										 const VkSemaphore*				pWaitSemaphore,
79 										 const VkPipelineStageFlags*	pWaitDstStageMask,
80 										 const deUint32					numSignalSemaphores,
81 										 const VkSemaphore*				pSignalSemaphore)
82 {
83 	const VkSubmitInfo submitInfo =
84 	{
85 		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
86 		DE_NULL,						// const void*					pNext;
87 		numWaitSemaphores,				// uint32_t						waitSemaphoreCount;
88 		pWaitSemaphore,					// const VkSemaphore*			pWaitSemaphores;
89 		pWaitDstStageMask,				// const VkPipelineStageFlags*	pWaitDstStageMask;
90 		0u,								// uint32_t						commandBufferCount;
91 		DE_NULL,						// const VkCommandBuffer*		pCommandBuffers;
92 		numSignalSemaphores,			// uint32_t						signalSemaphoreCount;
93 		pSignalSemaphore,				// const VkSemaphore*			pSignalSemaphores;
94 	};
95 
96 	QueueSubmission submission;
97 	submission.isSparseBinding	= false;
98 	submission.queue			= queue;
99 	submission.info.regular		= submitInfo;
100 
101 	return submission;
102 }
103 
makeSubmissionSparse(const Queue * queue,const deUint32 numWaitSemaphores,const VkSemaphore * pWaitSemaphore,const deUint32 numSignalSemaphores,const VkSemaphore * pSignalSemaphore)104 QueueSubmission makeSubmissionSparse	(const Queue*		queue,
105 										 const deUint32		numWaitSemaphores,
106 										 const VkSemaphore*	pWaitSemaphore,
107 										 const deUint32		numSignalSemaphores,
108 										 const VkSemaphore*	pSignalSemaphore)
109 {
110 	const VkBindSparseInfo bindInfo =
111 	{
112 		VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,			// VkStructureType							sType;
113 		DE_NULL,									// const void*								pNext;
114 		numWaitSemaphores,							// uint32_t									waitSemaphoreCount;
115 		pWaitSemaphore,								// const VkSemaphore*						pWaitSemaphores;
116 		0u,											// uint32_t									bufferBindCount;
117 		DE_NULL,									// const VkSparseBufferMemoryBindInfo*		pBufferBinds;
118 		0u,											// uint32_t									imageOpaqueBindCount;
119 		DE_NULL,									// const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
120 		0u,											// uint32_t									imageBindCount;
121 		DE_NULL,									// const VkSparseImageMemoryBindInfo*		pImageBinds;
122 		numSignalSemaphores,						// uint32_t									signalSemaphoreCount;
123 		pSignalSemaphore,							// const VkSemaphore*						pSignalSemaphores;
124 	};
125 
126 	QueueSubmission submission;
127 	submission.isSparseBinding	= true;
128 	submission.queue			= queue;
129 	submission.info.sparse		= bindInfo;
130 
131 	return submission;
132 }
133 
waitForFences(const DeviceInterface & vk,const VkDevice device,const std::vector<FenceSp> & fences)134 bool waitForFences (const DeviceInterface& vk, const VkDevice device, const std::vector<FenceSp>& fences)
135 {
136 	for (std::vector<FenceSp>::const_iterator fenceSpIter = fences.begin(); fenceSpIter != fences.end(); ++fenceSpIter)
137 	{
138 		if (vk.waitForFences(device, 1u, &(***fenceSpIter), VK_TRUE, ~0ull) != VK_SUCCESS)
139 			return false;
140 	}
141 	return true;
142 }
143 
144 class SparseQueueBindTestInstance : public SparseResourcesBaseInstance
145 {
146 public:
SparseQueueBindTestInstance(Context & context,const TestParams & params)147 	SparseQueueBindTestInstance (Context &context, const TestParams& params)
148 		: SparseResourcesBaseInstance	(context)
149 		, m_params						(params)
150 	{
151 		DE_ASSERT(m_params.numQueues > 0u);		// must use at least one queue
152 		DE_ASSERT(!m_params.emptySubmission || (m_params.numWaitSemaphores == 0u && m_params.numSignalSemaphores == 0u));	// can't use semaphores if we don't submit
153 	}
154 
iterate(void)155 	tcu::TestStatus iterate (void)
156 	{
157 		const Queue*				sparseQueue	= DE_NULL;
158 		std::vector<const Queue*>	otherQueues;
159 
160 		// Determine required queues and create a device that supports them
161 		{
162 			QueueRequirementsVec requirements;
163 			requirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
164 			requirements.push_back(QueueRequirements((VkQueueFlags)0, m_params.numQueues));		// any queue flags
165 
166 			createDeviceSupportingQueues(requirements);
167 
168 			sparseQueue = &getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0u);
169 
170 			// We probably have picked the sparse queue again, so filter it out
171 			for (deUint32 queueNdx = 0u; queueNdx < m_params.numQueues; ++queueNdx)
172 			{
173 				const Queue* queue = &getQueue((VkQueueFlags)0, queueNdx);
174 				if (queue->queueHandle != sparseQueue->queueHandle)
175 					otherQueues.push_back(queue);
176 			}
177 		}
178 
179 		const DeviceInterface&				vk = getDeviceInterface();
180 
181 		std::vector<SemaphoreSp>			allSemaphores;
182 		std::vector<VkSemaphore>			waitSemaphores;
183 		std::vector<VkSemaphore>			signalSemaphores;
184 		std::vector<VkPipelineStageFlags>	signalSemaphoresWaitDstStageMask;
185 		std::vector<QueueSubmission>		queueSubmissions;
186 
187 		for (deUint32 i = 0; i < m_params.numWaitSemaphores; ++i)
188 		{
189 			allSemaphores.push_back(makeVkSharedPtr(createSemaphore(vk, getDevice())));
190 			waitSemaphores.push_back(**allSemaphores.back());
191 		}
192 
193 		for (deUint32 i = 0; i < m_params.numSignalSemaphores; ++i)
194 		{
195 			allSemaphores.push_back(makeVkSharedPtr(createSemaphore(vk, getDevice())));
196 			signalSemaphores.push_back(**allSemaphores.back());
197 			signalSemaphoresWaitDstStageMask.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
198 		}
199 
200 		// Prepare submissions: signal semaphores for the sparse bind operation
201 		{
202 			deUint32 numQueues		= 1u + static_cast<deUint32>(otherQueues.size());
203 			deUint32 numSemaphores	= m_params.numWaitSemaphores;
204 
205 			while (numSemaphores > 0u && numQueues > 0u)
206 			{
207 				if (numQueues == 1u)	// sparse queue is assigned last
208 				{
209 					// sparse queue can handle regular submissions as well
210 					queueSubmissions.push_back(makeSubmissionRegular(
211 						sparseQueue, 0u, DE_NULL, DE_NULL, numSemaphores, getDataOrNullptr(waitSemaphores)));
212 					numSemaphores	= 0u;
213 					numQueues		= 0u;
214 				}
215 				else
216 				{
217 					queueSubmissions.push_back(makeSubmissionRegular(
218 						otherQueues[numQueues - 2], 0u, DE_NULL, DE_NULL, 1u, getDataOrNullptr(waitSemaphores, numSemaphores - 1)));
219 					--numQueues;
220 					--numSemaphores;
221 				}
222 			}
223 		}
224 
225 		// Prepare submission: bind sparse
226 		if (!m_params.emptySubmission)
227 		{
228 			queueSubmissions.push_back(makeSubmissionSparse(
229 				sparseQueue, m_params.numWaitSemaphores, getDataOrNullptr(waitSemaphores), m_params.numSignalSemaphores, getDataOrNullptr(signalSemaphores)));
230 		}
231 		else
232 		{
233 			// an unused submission, won't be used in a call to vkQueueBindSparse
234 			queueSubmissions.push_back(makeSubmissionSparse(sparseQueue, 0u, DE_NULL, 0u, DE_NULL));
235 		}
236 
237 		// Prepare submissions: wait on semaphores signaled by the sparse bind operation
238 		if (!m_params.emptySubmission)
239 		{
240 			deUint32 numQueues		= 1u + static_cast<deUint32>(otherQueues.size());
241 			deUint32 numSemaphores	= m_params.numSignalSemaphores;
242 
243 			while (numSemaphores > 0u && numQueues > 0u)
244 			{
245 				if (numQueues == 1u)
246 				{
247 					queueSubmissions.push_back(makeSubmissionRegular(
248 						sparseQueue, numSemaphores, getDataOrNullptr(signalSemaphores), getDataOrNullptr(signalSemaphoresWaitDstStageMask), 0u, DE_NULL));
249 					numSemaphores	= 0u;
250 					numQueues		= 0u;
251 				}
252 				else
253 				{
254 					queueSubmissions.push_back(makeSubmissionRegular(
255 						otherQueues[numQueues - 2], 1u, getDataOrNullptr(signalSemaphores, numSemaphores - 1), getDataOrNullptr(signalSemaphoresWaitDstStageMask, numSemaphores - 1), 0u, DE_NULL));
256 					--numQueues;
257 					--numSemaphores;
258 				}
259 			}
260 		}
261 
262 		// Submit to queues
263 		{
264 			std::vector<FenceSp>	regularFences;
265 			std::vector<FenceSp>	bindSparseFences;
266 
267 			for (std::vector<QueueSubmission>::const_iterator submissionIter = queueSubmissions.begin(); submissionIter != queueSubmissions.end(); ++submissionIter)
268 			{
269 				if (submissionIter->isSparseBinding)
270 				{
271 					VkFence fence = DE_NULL;
272 
273 					if (m_params.bindSparseUseFence)
274 					{
275 						bindSparseFences.push_back(makeVkSharedPtr(createFence(vk, getDevice())));
276 						fence = **bindSparseFences.back();
277 					}
278 
279 					if (m_params.emptySubmission)
280 						VK_CHECK(vk.queueBindSparse(submissionIter->queue->queueHandle, 0u, DE_NULL, fence));
281 					else
282 						VK_CHECK(vk.queueBindSparse(submissionIter->queue->queueHandle, 1u, &submissionIter->info.sparse, fence));
283 				}
284 				else
285 				{
286 					regularFences.push_back(makeVkSharedPtr(createFence(vk, getDevice())));
287 					VK_CHECK(vk.queueSubmit(submissionIter->queue->queueHandle, 1u, &submissionIter->info.regular, **regularFences.back()));
288 				}
289 			}
290 
291 			if (!waitForFences(vk, getDevice(), bindSparseFences))
292 				return tcu::TestStatus::fail("vkQueueBindSparse didn't signal the fence");
293 
294 			if (!waitForFences(vk, getDevice(), regularFences))
295 				return tcu::TestStatus::fail("Some fences weren't signaled (vkQueueBindSparse didn't signal semaphores?)");
296 		}
297 
298 		// May return an error if some waitSemaphores didn't get signaled
299 		VK_CHECK(vk.deviceWaitIdle(getDevice()));
300 
301 		return tcu::TestStatus::pass("Pass");
302 	}
303 
304 private:
305 	const TestParams	m_params;
306 };
307 
308 class SparseQueueBindTest : public TestCase
309 {
310 public:
SparseQueueBindTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)311 					SparseQueueBindTest	(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
312 		: TestCase	(testCtx, name, description)
313 		, m_params	(params)
314 	{
315 		DE_ASSERT(params.numQueues > 0u);
316 		DE_ASSERT(params.numQueues == 1u || m_params.numWaitSemaphores > 0u || m_params.numSignalSemaphores > 0u);	// without any semaphores, only sparse queue will be used
317 	}
318 
createInstance(Context & context) const319 	TestInstance*	createInstance		(Context& context) const
320 	{
321 		return new SparseQueueBindTestInstance(context, m_params);
322 	}
323 
checkSupport(Context & context) const324 	virtual void	checkSupport		(Context& context) const
325 	{
326 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING);
327 	}
328 
329 private:
330 	const TestParams	m_params;
331 };
332 
populateTestGroup(tcu::TestCaseGroup * group)333 void populateTestGroup(tcu::TestCaseGroup* group)
334 {
335 	const struct
336 	{
337 		std::string		name;
338 		TestParams		params;
339 		std::string		description;
340 	} cases[] =
341 	{
342 		// case name									// numQueues, numWaitSems, numSignalSems, emptySubmission, checkFence
343 		{ "no_dependency",								{	1u,	0u,	0u,	false,	false,	}, "submit without any semaphores", },
344 		{ "no_dependency_fence",						{	1u,	0u,	0u,	false,	true,	}, "submit without any semaphores, signal a fence", },
345 
346 		{ "single_queue_wait_one",						{	1u,	1u,	0u,	false,	true,	}, "only sparse queue, wait for semaphore(s)", },
347 		{ "single_queue_wait_many",						{	1u,	3u,	0u,	false,	true,	}, "only sparse queue, wait for semaphore(s)", },
348 		{ "single_queue_signal_one",					{	1u,	0u,	1u,	false,	true,	}, "only sparse queue, signal semaphore(s)", },
349 		{ "single_queue_signal_many",					{	1u,	0u,	3u,	false,	true,	}, "only sparse queue, signal semaphore(s)", },
350 		{ "single_queue_wait_one_signal_one",			{	1u,	1u,	1u,	false,	true,	}, "only sparse queue, wait for and signal semaphore(s)", },
351 		{ "single_queue_wait_many_signal_many",			{	1u,	2u,	3u,	false,	true,	}, "only sparse queue, wait for and signal semaphore(s)", },
352 
353 		{ "multi_queue_wait_one",						{	2u,	1u,	0u,	false,	true,	}, "sparse and other queues, wait for semaphore(s)", },
354 		{ "multi_queue_wait_many",						{	2u,	2u,	0u,	false,	true,	}, "sparse and other queues, wait for semaphore(s)", },
355 		{ "multi_queue_signal_one",						{	2u,	0u,	1u,	false,	true,	}, "sparse and other queues, signal semaphore(s)", },
356 		{ "multi_queue_signal_many",					{	2u,	0u,	2u,	false,	true,	}, "sparse and other queues, signal semaphore(s)", },
357 		{ "multi_queue_wait_one_signal_one",			{	2u,	1u,	1u,	false,	true,	}, "sparse and other queues, wait for and signal semaphore(s)", },
358 		{ "multi_queue_wait_many_signal_many",			{	2u,	2u,	2u,	false,	true,	}, "sparse and other queues, wait for and signal semaphore(s)", },
359 		{ "multi_queue_wait_one_signal_one_other",		{	2u,	1u,	1u,	false,	true,	}, "sparse and other queues, wait for and signal semaphore(s) on other queues", },
360 		{ "multi_queue_wait_many_signal_many_other",	{	3u,	2u,	2u,	false,	true,	}, "sparse and other queues, wait for and signal semaphore(s) on other queues", },
361 
362 		{ "empty",										{	1u,	0u,	0u,	true,	false,	}, "call vkQueueBindSparse with zero bindInfos", },
363 		{ "empty_fence",								{	1u,	0u,	0u,	true,	true,	}, "call vkQueueBindSparse with zero bindInfos, signal a fence", },
364 	};
365 
366 	for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
367 		group->addChild(new SparseQueueBindTest(group->getTestContext(), cases[caseNdx].name, cases[caseNdx].description, cases[caseNdx].params));
368 }
369 
370 } // anonymous ns
371 
372 //! Sparse queue binding edge cases and synchronization with semaphores/fences.
373 //! Actual binding and usage is tested by other test groups.
createQueueBindSparseTests(tcu::TestContext & testCtx)374 tcu::TestCaseGroup* createQueueBindSparseTests (tcu::TestContext& testCtx)
375 {
376 	return createTestGroup(testCtx, "queue_bind", "Queue bind sparse tests", populateTestGroup);
377 }
378 
379 } // sparse
380 } // vkt
381