Update Vulkan CTS to version 1.0.2.3 am: 148890e79f
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / sparse_resources / vktSparseResourcesQueueBindSparseTests.cpp
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
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
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
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:
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
155         tcu::TestStatus iterate (void)
156         {
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;
161
162                 if (!getPhysicalDeviceFeatures(vki, physDevice).sparseBinding)
163                         TCU_THROW(NotSupportedError, "Sparse binding not supported");
164
165                 // Determine required queues and create a device that supports them
166                 {
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
170
171                         createDeviceSupportingQueues(requirements);
172
173                         sparseQueue = &getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0u);
174
175                         // We probably have picked the sparse queue again, so filter it out
176                         for (deUint32 queueNdx = 0u; queueNdx < m_params.numQueues; ++queueNdx)
177                         {
178                                 const Queue* queue = &getQueue((VkQueueFlags)0, queueNdx);
179                                 if (queue->queueHandle != sparseQueue->queueHandle)
180                                         otherQueues.push_back(queue);
181                         }
182                 }
183
184                 const DeviceInterface&                          vk = getDeviceInterface();
185
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;
191
192                 for (deUint32 i = 0; i < m_params.numWaitSemaphores; ++i)
193                 {
194                         allSemaphores.push_back(makeVkSharedPtr(createSemaphore(vk, getDevice())));
195                         waitSemaphores.push_back(**allSemaphores.back());
196                 }
197
198                 for (deUint32 i = 0; i < m_params.numSignalSemaphores; ++i)
199                 {
200                         allSemaphores.push_back(makeVkSharedPtr(createSemaphore(vk, getDevice())));
201                         signalSemaphores.push_back(**allSemaphores.back());
202                         signalSemaphoresWaitDstStageMask.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
203                 }
204
205                 // Prepare submissions: signal semaphores for the sparse bind operation
206                 {
207                         deUint32 numQueues              = 1u + static_cast<deUint32>(otherQueues.size());
208                         deUint32 numSemaphores  = m_params.numWaitSemaphores;
209
210                         while (numSemaphores > 0u && numQueues > 0u)
211                         {
212                                 if (numQueues == 1u)    // sparse queue is assigned last
213                                 {
214                                         // sparse queue can handle regular submissions as well
215                                         queueSubmissions.push_back(makeSubmissionRegular(
216                                                 sparseQueue, 0u, DE_NULL, DE_NULL, numSemaphores, getDataOrNullptr(waitSemaphores)));
217                                         numSemaphores   = 0u;
218                                         numQueues               = 0u;
219                                 }
220                                 else
221                                 {
222                                         queueSubmissions.push_back(makeSubmissionRegular(
223                                                 otherQueues[numQueues - 2], 0u, DE_NULL, DE_NULL, 1u, getDataOrNullptr(waitSemaphores, numSemaphores - 1)));
224                                         --numQueues;
225                                         --numSemaphores;
226                                 }
227                         }
228                 }
229
230                 // Prepare submission: bind sparse
231                 if (!m_params.emptySubmission)
232                 {
233                         queueSubmissions.push_back(makeSubmissionSparse(
234                                 sparseQueue, m_params.numWaitSemaphores, getDataOrNullptr(waitSemaphores), m_params.numSignalSemaphores, getDataOrNullptr(signalSemaphores)));
235                 }
236                 else
237                 {
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));
240                 }
241
242                 // Prepare submissions: wait on semaphores signaled by the sparse bind operation
243                 if (!m_params.emptySubmission)
244                 {
245                         deUint32 numQueues              = 1u + static_cast<deUint32>(otherQueues.size());
246                         deUint32 numSemaphores  = m_params.numSignalSemaphores;
247
248                         while (numSemaphores > 0u && numQueues > 0u)
249                         {
250                                 if (numQueues == 1u)
251                                 {
252                                         queueSubmissions.push_back(makeSubmissionRegular(
253                                                 sparseQueue, numSemaphores, getDataOrNullptr(signalSemaphores), getDataOrNullptr(signalSemaphoresWaitDstStageMask), 0u, DE_NULL));
254                                         numSemaphores   = 0u;
255                                         numQueues               = 0u;
256                                 }
257                                 else
258                                 {
259                                         queueSubmissions.push_back(makeSubmissionRegular(
260                                                 otherQueues[numQueues - 2], 1u, getDataOrNullptr(signalSemaphores, numSemaphores - 1), getDataOrNullptr(signalSemaphoresWaitDstStageMask, numSemaphores - 1), 0u, DE_NULL));
261                                         --numQueues;
262                                         --numSemaphores;
263                                 }
264                         }
265                 }
266
267                 // Submit to queues
268                 {
269                         std::vector<FenceSp>    regularFences;
270                         std::vector<FenceSp>    bindSparseFences;
271
272                         for (std::vector<QueueSubmission>::const_iterator submissionIter = queueSubmissions.begin(); submissionIter != queueSubmissions.end(); ++submissionIter)
273                         {
274                                 if (submissionIter->isSparseBinding)
275                                 {
276                                         VkFence fence = DE_NULL;
277
278                                         if (m_params.bindSparseUseFence)
279                                         {
280                                                 bindSparseFences.push_back(makeVkSharedPtr(createFence(vk, getDevice())));
281                                                 fence = **bindSparseFences.back();
282                                         }
283
284                                         if (m_params.emptySubmission)
285                                                 VK_CHECK(vk.queueBindSparse(submissionIter->queue->queueHandle, 0u, DE_NULL, fence));
286                                         else
287                                                 VK_CHECK(vk.queueBindSparse(submissionIter->queue->queueHandle, 1u, &submissionIter->info.sparse, fence));
288                                 }
289                                 else
290                                 {
291                                         regularFences.push_back(makeVkSharedPtr(createFence(vk, getDevice())));
292                                         VK_CHECK(vk.queueSubmit(submissionIter->queue->queueHandle, 1u, &submissionIter->info.regular, **regularFences.back()));
293                                 }
294                         }
295
296                         if (!waitForFences(vk, getDevice(), bindSparseFences))
297                                 return tcu::TestStatus::fail("vkQueueBindSparse didn't signal the fence");
298
299                         if (!waitForFences(vk, getDevice(), regularFences))
300                                 return tcu::TestStatus::fail("Some fences weren't signaled (vkQueueBindSparse didn't signal semaphores?)");
301                 }
302
303                 // May return an error if some waitSemaphores didn't get signaled
304                 VK_CHECK(vk.deviceWaitIdle(getDevice()));
305
306                 return tcu::TestStatus::pass("Pass");
307         }
308
309 private:
310         const TestParams        m_params;
311 };
312
313 class SparseQueueBindTest : public TestCase
314 {
315 public:
316         SparseQueueBindTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
317                 : TestCase      (testCtx, name, description)
318                 , m_params      (params)
319         {
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
322         }
323
324         TestInstance* createInstance (Context& context) const
325         {
326                 return new SparseQueueBindTestInstance(context, m_params);
327         }
328
329 private:
330         const TestParams        m_params;
331 };
332
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.
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