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 multi queue 22 *//*--------------------------------------------------------------------*/ 23 24#include "vktSynchronizationOperationMultiQueueTests.hpp" 25#include "vktCustomInstancesDevices.hpp" 26#include "vkDefs.hpp" 27#include "vktTestCase.hpp" 28#include "vktTestCaseUtil.hpp" 29#include "vkRef.hpp" 30#include "vkRefUtil.hpp" 31#include "vkMemUtil.hpp" 32#include "vkBarrierUtil.hpp" 33#include "vkQueryUtil.hpp" 34#include "vkDeviceUtil.hpp" 35#include "vkTypeUtil.hpp" 36#include "vkPlatform.hpp" 37#include "vkCmdUtil.hpp" 38#include "vkSafetyCriticalUtil.hpp" 39#include "deRandom.hpp" 40#include "deUniquePtr.hpp" 41#include "deSharedPtr.hpp" 42#include "tcuTestLog.hpp" 43#include "vktSynchronizationUtil.hpp" 44#include "vktSynchronizationOperation.hpp" 45#include "vktSynchronizationOperationTestData.hpp" 46#include "vktSynchronizationOperationResources.hpp" 47#include "vktTestGroupUtil.hpp" 48#include "tcuCommandLine.hpp" 49 50#include <set> 51#include <unordered_map> 52 53namespace vkt 54{ 55 56namespace synchronization 57{ 58 59namespace 60{ 61using namespace vk; 62using de::MovePtr; 63using de::SharedPtr; 64using de::UniquePtr; 65using de::SharedPtr; 66 67enum QueueType 68{ 69 QUEUETYPE_WRITE, 70 QUEUETYPE_READ 71}; 72 73struct QueuePair 74{ 75 QueuePair (const deUint32 familyWrite, const deUint32 familyRead, const VkQueue write, const VkQueue read) 76 : familyIndexWrite (familyWrite) 77 , familyIndexRead (familyRead) 78 , queueWrite (write) 79 , queueRead (read) 80 {} 81 82 deUint32 familyIndexWrite; 83 deUint32 familyIndexRead; 84 VkQueue queueWrite; 85 VkQueue queueRead; 86}; 87 88struct Queue 89{ 90 Queue (const deUint32 familyOp, const VkQueue queueOp) 91 : family (familyOp) 92 , queue (queueOp) 93 {} 94 95 deUint32 family; 96 VkQueue queue; 97}; 98 99bool checkQueueFlags (VkQueueFlags availableFlags, const VkQueueFlags neededFlags) 100{ 101 if ((availableFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) != 0) 102 availableFlags |= VK_QUEUE_TRANSFER_BIT; 103 104 return (availableFlags & neededFlags) != 0; 105} 106 107class MultiQueues 108{ 109 struct QueueData 110 { 111 VkQueueFlags flags; 112 std::vector<VkQueue> queue; 113 }; 114 115 MultiQueues (Context& context, SynchronizationType type, bool timelineSemaphore) 116#ifdef CTS_USES_VULKANSC 117 : m_instance (createCustomInstanceFromContext(context)), 118#else 119 : 120#endif // CTS_USES_VULKANSC 121 m_queueCount (0) 122 { 123#ifdef CTS_USES_VULKANSC 124 const InstanceInterface& instanceDriver = m_instance.getDriver(); 125 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, m_instance, context.getTestContext().getCommandLine()); 126 const VkInstance instance = m_instance; 127#else 128 const InstanceInterface& instanceDriver = context.getInstanceInterface(); 129 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); 130 const VkInstance instance = context.getInstance(); 131#endif // CTS_USES_VULKANSC 132 const std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice); 133 134 for (deUint32 queuePropertiesNdx = 0; queuePropertiesNdx < queueFamilyProperties.size(); ++queuePropertiesNdx) 135 { 136 addQueueIndex(queuePropertiesNdx, 137 std::min(2u, queueFamilyProperties[queuePropertiesNdx].queueCount), 138 queueFamilyProperties[queuePropertiesNdx].queueFlags); 139 } 140 141 std::vector<VkDeviceQueueCreateInfo> queueInfos; 142 const float queuePriorities[2] = { 1.0f, 1.0f }; //get max 2 queues from one family 143 144 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it!= m_queues.end(); ++it) 145 { 146 const VkDeviceQueueCreateInfo queueInfo = 147 { 148 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, //VkStructureType sType; 149 DE_NULL, //const void* pNext; 150 (VkDeviceQueueCreateFlags)0u, //VkDeviceQueueCreateFlags flags; 151 it->first, //deUint32 queueFamilyIndex; 152 static_cast<deUint32>(it->second.queue.size()), //deUint32 queueCount; 153 &queuePriorities[0] //const float* pQueuePriorities; 154 }; 155 queueInfos.push_back(queueInfo); 156 } 157 158 { 159 VkPhysicalDeviceFeatures2 createPhysicalFeature { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, DE_NULL, context.getDeviceFeatures() }; 160 VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, DE_NULL, DE_TRUE }; 161 VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, DE_NULL, DE_TRUE }; 162 void** nextPtr = &createPhysicalFeature.pNext; 163 164 std::vector<const char*> deviceExtensions; 165 if (timelineSemaphore) 166 { 167 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_timeline_semaphore")) 168 deviceExtensions.push_back("VK_KHR_timeline_semaphore"); 169 addToChainVulkanStructure(&nextPtr, timelineSemaphoreFeatures); 170 } 171 if (type == SynchronizationType::SYNCHRONIZATION2) 172 { 173 deviceExtensions.push_back("VK_KHR_synchronization2"); 174 addToChainVulkanStructure(&nextPtr, synchronization2Features); 175 } 176 177 void* pNext = &createPhysicalFeature; 178#ifdef CTS_USES_VULKANSC 179 VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo(); 180 memReservationInfo.pNext = pNext; 181 pNext = &memReservationInfo; 182 183 VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features(); 184 sc10Features.pNext = pNext; 185 pNext = &sc10Features; 186 187 VkPipelineCacheCreateInfo pcCI; 188 std::vector<VkPipelinePoolSize> poolSizes; 189 if (context.getTestContext().getCommandLine().isSubProcess()) 190 { 191 if (context.getResourceInterface()->getCacheDataSize() > 0) 192 { 193 pcCI = 194 { 195 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType; 196 DE_NULL, // const void* pNext; 197 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT | 198 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags; 199 context.getResourceInterface()->getCacheDataSize(), // deUintptr initialDataSize; 200 context.getResourceInterface()->getCacheData() // const void* pInitialData; 201 }; 202 memReservationInfo.pipelineCacheCreateInfoCount = 1; 203 memReservationInfo.pPipelineCacheCreateInfos = &pcCI; 204 } 205 206 poolSizes = context.getResourceInterface()->getPipelinePoolSizes(); 207 if (!poolSizes.empty()) 208 { 209 memReservationInfo.pipelinePoolSizeCount = deUint32(poolSizes.size()); 210 memReservationInfo.pPipelinePoolSizes = poolSizes.data(); 211 } 212 } 213#endif // CTS_USES_VULKANSC 214 215 const VkDeviceCreateInfo deviceInfo = 216 { 217 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //VkStructureType sType; 218 pNext, //const void* pNext; 219 0u, //VkDeviceCreateFlags flags; 220 static_cast<deUint32>(queueInfos.size()), //deUint32 queueCreateInfoCount; 221 &queueInfos[0], //const VkDeviceQueueCreateInfo* pQueueCreateInfos; 222 0u, //deUint32 enabledLayerCount; 223 DE_NULL, //const char* const* ppEnabledLayerNames; 224 static_cast<deUint32>(deviceExtensions.size()), //deUint32 enabledExtensionCount; 225 deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0], //const char* const* ppEnabledExtensionNames; 226 DE_NULL //const VkPhysicalDeviceFeatures* pEnabledFeatures; 227 }; 228 229 m_logicalDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instance, instanceDriver, physicalDevice, &deviceInfo); 230#ifndef CTS_USES_VULKANSC 231 m_deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), instance, *m_logicalDevice, context.getUsedApiVersion())); 232#else 233 m_deviceDriver = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(context.getPlatformInterface(), instance, *m_logicalDevice, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(), context.getUsedApiVersion()), vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *m_logicalDevice)); 234#endif // CTS_USES_VULKANSC 235 m_allocator = MovePtr<Allocator>(new SimpleAllocator(*m_deviceDriver, *m_logicalDevice, getPhysicalDeviceMemoryProperties(instanceDriver, physicalDevice))); 236 237 for (std::map<deUint32, QueueData>::iterator it = m_queues.begin(); it != m_queues.end(); ++it) 238 for (int queueNdx = 0; queueNdx < static_cast<int>(it->second.queue.size()); ++queueNdx) 239 m_deviceDriver->getDeviceQueue(*m_logicalDevice, it->first, queueNdx, &it->second.queue[queueNdx]); 240 } 241 } 242 243 void addQueueIndex (const deUint32 queueFamilyIndex, const deUint32 count, const VkQueueFlags flags) 244 { 245 QueueData dataToPush; 246 dataToPush.flags = flags; 247 dataToPush.queue.resize(count); 248 m_queues[queueFamilyIndex] = dataToPush; 249 250 m_queueCount++; 251 } 252 253public: 254 ~MultiQueues() 255 { 256 } 257 258 std::vector<QueuePair> getQueuesPairs (const VkQueueFlags flagsWrite, const VkQueueFlags flagsRead) const 259 { 260 std::map<deUint32, QueueData> queuesWrite; 261 std::map<deUint32, QueueData> queuesRead; 262 std::vector<QueuePair> queuesPairs; 263 264 for (std::map<deUint32, QueueData>::const_iterator it = m_queues.begin(); it != m_queues.end(); ++it) 265 { 266 const bool writeQueue = checkQueueFlags(it->second.flags, flagsWrite); 267 const bool readQueue = checkQueueFlags(it->second.flags, flagsRead); 268 269 if (!(writeQueue || readQueue)) 270 continue; 271 272 if (writeQueue && readQueue) 273 { 274 queuesWrite[it->first] = it->second; 275 queuesRead[it->first] = it->second; 276 } 277 else if (writeQueue) 278 queuesWrite[it->first] = it->second; 279 else if (readQueue) 280 queuesRead[it->first] = it->second; 281 } 282 283 for (std::map<deUint32, QueueData>::iterator write = queuesWrite.begin(); write != queuesWrite.end(); ++write) 284 for (std::map<deUint32, QueueData>::iterator read = queuesRead.begin(); read != queuesRead.end(); ++read) 285 { 286 const int writeSize = static_cast<int>(write->second.queue.size()); 287 const int readSize = static_cast<int>(read->second.queue.size()); 288 289 for (int writeNdx = 0; writeNdx < writeSize; ++writeNdx) 290 for (int readNdx = 0; readNdx < readSize; ++readNdx) 291 { 292 if (write->second.queue[writeNdx] != read->second.queue[readNdx]) 293 { 294 queuesPairs.push_back(QueuePair(write->first, read->first, write->second.queue[writeNdx], read->second.queue[readNdx])); 295 writeNdx = readNdx = std::max(writeSize, readSize); //exit from the loops 296 } 297 } 298 } 299 300 if (queuesPairs.empty()) 301 TCU_THROW(NotSupportedError, "Queue not found"); 302 303 return queuesPairs; 304 } 305 306 Queue getDefaultQueue(const VkQueueFlags flagsOp) const 307 { 308 for (std::map<deUint32, QueueData>::const_iterator it = m_queues.begin(); it!= m_queues.end(); ++it) 309 { 310 if (checkQueueFlags(it->second.flags, flagsOp)) 311 return Queue(it->first, it->second.queue[0]); 312 } 313 314 TCU_THROW(NotSupportedError, "Queue not found"); 315 } 316 317 Queue getQueue (const deUint32 familyIdx, const deUint32 queueIdx) 318 { 319 return Queue(familyIdx, m_queues[familyIdx].queue[queueIdx]); 320 } 321 322 VkQueueFlags getQueueFamilyFlags (const deUint32 familyIdx) 323 { 324 return m_queues[familyIdx].flags; 325 } 326 327 deUint32 queueFamilyCount (const deUint32 familyIdx) 328 { 329 return (deUint32) m_queues[familyIdx].queue.size(); 330 } 331 332 deUint32 familyCount (void) const 333 { 334 return (deUint32) m_queues.size(); 335 } 336 337 deUint32 totalQueueCount (void) 338 { 339 deUint32 count = 0; 340 341 for (deUint32 familyIdx = 0; familyIdx < familyCount(); familyIdx++) 342 { 343 count += queueFamilyCount(familyIdx); 344 } 345 346 return count; 347 } 348 349 VkDevice getDevice (void) const 350 { 351 return *m_logicalDevice; 352 } 353 354 const DeviceInterface& getDeviceInterface (void) const 355 { 356 return *m_deviceDriver; 357 } 358 359 Allocator& getAllocator (void) 360 { 361 return *m_allocator; 362 } 363 364 static SharedPtr<MultiQueues> getInstance(Context& context, SynchronizationType type, bool timelineSemaphore) 365 { 366 deUint32 index = (deUint32)type << 1 | timelineSemaphore; 367 if (!m_multiQueues[index]) 368 m_multiQueues[index] = SharedPtr<MultiQueues>(new MultiQueues(context, type, timelineSemaphore)); 369 370 return m_multiQueues[index]; 371 } 372 static void destroy() 373 { 374 m_multiQueues.clear(); 375 } 376 377private: 378#ifdef CTS_USES_VULKANSC 379 CustomInstance m_instance; 380#endif // CTS_USES_VULKANSC 381 Move<VkDevice> m_logicalDevice; 382#ifndef CTS_USES_VULKANSC 383 de::MovePtr<vk::DeviceDriver> m_deviceDriver; 384#else 385 de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter> m_deviceDriver; 386#endif // CTS_USES_VULKANSC 387 MovePtr<Allocator> m_allocator; 388 std::map<deUint32, QueueData> m_queues; 389 deUint32 m_queueCount; 390 391 static std::unordered_map<deUint32, SharedPtr<MultiQueues>> m_multiQueues; 392}; 393std::unordered_map<deUint32, SharedPtr<MultiQueues>> MultiQueues::m_multiQueues; 394 395void createBarrierMultiQueue (SynchronizationWrapperPtr synchronizationWrapper, 396 const VkCommandBuffer& cmdBuffer, 397 const SyncInfo& writeSync, 398 const SyncInfo& readSync, 399 const Resource& resource, 400 const deUint32 writeFamily, 401 const deUint32 readFamily, 402 const VkSharingMode sharingMode, 403 const bool secondQueue = false) 404{ 405 if (resource.getType() == RESOURCE_TYPE_IMAGE) 406 { 407 VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2( 408 secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask, 409 secondQueue ? 0u : writeSync.accessMask, 410 !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, 411 !secondQueue ? 0u : readSync.accessMask, 412 writeSync.imageLayout, 413 readSync.imageLayout, 414 resource.getImage().handle, 415 resource.getImage().subresourceRange 416 ); 417 418 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode) 419 { 420 imageMemoryBarrier2.srcQueueFamilyIndex = writeFamily; 421 imageMemoryBarrier2.dstQueueFamilyIndex = readFamily; 422 423 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); 424 synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); 425 } 426 else if (!secondQueue) 427 { 428 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2); 429 synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); 430 } 431 } 432 else 433 { 434 VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2( 435 secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) : writeSync.stageMask, 436 secondQueue ? 0u : writeSync.accessMask, 437 !secondQueue ? VkPipelineStageFlags(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT) : readSync.stageMask, 438 !secondQueue ? 0u : readSync.accessMask, 439 resource.getBuffer().handle, 440 resource.getBuffer().offset, 441 resource.getBuffer().size 442 ); 443 444 if (writeFamily != readFamily && VK_SHARING_MODE_EXCLUSIVE == sharingMode) 445 { 446 bufferMemoryBarrier2.srcQueueFamilyIndex = writeFamily; 447 bufferMemoryBarrier2.dstQueueFamilyIndex = readFamily; 448 } 449 450 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2); 451 synchronizationWrapper->cmdPipelineBarrier(cmdBuffer, &dependencyInfo); 452 } 453} 454 455class BaseTestInstance : public TestInstance 456{ 457public: 458 BaseTestInstance (Context& context, SynchronizationType type, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, bool timelineSemaphore) 459 : TestInstance (context) 460 , m_type (type) 461 , m_queues (MultiQueues::getInstance(context, type, timelineSemaphore)) 462 , m_opContext (new OperationContext(context, type, m_queues->getDeviceInterface(), m_queues->getDevice(), m_queues->getAllocator(), pipelineCacheData)) 463 , m_resourceDesc (resourceDesc) 464 , m_writeOp (writeOp) 465 , m_readOp (readOp) 466 { 467 } 468 469protected: 470 const SynchronizationType m_type; 471 const SharedPtr<MultiQueues> m_queues; 472 const UniquePtr<OperationContext> m_opContext; 473 const ResourceDescription m_resourceDesc; 474 const OperationSupport& m_writeOp; 475 const OperationSupport& m_readOp; 476}; 477 478class BinarySemaphoreTestInstance : public BaseTestInstance 479{ 480public: 481 BinarySemaphoreTestInstance (Context& context, SynchronizationType type, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode) 482 : BaseTestInstance (context, type, resourceDesc, writeOp, readOp, pipelineCacheData, false) 483 , m_sharingMode (sharingMode) 484 { 485 } 486 487 tcu::TestStatus iterate (void) 488 { 489 const DeviceInterface& vk = m_opContext->getDeviceInterface(); 490 const VkDevice device = m_opContext->getDevice(); 491 const std::vector<QueuePair> queuePairs = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext)); 492 493 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx) 494 { 495 const UniquePtr<Resource> resource (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getOutResourceUsageFlags() | m_readOp.getInResourceUsageFlags())); 496 const UniquePtr<Operation> writeOp (m_writeOp.build(*m_opContext, *resource)); 497 const UniquePtr<Operation> readOp (m_readOp.build (*m_opContext, *resource)); 498 499 const Move<VkCommandPool> cmdPool[] = 500 { 501 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite), 502 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead) 503 }; 504 const Move<VkCommandBuffer> ptrCmdBuffer[] = 505 { 506 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]), 507 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ]) 508 }; 509 const VkCommandBufferSubmitInfoKHR cmdBufferInfos[] = 510 { 511 makeCommonCommandBufferSubmitInfo(*ptrCmdBuffer[QUEUETYPE_WRITE]), 512 makeCommonCommandBufferSubmitInfo(*ptrCmdBuffer[QUEUETYPE_READ]), 513 }; 514 const Unique<VkSemaphore> semaphore (createSemaphore(vk, device)); 515 VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo = 516 makeCommonSemaphoreSubmitInfo(*semaphore, 0u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR); 517 VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo = 518 makeCommonSemaphoreSubmitInfo(*semaphore, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR); 519 SynchronizationWrapperPtr synchronizationWrapper[] 520 { 521 getSynchronizationWrapper(m_type, vk, DE_FALSE), 522 getSynchronizationWrapper(m_type, vk, DE_FALSE), 523 }; 524 525 synchronizationWrapper[QUEUETYPE_WRITE]->addSubmitInfo( 526 0u, 527 DE_NULL, 528 1u, 529 &cmdBufferInfos[QUEUETYPE_WRITE], 530 1u, 531 &signalSemaphoreSubmitInfo 532 ); 533 synchronizationWrapper[QUEUETYPE_READ]->addSubmitInfo( 534 1u, 535 &waitSemaphoreSubmitInfo, 536 1u, 537 &cmdBufferInfos[QUEUETYPE_READ], 538 0u, 539 DE_NULL 540 ); 541 542 const SyncInfo writeSync = writeOp->getOutSyncInfo(); 543 const SyncInfo readSync = readOp->getInSyncInfo(); 544 VkCommandBuffer writeCmdBuffer = cmdBufferInfos[QUEUETYPE_WRITE].commandBuffer; 545 VkCommandBuffer readCmdBuffer = cmdBufferInfos[QUEUETYPE_READ].commandBuffer; 546 547 beginCommandBuffer (vk, writeCmdBuffer); 548 writeOp->recordCommands (writeCmdBuffer); 549 createBarrierMultiQueue (synchronizationWrapper[QUEUETYPE_WRITE], writeCmdBuffer, writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode); 550 endCommandBuffer (vk, writeCmdBuffer); 551 552 beginCommandBuffer (vk, readCmdBuffer); 553 createBarrierMultiQueue (synchronizationWrapper[QUEUETYPE_READ], readCmdBuffer, writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true); 554 readOp->recordCommands (readCmdBuffer); 555 endCommandBuffer (vk, readCmdBuffer); 556 557 VK_CHECK(synchronizationWrapper[QUEUETYPE_WRITE]->queueSubmit(queuePairs[pairNdx].queueWrite, DE_NULL)); 558 VK_CHECK(synchronizationWrapper[QUEUETYPE_READ]->queueSubmit(queuePairs[pairNdx].queueRead, DE_NULL)); 559 VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueWrite)); 560 VK_CHECK(vk.queueWaitIdle(queuePairs[pairNdx].queueRead)); 561 562 { 563 const Data expected = writeOp->getData(); 564 const Data actual = readOp->getData(); 565 566#ifdef CTS_USES_VULKANSC 567 if (m_context.getTestContext().getCommandLine().isSubProcess()) 568#endif // CTS_USES_VULKANSC 569 { 570 if (isIndirectBuffer(m_resourceDesc.type)) 571 { 572 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0]; 573 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0]; 574 575 if (actualValue < expectedValue) 576 return tcu::TestStatus::fail("Counter value is smaller than expected"); 577 } 578 else 579 { 580 if (0 != deMemCmp(expected.data, actual.data, expected.size)) 581 return tcu::TestStatus::fail("Memory contents don't match"); 582 } 583 } 584 } 585 } 586 return tcu::TestStatus::pass("OK"); 587 } 588 589private: 590 const VkSharingMode m_sharingMode; 591}; 592 593template<typename T> 594inline SharedPtr<Move<T> > makeVkSharedPtr (Move<T> move) 595{ 596 return SharedPtr<Move<T> >(new Move<T>(move)); 597} 598 599class TimelineSemaphoreTestInstance : public BaseTestInstance 600{ 601public: 602 TimelineSemaphoreTestInstance (Context& context, SynchronizationType type, const ResourceDescription& resourceDesc, const SharedPtr<OperationSupport>& writeOp, const SharedPtr<OperationSupport>& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode) 603 : BaseTestInstance (context, type, resourceDesc, *writeOp, *readOp, pipelineCacheData, true) 604 , m_sharingMode (sharingMode) 605 { 606 deUint32 maxQueues = 0; 607 std::vector<deUint32> queueFamilies; 608 609 if (m_queues->totalQueueCount() < 2) 610 TCU_THROW(NotSupportedError, "Not enough queues"); 611 612 for (deUint32 familyNdx = 0; familyNdx < m_queues->familyCount(); familyNdx++) 613 { 614 maxQueues = std::max(m_queues->queueFamilyCount(familyNdx), maxQueues); 615 queueFamilies.push_back(familyNdx); 616 } 617 618 // Create a chain of operations copying data from one resource 619 // to another across at least every single queue of the system 620 // at least once. Each of the operation will be executing with 621 // a dependency on the previous using timeline points. 622 m_opSupports.push_back(writeOp); 623 m_opQueues.push_back(m_queues->getDefaultQueue(writeOp->getQueueFlags(*m_opContext))); 624 625 for (deUint32 queueIdx = 0; queueIdx < maxQueues; queueIdx++) 626 { 627 for (deUint32 familyIdx = 0; familyIdx < m_queues->familyCount(); familyIdx++) 628 { 629 for (deUint32 copyOpIdx = 0; copyOpIdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpIdx++) 630 { 631 if (isResourceSupported(s_copyOps[copyOpIdx], resourceDesc)) 632 { 633 SharedPtr<OperationSupport> opSupport (makeOperationSupport(s_copyOps[copyOpIdx], m_resourceDesc).release()); 634 635 if (!checkQueueFlags(opSupport->getQueueFlags(*m_opContext), m_queues->getQueueFamilyFlags(familyIdx))) 636 continue; 637 638 m_opSupports.push_back(opSupport); 639 m_opQueues.push_back(m_queues->getQueue(familyIdx, queueIdx % m_queues->queueFamilyCount(familyIdx))); 640 break; 641 } 642 } 643 } 644 } 645 646 m_opSupports.push_back(readOp); 647 m_opQueues.push_back(m_queues->getDefaultQueue(readOp->getQueueFlags(*m_opContext))); 648 649 // Now create the resources with the usage associated to the 650 // operation performed on the resource. 651 for (deUint32 opIdx = 0; opIdx < (m_opSupports.size() - 1); opIdx++) 652 { 653 deUint32 usage = m_opSupports[opIdx]->getOutResourceUsageFlags() | m_opSupports[opIdx + 1]->getInResourceUsageFlags(); 654 655 m_resources.push_back(SharedPtr<Resource>(new Resource(*m_opContext, m_resourceDesc, usage, m_sharingMode, queueFamilies))); 656 } 657 658 // Finally create the operations using the resources. 659 m_ops.push_back(SharedPtr<Operation>(m_opSupports[0]->build(*m_opContext, *m_resources[0]).release())); 660 for (deUint32 opIdx = 1; opIdx < (m_opSupports.size() - 1); opIdx++) 661 m_ops.push_back(SharedPtr<Operation>(m_opSupports[opIdx]->build(*m_opContext, *m_resources[opIdx - 1], *m_resources[opIdx]).release())); 662 m_ops.push_back(SharedPtr<Operation>(m_opSupports[m_opSupports.size() - 1]->build(*m_opContext, *m_resources.back()).release())); 663 } 664 665 tcu::TestStatus iterate (void) 666 { 667 const DeviceInterface& vk = m_opContext->getDeviceInterface(); 668 const VkDevice device = m_opContext->getDevice(); 669 de::Random rng (1234); 670 const Unique<VkSemaphore> semaphore (createSemaphoreType(vk, device, VK_SEMAPHORE_TYPE_TIMELINE)); 671 std::vector<SharedPtr<Move<VkCommandPool> > > cmdPools; 672 std::vector<SharedPtr<Move<VkCommandBuffer> > > ptrCmdBuffers; 673 std::vector<VkCommandBufferSubmitInfoKHR> cmdBufferInfos; 674 std::vector<deUint64> timelineValues; 675 676 cmdPools.resize(m_queues->familyCount()); 677 for (deUint32 familyIdx = 0; familyIdx < m_queues->familyCount(); familyIdx++) 678 cmdPools[familyIdx] = makeVkSharedPtr(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, familyIdx)); 679 680 ptrCmdBuffers.resize(m_ops.size()); 681 cmdBufferInfos.resize(m_ops.size()); 682 for (deUint32 opIdx = 0; opIdx < m_ops.size(); opIdx++) 683 { 684 deUint64 increment = 1 + rng.getUint8(); 685 686 ptrCmdBuffers[opIdx] = makeVkSharedPtr(makeCommandBuffer(vk, device, **cmdPools[m_opQueues[opIdx].family])); 687 cmdBufferInfos[opIdx] = makeCommonCommandBufferSubmitInfo(**ptrCmdBuffers[opIdx]); 688 689 timelineValues.push_back(timelineValues.empty() ? increment : (timelineValues.back() + increment)); 690 } 691 692 for (deUint32 opIdx = 0; opIdx < m_ops.size(); opIdx++) 693 { 694 VkCommandBuffer cmdBuffer = cmdBufferInfos[opIdx].commandBuffer; 695 VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo = 696 makeCommonSemaphoreSubmitInfo(*semaphore, (opIdx == 0 ? 0u : timelineValues[opIdx - 1]), VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR); 697 VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo = 698 makeCommonSemaphoreSubmitInfo(*semaphore, timelineValues[opIdx], VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR); 699 SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_type, vk, DE_TRUE); 700 701 synchronizationWrapper->addSubmitInfo( 702 opIdx == 0 ? 0u : 1u, 703 &waitSemaphoreSubmitInfo, 704 1u, 705 &cmdBufferInfos[opIdx], 706 1u, 707 &signalSemaphoreSubmitInfo, 708 opIdx == 0 ? DE_FALSE : DE_TRUE, 709 DE_TRUE 710 ); 711 712 beginCommandBuffer(vk, cmdBuffer); 713 714 if (opIdx > 0) 715 { 716 const SyncInfo writeSync = m_ops[opIdx - 1]->getOutSyncInfo(); 717 const SyncInfo readSync = m_ops[opIdx]->getInSyncInfo(); 718 const Resource& resource = *m_resources[opIdx - 1].get(); 719 720 createBarrierMultiQueue(synchronizationWrapper, cmdBuffer, writeSync, readSync, resource, m_opQueues[opIdx - 1].family, m_opQueues[opIdx].family, m_sharingMode, true); 721 } 722 723 m_ops[opIdx]->recordCommands(cmdBuffer); 724 725 if (opIdx < (m_ops.size() - 1)) 726 { 727 const SyncInfo writeSync = m_ops[opIdx]->getOutSyncInfo(); 728 const SyncInfo readSync = m_ops[opIdx + 1]->getInSyncInfo(); 729 const Resource& resource = *m_resources[opIdx].get(); 730 731 createBarrierMultiQueue(synchronizationWrapper, cmdBuffer, writeSync, readSync, resource, m_opQueues[opIdx].family, m_opQueues[opIdx + 1].family, m_sharingMode); 732 } 733 734 endCommandBuffer(vk, cmdBuffer); 735 736 VK_CHECK(synchronizationWrapper->queueSubmit(m_opQueues[opIdx].queue, DE_NULL)); 737 } 738 739 740 VK_CHECK(vk.queueWaitIdle(m_opQueues.back().queue)); 741 742 { 743 const Data expected = m_ops.front()->getData(); 744 const Data actual = m_ops.back()->getData(); 745 746 if (isIndirectBuffer(m_resourceDesc.type)) 747 { 748 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0]; 749 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0]; 750 751 if (actualValue < expectedValue) 752 return tcu::TestStatus::fail("Counter value is smaller than expected"); 753 } 754 else 755 { 756 if (0 != deMemCmp(expected.data, actual.data, expected.size)) 757 return tcu::TestStatus::fail("Memory contents don't match"); 758 } 759 } 760 761 // Make the validation layers happy. 762 for (deUint32 opIdx = 0; opIdx < m_opQueues.size(); opIdx++) 763 VK_CHECK(vk.queueWaitIdle(m_opQueues[opIdx].queue)); 764 765 return tcu::TestStatus::pass("OK"); 766 } 767 768private: 769 const VkSharingMode m_sharingMode; 770 std::vector<SharedPtr<OperationSupport> > m_opSupports; 771 std::vector<SharedPtr<Operation> > m_ops; 772 std::vector<SharedPtr<Resource> > m_resources; 773 std::vector<Queue> m_opQueues; 774}; 775 776class FenceTestInstance : public BaseTestInstance 777{ 778public: 779 FenceTestInstance (Context& context, SynchronizationType type, const ResourceDescription& resourceDesc, const OperationSupport& writeOp, const OperationSupport& readOp, PipelineCacheData& pipelineCacheData, const VkSharingMode sharingMode) 780 : BaseTestInstance (context, type, resourceDesc, writeOp, readOp, pipelineCacheData, false) 781 , m_sharingMode (sharingMode) 782 { 783 } 784 785 tcu::TestStatus iterate (void) 786 { 787 const DeviceInterface& vk = m_opContext->getDeviceInterface(); 788 const VkDevice device = m_opContext->getDevice(); 789 const std::vector<QueuePair> queuePairs = m_queues->getQueuesPairs(m_writeOp.getQueueFlags(*m_opContext), m_readOp.getQueueFlags(*m_opContext)); 790 791 for (deUint32 pairNdx = 0; pairNdx < static_cast<deUint32>(queuePairs.size()); ++pairNdx) 792 { 793 const UniquePtr<Resource> resource (new Resource(*m_opContext, m_resourceDesc, m_writeOp.getOutResourceUsageFlags() | m_readOp.getInResourceUsageFlags())); 794 const UniquePtr<Operation> writeOp (m_writeOp.build(*m_opContext, *resource)); 795 const UniquePtr<Operation> readOp (m_readOp.build(*m_opContext, *resource)); 796 const Move<VkCommandPool> cmdPool[] 797 { 798 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexWrite), 799 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queuePairs[pairNdx].familyIndexRead) 800 }; 801 const Move<VkCommandBuffer> ptrCmdBuffer[] 802 { 803 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_WRITE]), 804 makeCommandBuffer(vk, device, *cmdPool[QUEUETYPE_READ]) 805 }; 806 const VkCommandBufferSubmitInfoKHR cmdBufferInfos[] 807 { 808 makeCommonCommandBufferSubmitInfo(*ptrCmdBuffer[QUEUETYPE_WRITE]), 809 makeCommonCommandBufferSubmitInfo(*ptrCmdBuffer[QUEUETYPE_READ]) 810 }; 811 SynchronizationWrapperPtr synchronizationWrapper[] 812 { 813 getSynchronizationWrapper(m_type, vk, DE_FALSE), 814 getSynchronizationWrapper(m_type, vk, DE_FALSE), 815 }; 816 const SyncInfo writeSync = writeOp->getOutSyncInfo(); 817 const SyncInfo readSync = readOp->getInSyncInfo(); 818 VkCommandBuffer writeCmdBuffer = cmdBufferInfos[QUEUETYPE_WRITE].commandBuffer; 819 VkCommandBuffer readCmdBuffer = cmdBufferInfos[QUEUETYPE_READ].commandBuffer; 820 821 beginCommandBuffer (vk, writeCmdBuffer); 822 writeOp->recordCommands (writeCmdBuffer); 823 createBarrierMultiQueue (synchronizationWrapper[QUEUETYPE_WRITE], writeCmdBuffer, writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode); 824 endCommandBuffer (vk, writeCmdBuffer); 825 826 submitCommandsAndWait (synchronizationWrapper[QUEUETYPE_WRITE], vk, device, queuePairs[pairNdx].queueWrite, writeCmdBuffer); 827 828 beginCommandBuffer (vk, readCmdBuffer); 829 createBarrierMultiQueue (synchronizationWrapper[QUEUETYPE_READ], readCmdBuffer, writeSync, readSync, *resource, queuePairs[pairNdx].familyIndexWrite, queuePairs[pairNdx].familyIndexRead, m_sharingMode, true); 830 readOp->recordCommands (readCmdBuffer); 831 endCommandBuffer (vk, readCmdBuffer); 832 833 submitCommandsAndWait(synchronizationWrapper[QUEUETYPE_READ], vk, device, queuePairs[pairNdx].queueRead, readCmdBuffer); 834 835 { 836 const Data expected = writeOp->getData(); 837 const Data actual = readOp->getData(); 838 839#ifdef CTS_USES_VULKANSC 840 if (m_context.getTestContext().getCommandLine().isSubProcess()) 841#endif // CTS_USES_VULKANSC 842 { 843 if (isIndirectBuffer(m_resourceDesc.type)) 844 { 845 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0]; 846 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0]; 847 848 if (actualValue < expectedValue) 849 return tcu::TestStatus::fail("Counter value is smaller than expected"); 850 } 851 else 852 { 853 if (0 != deMemCmp(expected.data, actual.data, expected.size)) 854 return tcu::TestStatus::fail("Memory contents don't match"); 855 } 856 } 857 } 858 } 859 return tcu::TestStatus::pass("OK"); 860 } 861 862private: 863 const VkSharingMode m_sharingMode; 864}; 865 866class BaseTestCase : public TestCase 867{ 868public: 869 BaseTestCase (tcu::TestContext& testCtx, 870 const std::string& name, 871 SynchronizationType type, 872 const SyncPrimitive syncPrimitive, 873 const ResourceDescription resourceDesc, 874 const OperationName writeOp, 875 const OperationName readOp, 876 const VkSharingMode sharingMode, 877 PipelineCacheData& pipelineCacheData) 878 : TestCase (testCtx, name) 879 , m_type (type) 880 , m_resourceDesc (resourceDesc) 881 , m_writeOp (makeOperationSupport(writeOp, resourceDesc).release()) 882 , m_readOp (makeOperationSupport(readOp, resourceDesc).release()) 883 , m_syncPrimitive (syncPrimitive) 884 , m_sharingMode (sharingMode) 885 , m_pipelineCacheData (pipelineCacheData) 886 { 887 } 888 889 void initPrograms (SourceCollections& programCollection) const 890 { 891 m_writeOp->initPrograms(programCollection); 892 m_readOp->initPrograms(programCollection); 893 894 if (m_syncPrimitive == SYNC_PRIMITIVE_TIMELINE_SEMAPHORE) 895 { 896 for (deUint32 copyOpNdx = 0; copyOpNdx < DE_LENGTH_OF_ARRAY(s_copyOps); copyOpNdx++) 897 { 898 if (isResourceSupported(s_copyOps[copyOpNdx], m_resourceDesc)) 899 makeOperationSupport(s_copyOps[copyOpNdx], m_resourceDesc)->initPrograms(programCollection); 900 } 901 } 902 } 903 904 void checkSupport(Context& context) const 905 { 906 if (m_type == SynchronizationType::SYNCHRONIZATION2) 907 context.requireDeviceFunctionality("VK_KHR_synchronization2"); 908 if (m_syncPrimitive == SYNC_PRIMITIVE_TIMELINE_SEMAPHORE) 909 context.requireDeviceFunctionality("VK_KHR_timeline_semaphore"); 910 911 const InstanceInterface& instance = context.getInstanceInterface(); 912 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); 913 const std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instance, physicalDevice); 914 if (m_sharingMode == VK_SHARING_MODE_CONCURRENT && queueFamilyProperties.size() < 2) 915 TCU_THROW(NotSupportedError, "Concurrent requires more than 1 queue family"); 916 917 if (m_syncPrimitive == SYNC_PRIMITIVE_TIMELINE_SEMAPHORE && 918 !context.getTimelineSemaphoreFeatures().timelineSemaphore) 919 TCU_THROW(NotSupportedError, "Timeline semaphore not supported"); 920 921 if (m_resourceDesc.type == RESOURCE_TYPE_IMAGE) 922 { 923 VkImageFormatProperties imageFormatProperties; 924 const deUint32 usage = m_writeOp->getOutResourceUsageFlags() | m_readOp->getInResourceUsageFlags(); 925 const VkResult formatResult = instance.getPhysicalDeviceImageFormatProperties(physicalDevice, m_resourceDesc.imageFormat, m_resourceDesc.imageType, VK_IMAGE_TILING_OPTIMAL, usage, (VkImageCreateFlags)0, &imageFormatProperties); 926 927 if (formatResult != VK_SUCCESS) 928 TCU_THROW(NotSupportedError, "Image format is not supported"); 929 930 if ((imageFormatProperties.sampleCounts & m_resourceDesc.imageSamples) != m_resourceDesc.imageSamples) 931 TCU_THROW(NotSupportedError, "Requested sample count is not supported"); 932 } 933 } 934 935 TestInstance* createInstance (Context& context) const 936 { 937 switch (m_syncPrimitive) 938 { 939 case SYNC_PRIMITIVE_FENCE: 940 return new FenceTestInstance(context, m_type, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode); 941 case SYNC_PRIMITIVE_BINARY_SEMAPHORE: 942 return new BinarySemaphoreTestInstance(context, m_type, m_resourceDesc, *m_writeOp, *m_readOp, m_pipelineCacheData, m_sharingMode); 943 case SYNC_PRIMITIVE_TIMELINE_SEMAPHORE: 944 return new TimelineSemaphoreTestInstance(context, m_type, m_resourceDesc, m_writeOp, m_readOp, m_pipelineCacheData, m_sharingMode); 945 default: 946 DE_ASSERT(0); 947 return DE_NULL; 948 } 949 } 950 951private: 952 const SynchronizationType m_type; 953 const ResourceDescription m_resourceDesc; 954 const SharedPtr<OperationSupport> m_writeOp; 955 const SharedPtr<OperationSupport> m_readOp; 956 const SyncPrimitive m_syncPrimitive; 957 const VkSharingMode m_sharingMode; 958 PipelineCacheData& m_pipelineCacheData; 959}; 960 961struct TestData 962{ 963 SynchronizationType type; 964 PipelineCacheData* pipelineCacheData; 965}; 966 967void createTests (tcu::TestCaseGroup* group, TestData data) 968{ 969 tcu::TestContext& testCtx = group->getTestContext(); 970 971 static const struct 972 { 973 const char* name; 974 SyncPrimitive syncPrimitive; 975 int numOptions; 976 } groups[] = 977 { 978 { "fence", SYNC_PRIMITIVE_FENCE, 1 }, 979 { "binary_semaphore", SYNC_PRIMITIVE_BINARY_SEMAPHORE, 1 }, 980 { "timeline_semaphore", SYNC_PRIMITIVE_TIMELINE_SEMAPHORE, 1 } 981 }; 982 983 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx) 984 { 985 MovePtr<tcu::TestCaseGroup> synchGroup (new tcu::TestCaseGroup(testCtx, groups[groupNdx].name)); 986 987 for (int writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx) 988 for (int readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx) 989 { 990 const OperationName writeOp = s_writeOps[writeOpNdx]; 991 const OperationName readOp = s_readOps[readOpNdx]; 992 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp); 993 bool empty = true; 994 995 MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str())); 996 997 for (int optionNdx = 0; optionNdx <= groups[groupNdx].numOptions; ++optionNdx) 998 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx) 999 { 1000 const ResourceDescription& resource = s_resources[resourceNdx]; 1001 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource)) 1002 { 1003 std::string name = getResourceName(resource); 1004 VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE; 1005 1006 // queue family sharing mode used for resource 1007 if (optionNdx) 1008 { 1009 name += "_concurrent"; 1010 sharingMode = VK_SHARING_MODE_CONCURRENT; 1011 } 1012 else 1013 name += "_exclusive"; 1014 1015 opGroup->addChild(new BaseTestCase(testCtx, name, data.type, groups[groupNdx].syncPrimitive, resource, writeOp, readOp, sharingMode, *data.pipelineCacheData)); 1016 empty = false; 1017 } 1018 } 1019 if (!empty) 1020 synchGroup->addChild(opGroup.release()); 1021 } 1022 group->addChild(synchGroup.release()); 1023 } 1024} 1025 1026void cleanupGroup (tcu::TestCaseGroup* group, TestData data) 1027{ 1028 DE_UNREF(group); 1029 DE_UNREF(data.pipelineCacheData); 1030 // Destroy singleton object 1031 MultiQueues::destroy(); 1032} 1033 1034} // anonymous 1035 1036tcu::TestCaseGroup* createSynchronizedOperationMultiQueueTests (tcu::TestContext& testCtx, SynchronizationType type, PipelineCacheData& pipelineCacheData) 1037{ 1038 TestData data 1039 { 1040 type, 1041 &pipelineCacheData 1042 }; 1043 1044 // Synchronization of a memory-modifying operation 1045 return createTestGroup(testCtx, "multi_queue", createTests, data, cleanupGroup); 1046} 1047 1048} // synchronization 1049} // vkt 1050