1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Queue bind sparse tests
22 *//*--------------------------------------------------------------------*/
24 #include "vktSparseResourcesQueueBindSparseTests.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestGroupUtil.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkQueryUtil.hpp"
35 #include "deUniquePtr.hpp"
36 #include "deSharedPtr.hpp"
51 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
52 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
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;
63 struct QueueSubmission
68 VkBindSparseInfo sparse;
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)
83 const VkSubmitInfo submitInfo =
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;
96 QueueSubmission submission;
97 submission.isSparseBinding = false;
98 submission.queue = queue;
99 submission.info.regular = submitInfo;
104 QueueSubmission makeSubmissionSparse (const Queue* queue,
105 const deUint32 numWaitSemaphores,
106 const VkSemaphore* pWaitSemaphore,
107 const deUint32 numSignalSemaphores,
108 const VkSemaphore* pSignalSemaphore)
110 const VkBindSparseInfo bindInfo =
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;
126 QueueSubmission submission;
127 submission.isSparseBinding = true;
128 submission.queue = queue;
129 submission.info.sparse = bindInfo;
134 bool waitForFences (const DeviceInterface& vk, const VkDevice device, const std::vector<FenceSp>& fences)
136 for (std::vector<FenceSp>::const_iterator fenceSpIter = fences.begin(); fenceSpIter != fences.end(); ++fenceSpIter)
138 if (vk.waitForFences(device, 1u, &(***fenceSpIter), VK_TRUE, ~0ull) != VK_SUCCESS)
144 class SparseQueueBindTestInstance : public SparseResourcesBaseInstance
147 SparseQueueBindTestInstance (Context &context, const TestParams& params)
148 : SparseResourcesBaseInstance (context)
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
155 tcu::TestStatus iterate (void)
157 const InstanceInterface& vki = m_context.getInstanceInterface();
158 const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
159 const Queue* sparseQueue = DE_NULL;
160 std::vector<const Queue*> otherQueues;
162 if (!getPhysicalDeviceFeatures(vki, physDevice).sparseBinding)
163 TCU_THROW(NotSupportedError, "Sparse binding not supported");
165 // Determine required queues and create a device that supports them
167 QueueRequirementsVec requirements;
168 requirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
169 requirements.push_back(QueueRequirements((VkQueueFlags)0, m_params.numQueues)); // any queue flags
171 createDeviceSupportingQueues(requirements);
173 sparseQueue = &getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0u);
175 // We probably have picked the sparse queue again, so filter it out
176 for (deUint32 queueNdx = 0u; queueNdx < m_params.numQueues; ++queueNdx)
178 const Queue* queue = &getQueue((VkQueueFlags)0, queueNdx);
179 if (queue->queueHandle != sparseQueue->queueHandle)
180 otherQueues.push_back(queue);
184 const DeviceInterface& vk = getDeviceInterface();
186 std::vector<SemaphoreSp> allSemaphores;
187 std::vector<VkSemaphore> waitSemaphores;
188 std::vector<VkSemaphore> signalSemaphores;
189 std::vector<VkPipelineStageFlags> signalSemaphoresWaitDstStageMask;
190 std::vector<QueueSubmission> queueSubmissions;
192 for (deUint32 i = 0; i < m_params.numWaitSemaphores; ++i)
194 allSemaphores.push_back(makeVkSharedPtr(createSemaphore(vk, getDevice())));
195 waitSemaphores.push_back(**allSemaphores.back());
198 for (deUint32 i = 0; i < m_params.numSignalSemaphores; ++i)
200 allSemaphores.push_back(makeVkSharedPtr(createSemaphore(vk, getDevice())));
201 signalSemaphores.push_back(**allSemaphores.back());
202 signalSemaphoresWaitDstStageMask.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
205 // Prepare submissions: signal semaphores for the sparse bind operation
207 deUint32 numQueues = 1u + static_cast<deUint32>(otherQueues.size());
208 deUint32 numSemaphores = m_params.numWaitSemaphores;
210 while (numSemaphores > 0u && numQueues > 0u)
212 if (numQueues == 1u) // sparse queue is assigned last
214 // sparse queue can handle regular submissions as well
215 queueSubmissions.push_back(makeSubmissionRegular(
216 sparseQueue, 0u, DE_NULL, DE_NULL, numSemaphores, getDataOrNullptr(waitSemaphores)));
222 queueSubmissions.push_back(makeSubmissionRegular(
223 otherQueues[numQueues - 2], 0u, DE_NULL, DE_NULL, 1u, getDataOrNullptr(waitSemaphores, numSemaphores - 1)));
230 // Prepare submission: bind sparse
231 if (!m_params.emptySubmission)
233 queueSubmissions.push_back(makeSubmissionSparse(
234 sparseQueue, m_params.numWaitSemaphores, getDataOrNullptr(waitSemaphores), m_params.numSignalSemaphores, getDataOrNullptr(signalSemaphores)));
238 // a dummy submission, won't be used in a call to vkQueueBindSparse
239 queueSubmissions.push_back(makeSubmissionSparse(sparseQueue, 0u, DE_NULL, 0u, DE_NULL));
242 // Prepare submissions: wait on semaphores signaled by the sparse bind operation
243 if (!m_params.emptySubmission)
245 deUint32 numQueues = 1u + static_cast<deUint32>(otherQueues.size());
246 deUint32 numSemaphores = m_params.numSignalSemaphores;
248 while (numSemaphores > 0u && numQueues > 0u)
252 queueSubmissions.push_back(makeSubmissionRegular(
253 sparseQueue, numSemaphores, getDataOrNullptr(signalSemaphores), getDataOrNullptr(signalSemaphoresWaitDstStageMask), 0u, DE_NULL));
259 queueSubmissions.push_back(makeSubmissionRegular(
260 otherQueues[numQueues - 2], 1u, getDataOrNullptr(signalSemaphores, numSemaphores - 1), getDataOrNullptr(signalSemaphoresWaitDstStageMask, numSemaphores - 1), 0u, DE_NULL));
269 std::vector<FenceSp> regularFences;
270 std::vector<FenceSp> bindSparseFences;
272 for (std::vector<QueueSubmission>::const_iterator submissionIter = queueSubmissions.begin(); submissionIter != queueSubmissions.end(); ++submissionIter)
274 if (submissionIter->isSparseBinding)
276 VkFence fence = DE_NULL;
278 if (m_params.bindSparseUseFence)
280 bindSparseFences.push_back(makeVkSharedPtr(createFence(vk, getDevice())));
281 fence = **bindSparseFences.back();
284 if (m_params.emptySubmission)
285 VK_CHECK(vk.queueBindSparse(submissionIter->queue->queueHandle, 0u, DE_NULL, fence));
287 VK_CHECK(vk.queueBindSparse(submissionIter->queue->queueHandle, 1u, &submissionIter->info.sparse, fence));
291 regularFences.push_back(makeVkSharedPtr(createFence(vk, getDevice())));
292 VK_CHECK(vk.queueSubmit(submissionIter->queue->queueHandle, 1u, &submissionIter->info.regular, **regularFences.back()));
296 if (!waitForFences(vk, getDevice(), bindSparseFences))
297 return tcu::TestStatus::fail("vkQueueBindSparse didn't signal the fence");
299 if (!waitForFences(vk, getDevice(), regularFences))
300 return tcu::TestStatus::fail("Some fences weren't signaled (vkQueueBindSparse didn't signal semaphores?)");
303 // May return an error if some waitSemaphores didn't get signaled
304 VK_CHECK(vk.deviceWaitIdle(getDevice()));
306 return tcu::TestStatus::pass("Pass");
310 const TestParams m_params;
313 class SparseQueueBindTest : public TestCase
316 SparseQueueBindTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
317 : TestCase (testCtx, name, description)
320 DE_ASSERT(params.numQueues > 0u);
321 DE_ASSERT(params.numQueues == 1u || m_params.numWaitSemaphores > 0u || m_params.numSignalSemaphores > 0u); // without any semaphores, only sparse queue will be used
324 TestInstance* createInstance (Context& context) const
326 return new SparseQueueBindTestInstance(context, m_params);
330 const TestParams m_params;
333 void populateTestGroup(tcu::TestCaseGroup* group)
339 std::string description;
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", },
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)", },
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", },
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", },
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));
372 //! Sparse queue binding edge cases and synchronization with semaphores/fences.
373 //! Actual binding and usage is tested by other test groups.
374 tcu::TestCaseGroup* createQueueBindSparseTests (tcu::TestContext& testCtx)
376 return createTestGroup(testCtx, "queue_bind", "Queue bind sparse tests", populateTestGroup);