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 Synchronization primitive tests with single queue
22 *//*--------------------------------------------------------------------*/
24 #include "vktSynchronizationOperationSingleQueueTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "deUniquePtr.hpp"
35 #include "tcuTestLog.hpp"
36 #include "vktSynchronizationUtil.hpp"
37 #include "vktSynchronizationOperation.hpp"
38 #include "vktSynchronizationOperationTestData.hpp"
39 #include "vktSynchronizationOperationResources.hpp"
43 namespace synchronization
49 class BaseTestInstance : public TestInstance
52 BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
53 : TestInstance (context)
54 , m_opContext (context, pipelineCacheData)
55 , m_resource (new Resource(m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
56 , m_writeOp (writeOp.build(m_opContext, *m_resource))
57 , m_readOp (readOp.build(m_opContext, *m_resource))
62 OperationContext m_opContext;
63 const de::UniquePtr<Resource> m_resource;
64 const de::UniquePtr<Operation> m_writeOp;
65 const de::UniquePtr<Operation> m_readOp;
68 class EventTestInstance : public BaseTestInstance
71 EventTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
72 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
76 tcu::TestStatus iterate (void)
78 const DeviceInterface& vk = m_context.getDeviceInterface();
79 const VkDevice device = m_context.getDevice();
80 const VkQueue queue = m_context.getUniversalQueue();
81 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
82 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
83 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
84 const Unique<VkEvent> event (createEvent(vk, device));
85 const SyncInfo writeSync = m_writeOp->getSyncInfo();
86 const SyncInfo readSync = m_readOp->getSyncInfo();
88 beginCommandBuffer(vk, *cmdBuffer);
90 m_writeOp->recordCommands(*cmdBuffer);
91 vk.cmdSetEvent(*cmdBuffer, *event, writeSync.stageMask);
93 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
95 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
96 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
97 vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
99 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
101 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
102 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
103 vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
106 m_readOp->recordCommands(*cmdBuffer);
108 endCommandBuffer(vk, *cmdBuffer);
109 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
112 const Data expected = m_writeOp->getData();
113 const Data actual = m_readOp->getData();
115 if (0 != deMemCmp(expected.data, actual.data, expected.size))
116 return tcu::TestStatus::fail("Memory contents don't match");
119 return tcu::TestStatus::pass("OK");
123 class BarrierTestInstance : public BaseTestInstance
126 BarrierTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
127 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
131 tcu::TestStatus iterate (void)
133 const DeviceInterface& vk = m_context.getDeviceInterface();
134 const VkDevice device = m_context.getDevice();
135 const VkQueue queue = m_context.getUniversalQueue();
136 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
137 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
138 const Move<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
139 const SyncInfo writeSync = m_writeOp->getSyncInfo();
140 const SyncInfo readSync = m_readOp->getSyncInfo();
142 beginCommandBuffer(vk, *cmdBuffer);
144 m_writeOp->recordCommands(*cmdBuffer);
146 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
148 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
149 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
150 vk.cmdPipelineBarrier(*cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
152 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
154 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
155 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
156 vk.cmdPipelineBarrier(*cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
159 m_readOp->recordCommands(*cmdBuffer);
161 endCommandBuffer(vk, *cmdBuffer);
163 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
166 const Data expected = m_writeOp->getData();
167 const Data actual = m_readOp->getData();
169 if (0 != deMemCmp(expected.data, actual.data, expected.size))
170 return tcu::TestStatus::fail("Memory contents don't match");
173 return tcu::TestStatus::pass("OK");
177 class SemaphoreTestInstance : public BaseTestInstance
180 SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
181 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
185 tcu::TestStatus iterate (void)
187 enum {WRITE=0, READ, COUNT};
188 const DeviceInterface& vk = m_context.getDeviceInterface();
189 const VkDevice device = m_context.getDevice();
190 const VkQueue queue = m_context.getUniversalQueue();
191 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
192 const Unique<VkSemaphore> semaphore (createSemaphore (vk, device));
193 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
194 const Move<VkCommandBuffer> ptrCmdBuffer[COUNT] = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
195 VkCommandBuffer cmdBuffers[COUNT] = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
196 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
197 const VkSubmitInfo submitInfo[2] =
200 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
201 DE_NULL, // const void* pNext;
202 0u, // deUint32 waitSemaphoreCount;
203 DE_NULL, // const VkSemaphore* pWaitSemaphores;
204 (const VkPipelineStageFlags*)DE_NULL,
205 1u, // deUint32 commandBufferCount;
206 &cmdBuffers[WRITE], // const VkCommandBuffer* pCommandBuffers;
207 1u, // deUint32 signalSemaphoreCount;
208 &semaphore.get(), // const VkSemaphore* pSignalSemaphores;
211 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
212 DE_NULL, // const void* pNext;
213 1u, // deUint32 waitSemaphoreCount;
214 &semaphore.get(), // const VkSemaphore* pWaitSemaphores;
215 stageBits, // const VkPipelineStageFlags* pWaitDstStageMask;
216 1u, // deUint32 commandBufferCount;
217 &cmdBuffers[READ], // const VkCommandBuffer* pCommandBuffers;
218 0u, // deUint32 signalSemaphoreCount;
219 DE_NULL, // const VkSemaphore* pSignalSemaphores;
222 const SyncInfo writeSync = m_writeOp->getSyncInfo();
223 const SyncInfo readSync = m_readOp->getSyncInfo();
225 beginCommandBuffer(vk, cmdBuffers[WRITE]);
227 m_writeOp->recordCommands(cmdBuffers[WRITE]);
229 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
231 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
232 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
233 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
236 endCommandBuffer(vk, cmdBuffers[WRITE]);
238 beginCommandBuffer(vk, cmdBuffers[READ]);
240 m_readOp->recordCommands(cmdBuffers[READ]);
242 endCommandBuffer(vk, cmdBuffers[READ]);
244 VK_CHECK(vk.queueSubmit(queue, 2u, submitInfo, DE_NULL));
245 VK_CHECK(vk.queueWaitIdle(queue));
248 const Data expected = m_writeOp->getData();
249 const Data actual = m_readOp->getData();
251 if (0 != deMemCmp(expected.data, actual.data, expected.size))
252 return tcu::TestStatus::fail("Memory contents don't match");
255 return tcu::TestStatus::pass("OK");
259 class FenceTestInstance : public BaseTestInstance
262 FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
263 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
267 tcu::TestStatus iterate (void)
269 enum {WRITE=0, READ, COUNT};
270 const DeviceInterface& vk = m_context.getDeviceInterface();
271 const VkDevice device = m_context.getDevice();
272 const VkQueue queue = m_context.getUniversalQueue();
273 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
274 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
275 const Move<VkCommandBuffer> ptrCmdBuffer[COUNT] = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
276 VkCommandBuffer cmdBuffers[COUNT] = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
277 const SyncInfo writeSync = m_writeOp->getSyncInfo();
278 const SyncInfo readSync = m_readOp->getSyncInfo();
280 beginCommandBuffer(vk, cmdBuffers[WRITE]);
282 m_writeOp->recordCommands(cmdBuffers[WRITE]);
284 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
286 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
287 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
288 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
291 endCommandBuffer(vk, cmdBuffers[WRITE]);
293 submitCommandsAndWait(vk, device, queue, cmdBuffers[WRITE]);
295 beginCommandBuffer(vk, cmdBuffers[READ]);
297 m_readOp->recordCommands(cmdBuffers[READ]);
299 endCommandBuffer(vk, cmdBuffers[READ]);
301 submitCommandsAndWait(vk, device, queue, cmdBuffers[READ]);
304 const Data expected = m_writeOp->getData();
305 const Data actual = m_readOp->getData();
307 if (0 != deMemCmp(expected.data, actual.data, expected.size))
308 return tcu::TestStatus::fail("Memory contents don't match");
311 return tcu::TestStatus::pass("OK");
315 class SyncTestCase : public TestCase
318 SyncTestCase (tcu::TestContext& testCtx,
319 const std::string& name,
320 const std::string& description,
321 const SyncPrimitive syncPrimitive,
322 const ResourceDescription resourceDesc,
323 const OperationName writeOp,
324 const OperationName readOp,
325 PipelineCacheData& pipelineCacheData)
326 : TestCase (testCtx, name, description)
327 , m_resourceDesc (resourceDesc)
328 , m_writeOp (makeOperationSupport(writeOp, resourceDesc))
329 , m_readOp (makeOperationSupport(readOp, resourceDesc))
330 , m_syncPrimitive (syncPrimitive)
331 , m_pipelineCacheData (pipelineCacheData)
335 void initPrograms (SourceCollections& programCollection) const
337 m_writeOp->initPrograms(programCollection);
338 m_readOp->initPrograms(programCollection);
341 TestInstance* createInstance (Context& context) const
343 switch (m_syncPrimitive)
345 case SYNC_PRIMITIVE_FENCE:
346 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
347 case SYNC_PRIMITIVE_SEMAPHORE:
348 return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
349 case SYNC_PRIMITIVE_BARRIER:
350 return new BarrierTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
351 case SYNC_PRIMITIVE_EVENT:
352 return new EventTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
360 const ResourceDescription m_resourceDesc;
361 const de::UniquePtr<OperationSupport> m_writeOp;
362 const de::UniquePtr<OperationSupport> m_readOp;
363 const SyncPrimitive m_syncPrimitive;
364 PipelineCacheData& m_pipelineCacheData;
367 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
369 tcu::TestContext& testCtx = group->getTestContext();
374 SyncPrimitive syncPrimitive;
378 { "fence", SYNC_PRIMITIVE_FENCE, 0, },
379 { "semaphore", SYNC_PRIMITIVE_SEMAPHORE, 0, },
380 { "barrier", SYNC_PRIMITIVE_BARRIER, 1, },
381 { "event", SYNC_PRIMITIVE_EVENT, 1, },
384 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
386 de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
388 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
389 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
391 const OperationName writeOp = s_writeOps[writeOpNdx];
392 const OperationName readOp = s_readOps[readOpNdx];
393 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
396 de::MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
398 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
400 const ResourceDescription& resource = s_resources[resourceNdx];
401 std::string name = getResourceName(resource);
403 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
405 opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, *pipelineCacheData));
410 synchGroup->addChild(opGroup.release());
413 group->addChild(synchGroup.release());
419 tcu::TestCaseGroup* createSynchronizedOperationSingleQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
421 return createTestGroup(testCtx, "single_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);