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 "vkBarrierUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "deUniquePtr.hpp"
38 #include "tcuTestLog.hpp"
39 #include "vktSynchronizationUtil.hpp"
40 #include "vktSynchronizationOperation.hpp"
41 #include "vktSynchronizationOperationTestData.hpp"
42 #include "vktSynchronizationOperationResources.hpp"
46 namespace synchronization
52 class BaseTestInstance : public TestInstance
55 BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
56 : TestInstance (context)
57 , m_opContext (context, pipelineCacheData)
58 , m_resource (new Resource(m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
59 , m_writeOp (writeOp.build(m_opContext, *m_resource))
60 , m_readOp (readOp.build(m_opContext, *m_resource))
65 OperationContext m_opContext;
66 const de::UniquePtr<Resource> m_resource;
67 const de::UniquePtr<Operation> m_writeOp;
68 const de::UniquePtr<Operation> m_readOp;
71 class EventTestInstance : public BaseTestInstance
74 EventTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
75 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
79 tcu::TestStatus iterate (void)
81 const DeviceInterface& vk = m_context.getDeviceInterface();
82 const VkDevice device = m_context.getDevice();
83 const VkQueue queue = m_context.getUniversalQueue();
84 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
85 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
86 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
87 const Unique<VkEvent> event (createEvent(vk, device));
88 const SyncInfo writeSync = m_writeOp->getSyncInfo();
89 const SyncInfo readSync = m_readOp->getSyncInfo();
91 beginCommandBuffer(vk, *cmdBuffer);
93 m_writeOp->recordCommands(*cmdBuffer);
94 vk.cmdSetEvent(*cmdBuffer, *event, writeSync.stageMask);
96 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
98 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
99 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
100 vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
102 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
104 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
105 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
106 vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
109 m_readOp->recordCommands(*cmdBuffer);
111 endCommandBuffer(vk, *cmdBuffer);
112 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
115 const Data expected = m_writeOp->getData();
116 const Data actual = m_readOp->getData();
118 if (isIndirectBuffer(m_resource->getType()))
120 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
121 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
123 if (actualValue < expectedValue)
124 return tcu::TestStatus::fail("Counter value is smaller than expected");
128 if (0 != deMemCmp(expected.data, actual.data, expected.size))
129 return tcu::TestStatus::fail("Memory contents don't match");
133 return tcu::TestStatus::pass("OK");
137 class BarrierTestInstance : public BaseTestInstance
140 BarrierTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
141 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
145 tcu::TestStatus iterate (void)
147 const DeviceInterface& vk = m_context.getDeviceInterface();
148 const VkDevice device = m_context.getDevice();
149 const VkQueue queue = m_context.getUniversalQueue();
150 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
151 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
152 const Move<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
153 const SyncInfo writeSync = m_writeOp->getSyncInfo();
154 const SyncInfo readSync = m_readOp->getSyncInfo();
156 beginCommandBuffer(vk, *cmdBuffer);
158 m_writeOp->recordCommands(*cmdBuffer);
160 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
162 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
163 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
164 vk.cmdPipelineBarrier(*cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
166 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
168 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
169 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
170 vk.cmdPipelineBarrier(*cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
173 m_readOp->recordCommands(*cmdBuffer);
175 endCommandBuffer(vk, *cmdBuffer);
177 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
180 const Data expected = m_writeOp->getData();
181 const Data actual = m_readOp->getData();
183 if (isIndirectBuffer(m_resource->getType()))
185 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
186 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
188 if (actualValue < expectedValue)
189 return tcu::TestStatus::fail("Counter value is smaller than expected");
193 if (0 != deMemCmp(expected.data, actual.data, expected.size))
194 return tcu::TestStatus::fail("Memory contents don't match");
198 return tcu::TestStatus::pass("OK");
202 class SemaphoreTestInstance : public BaseTestInstance
205 SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
206 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
210 tcu::TestStatus iterate (void)
212 enum {WRITE=0, READ, COUNT};
213 const DeviceInterface& vk = m_context.getDeviceInterface();
214 const VkDevice device = m_context.getDevice();
215 const VkQueue queue = m_context.getUniversalQueue();
216 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
217 const Unique<VkSemaphore> semaphore (createSemaphore (vk, device));
218 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
219 const Move<VkCommandBuffer> ptrCmdBuffer[COUNT] = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
220 VkCommandBuffer cmdBuffers[COUNT] = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
221 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
222 const VkSubmitInfo submitInfo[2] =
225 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
226 DE_NULL, // const void* pNext;
227 0u, // deUint32 waitSemaphoreCount;
228 DE_NULL, // const VkSemaphore* pWaitSemaphores;
229 (const VkPipelineStageFlags*)DE_NULL,
230 1u, // deUint32 commandBufferCount;
231 &cmdBuffers[WRITE], // const VkCommandBuffer* pCommandBuffers;
232 1u, // deUint32 signalSemaphoreCount;
233 &semaphore.get(), // const VkSemaphore* pSignalSemaphores;
236 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
237 DE_NULL, // const void* pNext;
238 1u, // deUint32 waitSemaphoreCount;
239 &semaphore.get(), // const VkSemaphore* pWaitSemaphores;
240 stageBits, // const VkPipelineStageFlags* pWaitDstStageMask;
241 1u, // deUint32 commandBufferCount;
242 &cmdBuffers[READ], // const VkCommandBuffer* pCommandBuffers;
243 0u, // deUint32 signalSemaphoreCount;
244 DE_NULL, // const VkSemaphore* pSignalSemaphores;
247 const SyncInfo writeSync = m_writeOp->getSyncInfo();
248 const SyncInfo readSync = m_readOp->getSyncInfo();
250 beginCommandBuffer(vk, cmdBuffers[WRITE]);
252 m_writeOp->recordCommands(cmdBuffers[WRITE]);
254 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
256 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
257 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
258 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
262 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
263 m_resource->getBuffer().handle, 0, VK_WHOLE_SIZE);
264 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
267 endCommandBuffer(vk, cmdBuffers[WRITE]);
269 beginCommandBuffer(vk, cmdBuffers[READ]);
271 m_readOp->recordCommands(cmdBuffers[READ]);
273 endCommandBuffer(vk, cmdBuffers[READ]);
275 VK_CHECK(vk.queueSubmit(queue, 2u, submitInfo, DE_NULL));
276 VK_CHECK(vk.queueWaitIdle(queue));
279 const Data expected = m_writeOp->getData();
280 const Data actual = m_readOp->getData();
282 if (isIndirectBuffer(m_resource->getType()))
284 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
285 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
287 if (actualValue < expectedValue)
288 return tcu::TestStatus::fail("Counter value is smaller than expected");
292 if (0 != deMemCmp(expected.data, actual.data, expected.size))
293 return tcu::TestStatus::fail("Memory contents don't match");
297 return tcu::TestStatus::pass("OK");
301 class FenceTestInstance : public BaseTestInstance
304 FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
305 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
309 tcu::TestStatus iterate (void)
311 enum {WRITE=0, READ, COUNT};
312 const DeviceInterface& vk = m_context.getDeviceInterface();
313 const VkDevice device = m_context.getDevice();
314 const VkQueue queue = m_context.getUniversalQueue();
315 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
316 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
317 const Move<VkCommandBuffer> ptrCmdBuffer[COUNT] = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
318 VkCommandBuffer cmdBuffers[COUNT] = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
319 const SyncInfo writeSync = m_writeOp->getSyncInfo();
320 const SyncInfo readSync = m_readOp->getSyncInfo();
322 beginCommandBuffer(vk, cmdBuffers[WRITE]);
324 m_writeOp->recordCommands(cmdBuffers[WRITE]);
326 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
328 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
329 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
330 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
333 endCommandBuffer(vk, cmdBuffers[WRITE]);
335 submitCommandsAndWait(vk, device, queue, cmdBuffers[WRITE]);
337 beginCommandBuffer(vk, cmdBuffers[READ]);
339 m_readOp->recordCommands(cmdBuffers[READ]);
341 endCommandBuffer(vk, cmdBuffers[READ]);
343 submitCommandsAndWait(vk, device, queue, cmdBuffers[READ]);
346 const Data expected = m_writeOp->getData();
347 const Data actual = m_readOp->getData();
349 if (isIndirectBuffer(m_resource->getType()))
351 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
352 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
354 if (actualValue < expectedValue)
355 return tcu::TestStatus::fail("Counter value is smaller than expected");
359 if (0 != deMemCmp(expected.data, actual.data, expected.size))
360 return tcu::TestStatus::fail("Memory contents don't match");
364 return tcu::TestStatus::pass("OK");
368 class SyncTestCase : public TestCase
371 SyncTestCase (tcu::TestContext& testCtx,
372 const std::string& name,
373 const std::string& description,
374 const SyncPrimitive syncPrimitive,
375 const ResourceDescription resourceDesc,
376 const OperationName writeOp,
377 const OperationName readOp,
378 PipelineCacheData& pipelineCacheData)
379 : TestCase (testCtx, name, description)
380 , m_resourceDesc (resourceDesc)
381 , m_writeOp (makeOperationSupport(writeOp, resourceDesc))
382 , m_readOp (makeOperationSupport(readOp, resourceDesc))
383 , m_syncPrimitive (syncPrimitive)
384 , m_pipelineCacheData (pipelineCacheData)
388 void initPrograms (SourceCollections& programCollection) const
390 m_writeOp->initPrograms(programCollection);
391 m_readOp->initPrograms(programCollection);
394 TestInstance* createInstance (Context& context) const
396 switch (m_syncPrimitive)
398 case SYNC_PRIMITIVE_FENCE:
399 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
400 case SYNC_PRIMITIVE_SEMAPHORE:
401 return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
402 case SYNC_PRIMITIVE_BARRIER:
403 return new BarrierTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
404 case SYNC_PRIMITIVE_EVENT:
405 return new EventTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
413 const ResourceDescription m_resourceDesc;
414 const de::UniquePtr<OperationSupport> m_writeOp;
415 const de::UniquePtr<OperationSupport> m_readOp;
416 const SyncPrimitive m_syncPrimitive;
417 PipelineCacheData& m_pipelineCacheData;
420 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
422 tcu::TestContext& testCtx = group->getTestContext();
427 SyncPrimitive syncPrimitive;
431 { "fence", SYNC_PRIMITIVE_FENCE, 0, },
432 { "semaphore", SYNC_PRIMITIVE_SEMAPHORE, 0, },
433 { "barrier", SYNC_PRIMITIVE_BARRIER, 1, },
434 { "event", SYNC_PRIMITIVE_EVENT, 1, },
437 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
439 de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
441 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
442 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
444 const OperationName writeOp = s_writeOps[writeOpNdx];
445 const OperationName readOp = s_readOps[readOpNdx];
446 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
449 de::MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
451 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
453 const ResourceDescription& resource = s_resources[resourceNdx];
454 std::string name = getResourceName(resource);
456 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
458 opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, *pipelineCacheData));
463 synchGroup->addChild(opGroup.release());
466 group->addChild(synchGroup.release());
472 tcu::TestCaseGroup* createSynchronizedOperationSingleQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
474 return createTestGroup(testCtx, "single_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);