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 40namespace vkt 41{ 42namespace synchronization 43{ 44namespace 45{ 46using namespace vk; 47 48class BaseTestInstance : public TestInstance 49{ 50public: 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 60protected: 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 67class EventTestInstance : public BaseTestInstance 68{ 69public: 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 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 122class BarrierTestInstance : public BaseTestInstance 123{ 124public: 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 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 176class SemaphoreTestInstance : public BaseTestInstance 177{ 178public: 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 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 264class FenceTestInstance : public BaseTestInstance 265{ 266public: 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 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 320class SyncTestCase : public TestCase 321{ 322public: 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 340 void initPrograms (SourceCollections& programCollection) const 341 { 342 m_writeOp->initPrograms(programCollection); 343 m_readOp->initPrograms(programCollection); 344 } 345 346 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 364private: 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 372void 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 424tcu::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