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 primitive tests with single queue
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSynchronizationOperationSingleQueueTests.hpp"
25 #include "vkDefs.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vkRef.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
40 namespace vkt
41 {
42 namespace synchronization
43 {
44 namespace
45 {
46 using namespace vk;
47
48 class BaseTestInstance : public TestInstance
49 {
50 public:
BaseTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)51 BaseTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
52 : TestInstance (context)
53 , m_opContext (context, pipelineCacheData)
54 , m_resource (new Resource(m_opContext, resourceDesc, writeOp.getResourceUsageFlags() | readOp.getResourceUsageFlags()))
55 , m_writeOp (writeOp.build(m_opContext, *m_resource))
56 , m_readOp (readOp.build(m_opContext, *m_resource))
57 {
58 }
59
60 protected:
61 OperationContext m_opContext;
62 const de::UniquePtr<Resource> m_resource;
63 const de::UniquePtr<Operation> m_writeOp;
64 const de::UniquePtr<Operation> m_readOp;
65 };
66
67 class EventTestInstance : public BaseTestInstance
68 {
69 public:
EventTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)70 EventTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
71 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
72 {
73 }
74
iterate(void)75 tcu::TestStatus iterate (void)
76 {
77 const DeviceInterface& vk = m_context.getDeviceInterface();
78 const VkDevice device = m_context.getDevice();
79 const VkQueue queue = m_context.getUniversalQueue();
80 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
81 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
82 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
83 const Unique<VkEvent> event (makeEvent(vk, device));
84 const SyncInfo writeSync = m_writeOp->getSyncInfo();
85 const SyncInfo readSync = m_readOp->getSyncInfo();
86
87 beginCommandBuffer(vk, *cmdBuffer);
88
89 m_writeOp->recordCommands(*cmdBuffer);
90 vk.cmdSetEvent(*cmdBuffer, *event, writeSync.stageMask);
91
92 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
93 {
94 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
95 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
96 vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
97 }
98 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
99 {
100 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
101 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
102 vk.cmdWaitEvents(*cmdBuffer, 1u, &event.get(), writeSync.stageMask, readSync.stageMask, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
103 }
104
105 m_readOp->recordCommands(*cmdBuffer);
106
107 endCommandBuffer(vk, *cmdBuffer);
108 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
109
110 {
111 const Data expected = m_writeOp->getData();
112 const Data actual = m_readOp->getData();
113
114 if (0 != deMemCmp(expected.data, actual.data, expected.size))
115 return tcu::TestStatus::fail("Memory contents don't match");
116 }
117
118 return tcu::TestStatus::pass("OK");
119 }
120 };
121
122 class BarrierTestInstance : public BaseTestInstance
123 {
124 public:
BarrierTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)125 BarrierTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
126 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
127 {
128 }
129
iterate(void)130 tcu::TestStatus iterate (void)
131 {
132 const DeviceInterface& vk = m_context.getDeviceInterface();
133 const VkDevice device = m_context.getDevice();
134 const VkQueue queue = m_context.getUniversalQueue();
135 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
136 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
137 const Move<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
138 const SyncInfo writeSync = m_writeOp->getSyncInfo();
139 const SyncInfo readSync = m_readOp->getSyncInfo();
140
141 beginCommandBuffer(vk, *cmdBuffer);
142
143 m_writeOp->recordCommands(*cmdBuffer);
144
145 if (m_resource->getType() == RESOURCE_TYPE_BUFFER || isIndirectBuffer(m_resource->getType()))
146 {
147 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(writeSync.accessMask, readSync.accessMask,
148 m_resource->getBuffer().handle, m_resource->getBuffer().offset, m_resource->getBuffer().size);
149 vk.cmdPipelineBarrier(*cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
150 }
151 else if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
152 {
153 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
154 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
155 vk.cmdPipelineBarrier(*cmdBuffer, writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
156 }
157
158 m_readOp->recordCommands(*cmdBuffer);
159
160 endCommandBuffer(vk, *cmdBuffer);
161
162 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
163
164 {
165 const Data expected = m_writeOp->getData();
166 const Data actual = m_readOp->getData();
167
168 if (0 != deMemCmp(expected.data, actual.data, expected.size))
169 return tcu::TestStatus::fail("Memory contents don't match");
170 }
171
172 return tcu::TestStatus::pass("OK");
173 }
174 };
175
176 class SemaphoreTestInstance : public BaseTestInstance
177 {
178 public:
SemaphoreTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)179 SemaphoreTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
180 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
181 {
182 }
183
iterate(void)184 tcu::TestStatus iterate (void)
185 {
186 enum {WRITE=0, READ, COUNT};
187 const DeviceInterface& vk = m_context.getDeviceInterface();
188 const VkDevice device = m_context.getDevice();
189 const VkQueue queue = m_context.getUniversalQueue();
190 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
191 const VkSemaphoreCreateInfo semaphoreInfo =
192 {
193 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, //VkStructureType sType;
194 DE_NULL, //const void* pNext;
195 0u //VkSemaphoreCreateFlags flags;
196 };
197 const Unique<VkSemaphore> semaphore (createSemaphore (vk, device, &semaphoreInfo, DE_NULL));
198 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
199 const Move<VkCommandBuffer> ptrCmdBuffer[COUNT] = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
200 VkCommandBuffer cmdBuffers[COUNT] = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
201 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
202 const VkSubmitInfo submitInfo[2] =
203 {
204 {
205 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
206 DE_NULL, // const void* pNext;
207 0u, // deUint32 waitSemaphoreCount;
208 DE_NULL, // const VkSemaphore* pWaitSemaphores;
209 (const VkPipelineStageFlags*)DE_NULL,
210 1u, // deUint32 commandBufferCount;
211 &cmdBuffers[WRITE], // const VkCommandBuffer* pCommandBuffers;
212 1u, // deUint32 signalSemaphoreCount;
213 &semaphore.get(), // const VkSemaphore* pSignalSemaphores;
214 },
215 {
216 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
217 DE_NULL, // const void* pNext;
218 1u, // deUint32 waitSemaphoreCount;
219 &semaphore.get(), // const VkSemaphore* pWaitSemaphores;
220 stageBits, // const VkPipelineStageFlags* pWaitDstStageMask;
221 1u, // deUint32 commandBufferCount;
222 &cmdBuffers[READ], // const VkCommandBuffer* pCommandBuffers;
223 0u, // deUint32 signalSemaphoreCount;
224 DE_NULL, // const VkSemaphore* pSignalSemaphores;
225 }
226 };
227 const SyncInfo writeSync = m_writeOp->getSyncInfo();
228 const SyncInfo readSync = m_readOp->getSyncInfo();
229
230 beginCommandBuffer(vk, cmdBuffers[WRITE]);
231
232 m_writeOp->recordCommands(cmdBuffers[WRITE]);
233
234 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
235 {
236 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
237 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
238 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
239 }
240
241 endCommandBuffer(vk, cmdBuffers[WRITE]);
242
243 beginCommandBuffer(vk, cmdBuffers[READ]);
244
245 m_readOp->recordCommands(cmdBuffers[READ]);
246
247 endCommandBuffer(vk, cmdBuffers[READ]);
248
249 VK_CHECK(vk.queueSubmit(queue, 2u, submitInfo, DE_NULL));
250 VK_CHECK(vk.queueWaitIdle(queue));
251
252 {
253 const Data expected = m_writeOp->getData();
254 const Data actual = m_readOp->getData();
255
256 if (0 != deMemCmp(expected.data, actual.data, expected.size))
257 return tcu::TestStatus::fail("Memory contents don't match");
258 }
259
260 return tcu::TestStatus::pass("OK");
261 }
262 };
263
264 class FenceTestInstance : public BaseTestInstance
265 {
266 public:
FenceTestInstance(Context & context,const ResourceDescription & resourceDesc,const OperationSupport & writeOp,const OperationSupport & readOp,PipelineCacheData & pipelineCacheData)267 FenceTestInstance (Context& context, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData)
268 : BaseTestInstance (context, resourceDesc, writeOp, readOp, pipelineCacheData)
269 {
270 }
271
iterate(void)272 tcu::TestStatus iterate (void)
273 {
274 enum {WRITE=0, READ, COUNT};
275 const DeviceInterface& vk = m_context.getDeviceInterface();
276 const VkDevice device = m_context.getDevice();
277 const VkQueue queue = m_context.getUniversalQueue();
278 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
279 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
280 const Move<VkCommandBuffer> ptrCmdBuffer[COUNT] = {makeCommandBuffer(vk, device, *cmdPool), makeCommandBuffer(vk, device, *cmdPool)};
281 VkCommandBuffer cmdBuffers[COUNT] = {*ptrCmdBuffer[WRITE], *ptrCmdBuffer[READ]};
282 const SyncInfo writeSync = m_writeOp->getSyncInfo();
283 const SyncInfo readSync = m_readOp->getSyncInfo();
284
285 beginCommandBuffer(vk, cmdBuffers[WRITE]);
286
287 m_writeOp->recordCommands(cmdBuffers[WRITE]);
288
289 if (m_resource->getType() == RESOURCE_TYPE_IMAGE)
290 {
291 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(writeSync.accessMask, readSync.accessMask,
292 writeSync.imageLayout, readSync.imageLayout, m_resource->getImage().handle, m_resource->getImage().subresourceRange);
293 vk.cmdPipelineBarrier(cmdBuffers[WRITE], writeSync.stageMask, readSync.stageMask, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &barrier);
294 }
295
296 endCommandBuffer(vk, cmdBuffers[WRITE]);
297
298 submitCommandsAndWait(vk, device, queue, cmdBuffers[WRITE]);
299
300 beginCommandBuffer(vk, cmdBuffers[READ]);
301
302 m_readOp->recordCommands(cmdBuffers[READ]);
303
304 endCommandBuffer(vk, cmdBuffers[READ]);
305
306 submitCommandsAndWait(vk, device, queue, cmdBuffers[READ]);
307
308 {
309 const Data expected = m_writeOp->getData();
310 const Data actual = m_readOp->getData();
311
312 if (0 != deMemCmp(expected.data, actual.data, expected.size))
313 return tcu::TestStatus::fail("Memory contents don't match");
314 }
315
316 return tcu::TestStatus::pass("OK");
317 }
318 };
319
320 class SyncTestCase : public TestCase
321 {
322 public:
SyncTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const SyncPrimitive syncPrimitive,const ResourceDescription resourceDesc,const OperationName writeOp,const OperationName readOp,PipelineCacheData & pipelineCacheData)323 SyncTestCase (tcu::TestContext& testCtx,
324 const std::string& name,
325 const std::string& description,
326 const SyncPrimitive syncPrimitive,
327 const ResourceDescription resourceDesc,
328 const OperationName writeOp,
329 const OperationName readOp,
330 PipelineCacheData& pipelineCacheData)
331 : TestCase (testCtx, name, description)
332 , m_resourceDesc (resourceDesc)
333 , m_writeOp (makeOperationSupport(writeOp, resourceDesc))
334 , m_readOp (makeOperationSupport(readOp, resourceDesc))
335 , m_syncPrimitive (syncPrimitive)
336 , m_pipelineCacheData (pipelineCacheData)
337 {
338 }
339
initPrograms(SourceCollections & programCollection) const340 void initPrograms (SourceCollections& programCollection) const
341 {
342 m_writeOp->initPrograms(programCollection);
343 m_readOp->initPrograms(programCollection);
344 }
345
createInstance(Context & context) const346 TestInstance* createInstance (Context& context) const
347 {
348 switch (m_syncPrimitive)
349 {
350 case SYNC_PRIMITIVE_FENCE:
351 return new FenceTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
352 case SYNC_PRIMITIVE_SEMAPHORE:
353 return new SemaphoreTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
354 case SYNC_PRIMITIVE_BARRIER:
355 return new BarrierTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
356 case SYNC_PRIMITIVE_EVENT:
357 return new EventTestInstance(context, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData);
358 }
359
360 DE_ASSERT(0);
361 return DE_NULL;
362 }
363
364 private:
365 const ResourceDescription m_resourceDesc;
366 const de::UniquePtr<OperationSupport> m_writeOp;
367 const de::UniquePtr<OperationSupport> m_readOp;
368 const SyncPrimitive m_syncPrimitive;
369 PipelineCacheData& m_pipelineCacheData;
370 };
371
createTests(tcu::TestCaseGroup * group,PipelineCacheData * pipelineCacheData)372 void createTests (tcu::TestCaseGroup* group, PipelineCacheData* pipelineCacheData)
373 {
374 tcu::TestContext& testCtx = group->getTestContext();
375
376 static const struct
377 {
378 const char* name;
379 SyncPrimitive syncPrimitive;
380 int numOptions;
381 } groups[] =
382 {
383 { "fence", SYNC_PRIMITIVE_FENCE, 0, },
384 { "semaphore", SYNC_PRIMITIVE_SEMAPHORE, 0, },
385 { "barrier", SYNC_PRIMITIVE_BARRIER, 1, },
386 { "event", SYNC_PRIMITIVE_EVENT, 1, },
387 };
388
389 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
390 {
391 de::MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name, ""));
392
393 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
394 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
395 {
396 const OperationName writeOp = s_writeOps[writeOpNdx];
397 const OperationName readOp = s_readOps[readOpNdx];
398 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
399 bool empty = true;
400
401 de::MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
402
403 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
404 {
405 const ResourceDescription& resource = s_resources[resourceNdx];
406 std::string name = getResourceName(resource);
407
408 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
409 {
410 opGroup->addChild(new SyncTestCase(testCtx, name, "", groups[groupNdx].syncPrimitive, resource, writeOp, readOp, *pipelineCacheData));
411 empty = false;
412 }
413 }
414 if (!empty)
415 synchGroup->addChild(opGroup.release());
416 }
417
418 group->addChild(synchGroup.release());
419 }
420 }
421
422 } // anonymous
423
createSynchronizedOperationSingleQueueTests(tcu::TestContext & testCtx,PipelineCacheData & pipelineCacheData)424 tcu::TestCaseGroup* createSynchronizedOperationSingleQueueTests (tcu::TestContext& testCtx, PipelineCacheData& pipelineCacheData)
425 {
426 return createTestGroup(testCtx, "single_queue", "Synchronization of a memory-modifying operation", createTests, &pipelineCacheData);
427 }
428
429 } // synchronization
430 } // vkt
431