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 Synchronization fence basic tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSynchronizationBasicFenceTests.hpp"
25 #include "vktTestCaseUtil.hpp"
26 #include "vktSynchronizationUtil.hpp"
27 
28 #include "vkDefs.hpp"
29 #include "vkPlatform.hpp"
30 #include "vkRef.hpp"
31 #include "vkCmdUtil.hpp"
32 
33 #include <vector>
34 #include <algorithm>
35 #include <iterator>
36 
37 namespace vkt
38 {
39 namespace synchronization
40 {
41 namespace
42 {
43 using namespace vk;
44 using vkt::synchronization::VideoCodecOperationFlags;
45 
46 static const uint64_t SHORT_FENCE_WAIT = 1000ull;       // 1us
47 static const uint64_t LONG_FENCE_WAIT  = 1000000000ull; // 1s
48 
49 struct FenceConfig
50 {
51     uint32_t numFences;
52     VideoCodecOperationFlags videoCodecOperationFlags;
53 };
54 
basicOneFenceCase(Context & context,FenceConfig config)55 tcu::TestStatus basicOneFenceCase(Context &context, FenceConfig config)
56 {
57     de::MovePtr<VideoDevice> videoDevice(
58         config.videoCodecOperationFlags != 0 ? new VideoDevice(context, config.videoCodecOperationFlags) : DE_NULL);
59     const DeviceInterface &vk       = getSyncDeviceInterface(videoDevice, context);
60     const VkDevice device           = getSyncDevice(videoDevice, context);
61     const VkQueue queue             = getSyncQueue(videoDevice, context);
62     const uint32_t queueFamilyIndex = getSyncQueueFamilyIndex(videoDevice, context);
63     const Unique<VkCommandPool> cmdPool(
64         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
65     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
66 
67     const VkFenceCreateInfo fenceInfo = {
68         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType      sType;
69         DE_NULL,                             // const void*          pNext;
70         0u,                                  // VkFenceCreateFlags   flags;
71     };
72 
73     const Unique<VkFence> fence(createFence(vk, device, &fenceInfo));
74 
75     const VkSubmitInfo submitInfo = {
76         VK_STRUCTURE_TYPE_SUBMIT_INFO,         // VkStructureType                sType;
77         DE_NULL,                               // const void*                    pNext;
78         0u,                                    // uint32_t                       waitSemaphoreCount;
79         DE_NULL,                               // const VkSemaphore*             pWaitSemaphores;
80         (const VkPipelineStageFlags *)DE_NULL, // const VkPipelineStageFlags*    pWaitDstStageMask;
81         1u,                                    // uint32_t                       commandBufferCount;
82         &cmdBuffer.get(),                      // const VkCommandBuffer*         pCommandBuffers;
83         0u,                                    // uint32_t                       signalSemaphoreCount;
84         DE_NULL,                               // const VkSemaphore*             pSignalSemaphores;
85     };
86 
87     if (VK_NOT_READY != vk.getFenceStatus(device, *fence))
88         return tcu::TestStatus::fail("Created fence should be in unsignaled state");
89 
90     if (VK_TIMEOUT != vk.waitForFences(device, 1u, &fence.get(), VK_TRUE, SHORT_FENCE_WAIT))
91         return tcu::TestStatus::fail("vkWaitForFences should return VK_TIMEOUT");
92 
93     if (VK_NOT_READY != vk.getFenceStatus(device, *fence))
94         return tcu::TestStatus::fail("Created fence should be in unsignaled state");
95 
96     beginCommandBuffer(vk, *cmdBuffer);
97     endCommandBuffer(vk, *cmdBuffer);
98 
99     VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
100 
101     if (VK_SUCCESS != vk.waitForFences(device, 1u, &fence.get(), true, LONG_FENCE_WAIT))
102         return tcu::TestStatus::fail("vkWaitForFences should return VK_SUCCESS");
103 
104     if (VK_SUCCESS != vk.getFenceStatus(device, *fence))
105         return tcu::TestStatus::fail("Fence should be in signaled state");
106 
107     if (VK_SUCCESS != vk.resetFences(device, 1u, &fence.get()))
108         return tcu::TestStatus::fail("Couldn't reset the fence");
109 
110     if (VK_NOT_READY != vk.getFenceStatus(device, *fence))
111         return tcu::TestStatus::fail("Fence after reset should be in unsignaled state");
112 
113     return tcu::TestStatus::pass("Basic one fence tests passed");
114 }
115 
checkVideoSupport(Context & context,FenceConfig config)116 void checkVideoSupport(Context &context, FenceConfig config)
117 {
118     if (config.videoCodecOperationFlags != 0)
119         VideoDevice::checkSupport(context, config.videoCodecOperationFlags);
120 }
121 
checkCommandBufferSimultaneousUseSupport(Context & context,FenceConfig config)122 void checkCommandBufferSimultaneousUseSupport(Context &context, FenceConfig config)
123 {
124 #ifdef CTS_USES_VULKANSC
125     if (context.getDeviceVulkanSC10Properties().commandBufferSimultaneousUse == VK_FALSE)
126         TCU_THROW(NotSupportedError, "commandBufferSimultaneousUse is not supported");
127 #endif
128 
129     checkVideoSupport(context, config);
130 }
131 
basicSignaledCase(Context & context,FenceConfig config)132 tcu::TestStatus basicSignaledCase(Context &context, FenceConfig config)
133 {
134     de::MovePtr<VideoDevice> videoDevice(
135         config.videoCodecOperationFlags != 0 ? new VideoDevice(context, config.videoCodecOperationFlags) : DE_NULL);
136     const DeviceInterface &vkd = getSyncDeviceInterface(videoDevice, context);
137     const VkDevice device      = getSyncDevice(videoDevice, context);
138 
139     std::vector<Move<VkFence>> fences;
140     fences.reserve(config.numFences);
141 
142     const VkFenceCreateInfo fenceCreateInfo = {
143         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
144         nullptr,                             // const void* pNext;
145         VK_FENCE_CREATE_SIGNALED_BIT,        // VkFenceCreateFlags flags;
146     };
147 
148     for (uint32_t i = 0u; i < config.numFences; ++i)
149     {
150         fences.push_back(createFence(vkd, device, &fenceCreateInfo));
151         if (vkd.getFenceStatus(device, fences.back().get()) != VK_SUCCESS)
152             TCU_FAIL("Fence was not created signaled");
153     }
154 
155     std::vector<VkFence> rawFences;
156     std::transform(begin(fences), end(fences), std::back_inserter(rawFences),
157                    [](const Move<VkFence> &f) { return f.get(); });
158 
159     const auto waitResult = vkd.waitForFences(device, static_cast<uint32_t>(rawFences.size()),
160                                               de::dataOrNull(rawFences), VK_TRUE, LONG_FENCE_WAIT);
161     if (waitResult != VK_SUCCESS)
162         TCU_FAIL("vkWaitForFences failed with exit status " + std::to_string(waitResult));
163 
164     return tcu::TestStatus::pass("Pass");
165 }
166 
basicMultiFenceCase(Context & context,FenceConfig config)167 tcu::TestStatus basicMultiFenceCase(Context &context, FenceConfig config)
168 {
169     enum
170     {
171         FIRST_FENCE = 0,
172         SECOND_FENCE
173     };
174 
175     de::MovePtr<VideoDevice> videoDevice(
176         config.videoCodecOperationFlags != 0 ? new VideoDevice(context, config.videoCodecOperationFlags) : DE_NULL);
177     const DeviceInterface &vk       = getSyncDeviceInterface(videoDevice, context);
178     const VkDevice device           = getSyncDevice(videoDevice, context);
179     const VkQueue queue             = getSyncQueue(videoDevice, context);
180     const uint32_t queueFamilyIndex = getSyncQueueFamilyIndex(videoDevice, context);
181     const Unique<VkCommandPool> cmdPool(
182         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
183     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
184 
185     const VkFenceCreateInfo fenceInfo = {
186         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType      sType;
187         DE_NULL,                             // const void*          pNext;
188         0u,                                  // VkFenceCreateFlags   flags;
189     };
190 
191     const Move<VkFence> ptrFence[2] = {createFence(vk, device, &fenceInfo), createFence(vk, device, &fenceInfo)};
192 
193     const VkFence fence[2] = {*ptrFence[FIRST_FENCE], *ptrFence[SECOND_FENCE]};
194 
195     const VkCommandBufferBeginInfo info = {
196         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,  // VkStructureType                          sType;
197         DE_NULL,                                      // const void*                              pNext;
198         VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, // VkCommandBufferUsageFlags                flags;
199         DE_NULL,                                      // const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
200     };
201 
202     const VkSubmitInfo submitInfo = {
203         VK_STRUCTURE_TYPE_SUBMIT_INFO,         // VkStructureType                sType;
204         DE_NULL,                               // const void*                    pNext;
205         0u,                                    // uint32_t                       waitSemaphoreCount;
206         DE_NULL,                               // const VkSemaphore*             pWaitSemaphores;
207         (const VkPipelineStageFlags *)DE_NULL, // const VkPipelineStageFlags*    pWaitDstStageMask;
208         1u,                                    // uint32_t                       commandBufferCount;
209         &cmdBuffer.get(),                      // const VkCommandBuffer*         pCommandBuffers;
210         0u,                                    // uint32_t                       signalSemaphoreCount;
211         DE_NULL,                               // const VkSemaphore*             pSignalSemaphores;
212     };
213 
214     VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &info));
215     endCommandBuffer(vk, *cmdBuffer);
216 
217     VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence[FIRST_FENCE]));
218 
219     if (VK_SUCCESS != vk.waitForFences(device, 1u, &fence[FIRST_FENCE], false, LONG_FENCE_WAIT))
220         return tcu::TestStatus::fail("vkWaitForFences should return VK_SUCCESS");
221 
222     if (VK_SUCCESS != vk.resetFences(device, 1u, &fence[FIRST_FENCE]))
223         return tcu::TestStatus::fail("Couldn't reset the fence");
224 
225     VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence[FIRST_FENCE]));
226 
227     if (VK_TIMEOUT != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], true, SHORT_FENCE_WAIT))
228         return tcu::TestStatus::fail("vkWaitForFences should return VK_TIMEOUT");
229 
230     VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence[SECOND_FENCE]));
231 
232     if (VK_SUCCESS != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], true, LONG_FENCE_WAIT))
233         return tcu::TestStatus::fail("vkWaitForFences should return VK_SUCCESS");
234 
235     return tcu::TestStatus::pass("Basic multi fence tests passed");
236 }
237 
emptySubmitCase(Context & context,FenceConfig config)238 tcu::TestStatus emptySubmitCase(Context &context, FenceConfig config)
239 {
240     de::MovePtr<VideoDevice> videoDevice(
241         config.videoCodecOperationFlags != 0 ? new VideoDevice(context, config.videoCodecOperationFlags) : DE_NULL);
242     const DeviceInterface &vk = getSyncDeviceInterface(videoDevice, context);
243     const VkDevice device     = getSyncDevice(videoDevice, context);
244     const VkQueue queue       = getSyncQueue(videoDevice, context);
245 
246     const VkFenceCreateInfo fenceCreateInfo = {
247         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType       sType;
248         DE_NULL,                             // const void*           pNext;
249         (VkFenceCreateFlags)0,               // VkFenceCreateFlags    flags;
250     };
251 
252     const Unique<VkFence> fence(createFence(vk, device, &fenceCreateInfo));
253 
254     VK_CHECK(vk.queueSubmit(queue, 0u, DE_NULL, *fence));
255 
256     if (VK_SUCCESS != vk.waitForFences(device, 1u, &fence.get(), true, LONG_FENCE_WAIT))
257         return tcu::TestStatus::fail("vkWaitForFences should return VK_SUCCESS");
258 
259     return tcu::TestStatus::pass("OK");
260 }
261 
basicMultiFenceWaitAllFalseCase(Context & context,FenceConfig config)262 tcu::TestStatus basicMultiFenceWaitAllFalseCase(Context &context, FenceConfig config)
263 {
264     enum
265     {
266         FIRST_FENCE = 0,
267         SECOND_FENCE
268     };
269 
270     de::MovePtr<VideoDevice> videoDevice(
271         config.videoCodecOperationFlags != 0 ? new VideoDevice(context, config.videoCodecOperationFlags) : DE_NULL);
272     const DeviceInterface &vk       = getSyncDeviceInterface(videoDevice, context);
273     const VkDevice device           = getSyncDevice(videoDevice, context);
274     const VkQueue queue             = getSyncQueue(videoDevice, context);
275     const uint32_t queueFamilyIndex = getSyncQueueFamilyIndex(videoDevice, context);
276     const Unique<VkCommandPool> cmdPool(
277         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
278     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
279 
280     const VkFenceCreateInfo fenceInfo = {
281         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType     sType;
282         DE_NULL,                             // const void*         pNext;
283         0u,                                  // VkFenceCreateFlags  flags;
284     };
285 
286     const Move<VkFence> ptrFence[2] = {createFence(vk, device, &fenceInfo), createFence(vk, device, &fenceInfo)};
287 
288     const VkFence fence[2] = {*ptrFence[FIRST_FENCE], *ptrFence[SECOND_FENCE]};
289 
290     const VkCommandBufferBeginInfo info = {
291         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,  // VkStructureType                          sType;
292         DE_NULL,                                      // const void*                              pNext;
293         VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, // VkCommandBufferUsageFlags                flags;
294         DE_NULL,                                      // const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
295     };
296 
297     const VkSubmitInfo submitInfo = {
298         VK_STRUCTURE_TYPE_SUBMIT_INFO,         // VkStructureType                sType;
299         DE_NULL,                               // const void*                    pNext;
300         0u,                                    // uint32_t                       waitSemaphoreCount;
301         DE_NULL,                               // const VkSemaphore*             pWaitSemaphores;
302         (const VkPipelineStageFlags *)DE_NULL, // const VkPipelineStageFlags*    pWaitDstStageMask;
303         1u,                                    // uint32_t                       commandBufferCount;
304         &cmdBuffer.get(),                      // const VkCommandBuffer*         pCommandBuffers;
305         0u,                                    // uint32_t                       signalSemaphoreCount;
306         DE_NULL,                               // const VkSemaphore*             pSignalSemaphores;
307     };
308 
309     VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &info));
310     endCommandBuffer(vk, *cmdBuffer);
311 
312     if (VK_TIMEOUT != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], false, SHORT_FENCE_WAIT))
313         return tcu::TestStatus::fail(
314             "vkWaitForFences should return VK_TIMEOUT for case: Wait for any fence (No fence has been signaled)");
315 
316     if (VK_TIMEOUT != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], true, SHORT_FENCE_WAIT))
317         return tcu::TestStatus::fail(
318             "vkWaitForFences should return VK_TIMEOUT for case: Wait for all fences (No fence has been signaled)");
319 
320     VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence[SECOND_FENCE]));
321 
322     if (VK_SUCCESS != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], false, LONG_FENCE_WAIT))
323         return tcu::TestStatus::fail(
324             "vkWaitForFences should return VK_SUCCESS for case: Wait for any fence (Only second fence signaled)");
325 
326     if (VK_TIMEOUT != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], true, SHORT_FENCE_WAIT))
327         return tcu::TestStatus::fail(
328             "vkWaitForFences should return VK_TIMEOUT for case: Wait for all fences (Only second fence signaled)");
329 
330     VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence[FIRST_FENCE]));
331 
332     if (VK_SUCCESS != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], false, LONG_FENCE_WAIT))
333         return tcu::TestStatus::fail(
334             "vkWaitForFences should return VK_SUCCESS for case: Wait for any fence (All fences signaled)");
335 
336     if (VK_SUCCESS != vk.waitForFences(device, 2u, &fence[FIRST_FENCE], true, LONG_FENCE_WAIT))
337         return tcu::TestStatus::fail(
338             "vkWaitForFences should return VK_SUCCESS for case: Wait for all fences (All fences signaled)");
339 
340     return tcu::TestStatus::pass("Basic multi fence test without waitAll passed");
341 }
342 
343 } // namespace
344 
createBasicFenceTests(tcu::TestContext & testCtx,VideoCodecOperationFlags videoCodecOperationFlags)345 tcu::TestCaseGroup *createBasicFenceTests(tcu::TestContext &testCtx, VideoCodecOperationFlags videoCodecOperationFlags)
346 {
347     // Basic fence tests
348     de::MovePtr<tcu::TestCaseGroup> basicFenceTests(new tcu::TestCaseGroup(testCtx, "fence"));
349 
350     // Basic one fence tests
351     addFunctionCase(basicFenceTests.get(), "one", checkVideoSupport, basicOneFenceCase,
352                     FenceConfig{0u, videoCodecOperationFlags});
353     // Basic multi fence tests
354     addFunctionCase(basicFenceTests.get(), "multi", checkCommandBufferSimultaneousUseSupport, basicMultiFenceCase,
355                     FenceConfig{0u, videoCodecOperationFlags});
356     // Signal a fence after an empty queue submission
357     addFunctionCase(basicFenceTests.get(), "empty_submit", checkVideoSupport, emptySubmitCase,
358                     FenceConfig{0u, videoCodecOperationFlags});
359     // Basic multi fence test without waitAll
360     addFunctionCase(basicFenceTests.get(), "multi_waitall_false", checkCommandBufferSimultaneousUseSupport,
361                     basicMultiFenceWaitAllFalseCase, FenceConfig{0u, videoCodecOperationFlags});
362     // Create a single signaled fence and wait on it
363     addFunctionCase(basicFenceTests.get(), "one_signaled", checkVideoSupport, basicSignaledCase,
364                     FenceConfig{1u, videoCodecOperationFlags});
365     // Create multiple signaled fences and wait on them
366     addFunctionCase(basicFenceTests.get(), "multiple_signaled", checkCommandBufferSimultaneousUseSupport,
367                     basicSignaledCase, FenceConfig{10u, videoCodecOperationFlags});
368 
369     return basicFenceTests.release();
370 }
371 
372 } // namespace synchronization
373 } // namespace vkt
374