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 vktSparseResourcesImageMemoryAliasing.cpp 21 * \brief Sparse image memory aliasing tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktSparseResourcesImageMemoryAliasing.hpp" 25 #include "vktSparseResourcesTestsUtil.hpp" 26 #include "vktSparseResourcesBase.hpp" 27 #include "vktTestCaseUtil.hpp" 28 29 #include "vkDefs.hpp" 30 #include "vkRef.hpp" 31 #include "vkRefUtil.hpp" 32 #include "vkPlatform.hpp" 33 #include "vkPrograms.hpp" 34 #include "vkRefUtil.hpp" 35 #include "vkMemUtil.hpp" 36 #include "vkBarrierUtil.hpp" 37 #include "vkQueryUtil.hpp" 38 #include "vkBuilderUtil.hpp" 39 #include "vkTypeUtil.hpp" 40 #include "vkCmdUtil.hpp" 41 42 #include "deStringUtil.hpp" 43 #include "deUniquePtr.hpp" 44 #include "deSharedPtr.hpp" 45 #include "tcuTexture.hpp" 46 47 #include <deMath.h> 48 #include <string> 49 #include <vector> 50 51 using namespace vk; 52 53 namespace vkt 54 { 55 namespace sparse 56 { 57 namespace 58 { 59 60 enum ShaderParameters 61 { 62 MODULO_DIVISOR = 128 63 }; 64 65 const std::string getCoordStr (const ImageType imageType, 66 const std::string& x, 67 const std::string& y, 68 const std::string& z) 69 { 70 switch (imageType) 71 { 72 case IMAGE_TYPE_1D: 73 case IMAGE_TYPE_BUFFER: 74 return x; 75 76 case IMAGE_TYPE_1D_ARRAY: 77 case IMAGE_TYPE_2D: 78 return "ivec2(" + x + "," + y + ")"; 79 80 case IMAGE_TYPE_2D_ARRAY: 81 case IMAGE_TYPE_3D: 82 case IMAGE_TYPE_CUBE: 83 case IMAGE_TYPE_CUBE_ARRAY: 84 return "ivec3(" + x + "," + y + "," + z + ")"; 85 86 default: 87 DE_ASSERT(false); 88 return ""; 89 } 90 } 91 92 class ImageSparseMemoryAliasingCase : public TestCase 93 { 94 public: 95 ImageSparseMemoryAliasingCase (tcu::TestContext& testCtx, 96 const std::string& name, 97 const std::string& description, 98 const ImageType imageType, 99 const tcu::UVec3& imageSize, 100 const tcu::TextureFormat& format, 101 const glu::GLSLVersion glslVersion, 102 const bool useDeviceGroups); 103 104 void initPrograms (SourceCollections& sourceCollections) const; 105 TestInstance* createInstance (Context& context) const; 106 107 108 private: 109 const bool m_useDeviceGroups; 110 const ImageType m_imageType; 111 const tcu::UVec3 m_imageSize; 112 const tcu::TextureFormat m_format; 113 const glu::GLSLVersion m_glslVersion; 114 }; 115 116 ImageSparseMemoryAliasingCase::ImageSparseMemoryAliasingCase (tcu::TestContext& testCtx, 117 const std::string& name, 118 const std::string& description, 119 const ImageType imageType, 120 const tcu::UVec3& imageSize, 121 const tcu::TextureFormat& format, 122 const glu::GLSLVersion glslVersion, 123 const bool useDeviceGroups) 124 : TestCase (testCtx, name, description) 125 , m_useDeviceGroups (useDeviceGroups) 126 , m_imageType (imageType) 127 , m_imageSize (imageSize) 128 , m_format (format) 129 , m_glslVersion (glslVersion) 130 { 131 } 132 133 class ImageSparseMemoryAliasingInstance : public SparseResourcesBaseInstance 134 { 135 public: 136 ImageSparseMemoryAliasingInstance (Context& context, 137 const ImageType imageType, 138 const tcu::UVec3& imageSize, 139 const tcu::TextureFormat& format, 140 const bool useDeviceGroups); 141 142 tcu::TestStatus iterate (void); 143 144 private: 145 const bool m_useDeviceGroups; 146 const ImageType m_imageType; 147 const tcu::UVec3 m_imageSize; 148 const tcu::TextureFormat m_format; 149 }; 150 151 ImageSparseMemoryAliasingInstance::ImageSparseMemoryAliasingInstance (Context& context, 152 const ImageType imageType, 153 const tcu::UVec3& imageSize, 154 const tcu::TextureFormat& format, 155 const bool useDeviceGroups) 156 : SparseResourcesBaseInstance (context, useDeviceGroups) 157 , m_useDeviceGroups (useDeviceGroups) 158 , m_imageType (imageType) 159 , m_imageSize (imageSize) 160 , m_format (format) 161 { 162 } 163 164 tcu::TestStatus ImageSparseMemoryAliasingInstance::iterate (void) 165 { 166 const InstanceInterface& instance = m_context.getInstanceInterface(); 167 168 { 169 // Create logical device supporting both sparse and compute queues 170 QueueRequirementsVec queueRequirements; 171 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u)); 172 queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u)); 173 174 createDeviceSupportingQueues(queueRequirements); 175 } 176 177 const VkPhysicalDevice physicalDevice = getPhysicalDevice(); 178 const tcu::UVec3 maxWorkGroupSize = tcu::UVec3(128u, 128u, 64u); 179 const tcu::UVec3 maxWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u); 180 const deUint32 maxWorkGroupInvocations = 128u; 181 VkImageCreateInfo imageSparseInfo; 182 VkSparseImageMemoryRequirements aspectRequirements; 183 std::vector<DeviceMemorySp> deviceMemUniquePtrVec; 184 185 //vsk checking these flags should be after creating m_imageType 186 //getting queues should be outside the loop 187 //see these in all image files 188 189 // Check if image size does not exceed device limits 190 if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize)) 191 TCU_THROW(NotSupportedError, "Image size not supported for device"); 192 193 // Check if sparse memory aliasing is supported 194 if (!getPhysicalDeviceFeatures(instance, physicalDevice).sparseResidencyAliased) 195 TCU_THROW(NotSupportedError, "Sparse memory aliasing not supported"); 196 197 // Check if device supports sparse operations for image type 198 if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType)) 199 TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported"); 200 201 const DeviceInterface& deviceInterface = getDeviceInterface(); 202 const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0); 203 const Queue& computeQueue = getQueue(VK_QUEUE_COMPUTE_BIT, 0); 204 205 // Go through all physical devices 206 for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++) 207 { 208 const deUint32 firstDeviceID = physDevID; 209 const deUint32 secondDeviceID = (firstDeviceID + 1) % m_numPhysicalDevices; 210 211 imageSparseInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 212 imageSparseInfo.pNext = DE_NULL; 213 imageSparseInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | 214 VK_IMAGE_CREATE_SPARSE_ALIASED_BIT | 215 VK_IMAGE_CREATE_SPARSE_BINDING_BIT; 216 imageSparseInfo.imageType = mapImageType(m_imageType); 217 imageSparseInfo.format = mapTextureFormat(m_format); 218 imageSparseInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize)); 219 imageSparseInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize); 220 imageSparseInfo.samples = VK_SAMPLE_COUNT_1_BIT; 221 imageSparseInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 222 imageSparseInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 223 imageSparseInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | 224 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 225 VK_IMAGE_USAGE_STORAGE_BIT; 226 imageSparseInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 227 imageSparseInfo.queueFamilyIndexCount = 0u; 228 imageSparseInfo.pQueueFamilyIndices = DE_NULL; 229 230 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY) 231 imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 232 233 { 234 // Assign maximum allowed mipmap levels to image 235 VkImageFormatProperties imageFormatProperties; 236 instance.getPhysicalDeviceImageFormatProperties(physicalDevice, 237 imageSparseInfo.format, 238 imageSparseInfo.imageType, 239 imageSparseInfo.tiling, 240 imageSparseInfo.usage, 241 imageSparseInfo.flags, 242 &imageFormatProperties); 243 244 imageSparseInfo.mipLevels = getImageMaxMipLevels(imageFormatProperties, imageSparseInfo.extent); 245 } 246 247 // Check if device supports sparse operations for image format 248 if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageSparseInfo)) 249 TCU_THROW(NotSupportedError, "The image format does not support sparse operations"); 250 251 // Create sparse image 252 const Unique<VkImage> imageRead(createImage(deviceInterface, getDevice(), &imageSparseInfo)); 253 const Unique<VkImage> imageWrite(createImage(deviceInterface, getDevice(), &imageSparseInfo)); 254 255 // Create semaphores to synchronize sparse binding operations with other operations on the sparse images 256 const Unique<VkSemaphore> memoryBindSemaphoreTransfer(createSemaphore(deviceInterface, getDevice())); 257 const Unique<VkSemaphore> memoryBindSemaphoreCompute(createSemaphore(deviceInterface, getDevice())); 258 259 const VkSemaphore imageMemoryBindSemaphores[] = { memoryBindSemaphoreTransfer.get(), memoryBindSemaphoreCompute.get() }; 260 261 { 262 std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds; 263 std::vector<VkSparseMemoryBind> imageReadMipTailBinds; 264 std::vector<VkSparseMemoryBind> imageWriteMipTailBinds; 265 266 // Get sparse image general memory requirements 267 const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageRead); 268 269 // Check if required image memory size does not exceed device limits 270 if (imageMemoryRequirements.size > getPhysicalDeviceProperties(instance, getPhysicalDevice(secondDeviceID)).limits.sparseAddressSpaceSize) 271 TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits"); 272 273 DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0); 274 275 // Get sparse image sparse memory requirements 276 const std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageRead); 277 278 DE_ASSERT(sparseMemoryRequirements.size() != 0); 279 280 const deUint32 colorAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_COLOR_BIT); 281 282 if (colorAspectIndex == NO_MATCH_FOUND) 283 TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT"); 284 285 aspectRequirements = sparseMemoryRequirements[colorAspectIndex]; 286 287 const VkImageAspectFlags aspectMask = aspectRequirements.formatProperties.aspectMask; 288 const VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity; 289 290 DE_ASSERT((aspectRequirements.imageMipTailSize % imageMemoryRequirements.alignment) == 0); 291 292 const deUint32 memoryType = findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), imageMemoryRequirements, MemoryRequirement::Any); 293 294 if (memoryType == NO_MATCH_FOUND) 295 return tcu::TestStatus::fail("No matching memory type found"); 296 297 if (firstDeviceID != secondDeviceID) 298 { 299 VkPeerMemoryFeatureFlags peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0; 300 const deUint32 heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType); 301 deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags); 302 303 if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT) == 0) || 304 ((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_DST_BIT) == 0) || 305 ((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT) == 0)) 306 { 307 TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC, COPY_DST, and GENERIC_DST"); 308 } 309 } 310 311 // Bind memory for each layer 312 for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx) 313 { 314 for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx) 315 { 316 const VkExtent3D mipExtent = mipLevelExtents(imageSparseInfo.extent, mipLevelNdx); 317 const tcu::UVec3 sparseBlocks = alignedDivide(mipExtent, imageGranularity); 318 const deUint32 numSparseBlocks = sparseBlocks.x() * sparseBlocks.y() * sparseBlocks.z(); 319 const VkImageSubresource subresource = { aspectMask, mipLevelNdx, layerNdx }; 320 321 const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(), 322 imageMemoryRequirements.alignment * numSparseBlocks, memoryType, subresource, makeOffset3D(0u, 0u, 0u), mipExtent); 323 324 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 325 326 imageResidencyMemoryBinds.push_back(imageMemoryBind); 327 } 328 329 if (!(aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels) 330 { 331 const VkSparseMemoryBind imageReadMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 332 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride); 333 334 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageReadMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 335 336 imageReadMipTailBinds.push_back(imageReadMipTailMemoryBind); 337 338 const VkSparseMemoryBind imageWriteMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 339 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride); 340 341 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageWriteMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 342 343 imageWriteMipTailBinds.push_back(imageWriteMipTailMemoryBind); 344 } 345 } 346 347 if ((aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels) 348 { 349 const VkSparseMemoryBind imageReadMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 350 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset); 351 352 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageReadMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 353 354 imageReadMipTailBinds.push_back(imageReadMipTailMemoryBind); 355 356 const VkSparseMemoryBind imageWriteMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 357 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset); 358 359 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageWriteMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 360 361 imageWriteMipTailBinds.push_back(imageWriteMipTailMemoryBind); 362 } 363 364 const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo = 365 { 366 VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR, //VkStructureType sType; 367 DE_NULL, //const void* pNext; 368 firstDeviceID, //deUint32 resourceDeviceIndex; 369 secondDeviceID, //deUint32 memoryDeviceIndex; 370 }; 371 372 VkBindSparseInfo bindSparseInfo = 373 { 374 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType; 375 m_useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL, //const void* pNext; 376 0u, //deUint32 waitSemaphoreCount; 377 DE_NULL, //const VkSemaphore* pWaitSemaphores; 378 0u, //deUint32 bufferBindCount; 379 DE_NULL, //const VkSparseBufferMemoryBindInfo* pBufferBinds; 380 0u, //deUint32 imageOpaqueBindCount; 381 DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; 382 0u, //deUint32 imageBindCount; 383 DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds; 384 2u, //deUint32 signalSemaphoreCount; 385 imageMemoryBindSemaphores //const VkSemaphore* pSignalSemaphores; 386 }; 387 388 VkSparseImageMemoryBindInfo imageResidencyBindInfo[2]; 389 VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo[2]; 390 391 if (imageResidencyMemoryBinds.size() > 0) 392 { 393 imageResidencyBindInfo[0].image = *imageRead; 394 imageResidencyBindInfo[0].bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size()); 395 imageResidencyBindInfo[0].pBinds = &imageResidencyMemoryBinds[0]; 396 397 imageResidencyBindInfo[1].image = *imageWrite; 398 imageResidencyBindInfo[1].bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size()); 399 imageResidencyBindInfo[1].pBinds = &imageResidencyMemoryBinds[0]; 400 401 bindSparseInfo.imageBindCount = 2u; 402 bindSparseInfo.pImageBinds = imageResidencyBindInfo; 403 } 404 405 if (imageReadMipTailBinds.size() > 0) 406 { 407 imageMipTailBindInfo[0].image = *imageRead; 408 imageMipTailBindInfo[0].bindCount = static_cast<deUint32>(imageReadMipTailBinds.size()); 409 imageMipTailBindInfo[0].pBinds = &imageReadMipTailBinds[0]; 410 411 imageMipTailBindInfo[1].image = *imageWrite; 412 imageMipTailBindInfo[1].bindCount = static_cast<deUint32>(imageWriteMipTailBinds.size()); 413 imageMipTailBindInfo[1].pBinds = &imageWriteMipTailBinds[0]; 414 415 bindSparseInfo.imageOpaqueBindCount = 2u; 416 bindSparseInfo.pImageOpaqueBinds = imageMipTailBindInfo; 417 } 418 419 // Submit sparse bind commands for execution 420 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL)); 421 } 422 423 // Create command buffer for compute and transfer oparations 424 const Unique<VkCommandPool> commandPool (makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex)); 425 const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 426 427 std::vector<VkBufferImageCopy> bufferImageCopy(imageSparseInfo.mipLevels); 428 429 { 430 deUint32 bufferOffset = 0u; 431 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 432 { 433 bufferImageCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, bufferOffset); 434 bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY); 435 } 436 } 437 438 // Start recording commands 439 beginCommandBuffer(deviceInterface, *commandBuffer); 440 441 const deUint32 imageSizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY); 442 const VkBufferCreateInfo inputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); 443 const Unique<VkBuffer> inputBuffer (createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo)); 444 const de::UniquePtr<Allocation> inputBufferAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible)); 445 446 std::vector<deUint8> referenceData(imageSizeInBytes); 447 448 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 449 { 450 const deUint32 mipLevelSizeInBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx); 451 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageCopy[mipLevelNdx].bufferOffset); 452 453 deMemset(&referenceData[bufferOffset], mipLevelNdx + 1u, mipLevelSizeInBytes); 454 } 455 456 deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], imageSizeInBytes); 457 458 flushAlloc(deviceInterface, getDevice(), *inputBufferAlloc); 459 460 { 461 const VkBufferMemoryBarrier inputBufferBarrier = makeBufferMemoryBarrier 462 ( 463 VK_ACCESS_HOST_WRITE_BIT, 464 VK_ACCESS_TRANSFER_READ_BIT, 465 *inputBuffer, 466 0u, 467 imageSizeInBytes 468 ); 469 470 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL); 471 } 472 473 { 474 const VkImageMemoryBarrier imageSparseTransferDstBarrier = makeImageMemoryBarrier 475 ( 476 0u, 477 VK_ACCESS_TRANSFER_WRITE_BIT, 478 VK_IMAGE_LAYOUT_UNDEFINED, 479 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 480 *imageRead, 481 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers), 482 sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED, 483 sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? computeQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED 484 ); 485 486 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferDstBarrier); 487 } 488 489 deviceInterface.cmdCopyBufferToImage(*commandBuffer, *inputBuffer, *imageRead, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]); 490 491 { 492 const VkImageMemoryBarrier imageSparseTransferSrcBarrier = makeImageMemoryBarrier 493 ( 494 VK_ACCESS_TRANSFER_WRITE_BIT, 495 VK_ACCESS_TRANSFER_READ_BIT, 496 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 497 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 498 *imageRead, 499 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers) 500 ); 501 502 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferSrcBarrier); 503 } 504 505 { 506 const VkImageMemoryBarrier imageSparseShaderStorageBarrier = makeImageMemoryBarrier 507 ( 508 0u, 509 VK_ACCESS_SHADER_WRITE_BIT, 510 VK_IMAGE_LAYOUT_UNDEFINED, 511 VK_IMAGE_LAYOUT_GENERAL, 512 *imageWrite, 513 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers) 514 ); 515 516 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseShaderStorageBarrier); 517 } 518 519 // Create descriptor set layout 520 const Unique<VkDescriptorSetLayout> descriptorSetLayout( 521 DescriptorSetLayoutBuilder() 522 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT) 523 .build(deviceInterface, getDevice())); 524 525 Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout)); 526 527 Unique<VkDescriptorPool> descriptorPool( 528 DescriptorPoolBuilder() 529 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, imageSparseInfo.mipLevels) 530 .build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, imageSparseInfo.mipLevels)); 531 532 typedef de::SharedPtr< Unique<VkImageView> > SharedVkImageView; 533 std::vector<SharedVkImageView> imageViews; 534 imageViews.resize(imageSparseInfo.mipLevels); 535 536 typedef de::SharedPtr< Unique<VkDescriptorSet> > SharedVkDescriptorSet; 537 std::vector<SharedVkDescriptorSet> descriptorSets; 538 descriptorSets.resize(imageSparseInfo.mipLevels); 539 540 typedef de::SharedPtr< Unique<VkPipeline> > SharedVkPipeline; 541 std::vector<SharedVkPipeline> computePipelines; 542 computePipelines.resize(imageSparseInfo.mipLevels); 543 544 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 545 { 546 std::ostringstream name; 547 name << "comp" << mipLevelNdx; 548 549 // Create and bind compute pipeline 550 Unique<VkShaderModule> shaderModule(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get(name.str()), DE_NULL)); 551 552 computePipelines[mipLevelNdx] = makeVkSharedPtr(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, *shaderModule)); 553 VkPipeline computePipeline = **computePipelines[mipLevelNdx]; 554 555 deviceInterface.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline); 556 557 // Create and bind descriptor set 558 descriptorSets[mipLevelNdx] = makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout)); 559 VkDescriptorSet descriptorSet = **descriptorSets[mipLevelNdx]; 560 561 // Select which mipmap level to bind 562 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevelNdx, 1u, 0u, imageSparseInfo.arrayLayers); 563 564 imageViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), *imageWrite, mapImageViewType(m_imageType), imageSparseInfo.format, subresourceRange)); 565 VkImageView imageView = **imageViews[mipLevelNdx]; 566 567 const VkDescriptorImageInfo sparseImageInfo = makeDescriptorImageInfo(DE_NULL, imageView, VK_IMAGE_LAYOUT_GENERAL); 568 569 DescriptorSetUpdateBuilder() 570 .writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &sparseImageInfo) 571 .update(deviceInterface, getDevice()); 572 573 deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); 574 575 const tcu::UVec3 gridSize = getShaderGridSize(m_imageType, m_imageSize, mipLevelNdx); 576 const deUint32 xWorkGroupSize = std::min(std::min(gridSize.x(), maxWorkGroupSize.x()), maxWorkGroupInvocations); 577 const deUint32 yWorkGroupSize = std::min(std::min(gridSize.y(), maxWorkGroupSize.y()), maxWorkGroupInvocations / xWorkGroupSize); 578 const deUint32 zWorkGroupSize = std::min(std::min(gridSize.z(), maxWorkGroupSize.z()), maxWorkGroupInvocations / (xWorkGroupSize * yWorkGroupSize)); 579 580 const deUint32 xWorkGroupCount = gridSize.x() / xWorkGroupSize + (gridSize.x() % xWorkGroupSize ? 1u : 0u); 581 const deUint32 yWorkGroupCount = gridSize.y() / yWorkGroupSize + (gridSize.y() % yWorkGroupSize ? 1u : 0u); 582 const deUint32 zWorkGroupCount = gridSize.z() / zWorkGroupSize + (gridSize.z() % zWorkGroupSize ? 1u : 0u); 583 584 if (maxWorkGroupCount.x() < xWorkGroupCount || 585 maxWorkGroupCount.y() < yWorkGroupCount || 586 maxWorkGroupCount.z() < zWorkGroupCount) 587 TCU_THROW(NotSupportedError, "Image size is not supported"); 588 589 deviceInterface.cmdDispatch(*commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount); 590 } 591 592 { 593 const VkMemoryBarrier memoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); 594 595 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 1u, &memoryBarrier, 0u, DE_NULL, 0u, DE_NULL); 596 } 597 598 const VkBufferCreateInfo outputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 599 const Unique<VkBuffer> outputBuffer (createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo)); 600 const de::UniquePtr<Allocation> outputBufferAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible)); 601 602 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageRead, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]); 603 604 { 605 const VkBufferMemoryBarrier outputBufferBarrier = makeBufferMemoryBarrier 606 ( 607 VK_ACCESS_TRANSFER_WRITE_BIT, 608 VK_ACCESS_HOST_READ_BIT, 609 *outputBuffer, 610 0u, 611 imageSizeInBytes 612 ); 613 614 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL); 615 } 616 617 // End recording commands 618 endCommandBuffer(deviceInterface, *commandBuffer); 619 620 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT }; 621 622 // Submit commands for execution and wait for completion 623 submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 2u, imageMemoryBindSemaphores, stageBits, 624 0, DE_NULL, m_useDeviceGroups, firstDeviceID); 625 626 // Retrieve data from buffer to host memory 627 invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc); 628 629 const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr()); 630 631 // Wait for sparse queue to become idle 632 deviceInterface.queueWaitIdle(sparseQueue.queueHandle); 633 634 for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx) 635 { 636 const tcu::UVec3 gridSize = getShaderGridSize(m_imageType, m_imageSize, mipLevelNdx); 637 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageCopy[mipLevelNdx].bufferOffset); 638 const tcu::ConstPixelBufferAccess pixelBuffer = tcu::ConstPixelBufferAccess(m_format, gridSize.x(), gridSize.y(), gridSize.z(), outputData + bufferOffset); 639 640 for (deUint32 offsetZ = 0u; offsetZ < gridSize.z(); ++offsetZ) 641 for (deUint32 offsetY = 0u; offsetY < gridSize.y(); ++offsetY) 642 for (deUint32 offsetX = 0u; offsetX < gridSize.x(); ++offsetX) 643 { 644 const deUint32 index = offsetX + (offsetY + offsetZ * gridSize.y()) * gridSize.x(); 645 const tcu::UVec4 referenceValue = tcu::UVec4(index % MODULO_DIVISOR, index % MODULO_DIVISOR, index % MODULO_DIVISOR, 1u); 646 const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX, offsetY, offsetZ); 647 648 if (deMemCmp(&outputValue, &referenceValue, sizeof(deUint32) * getNumUsedChannels(m_format.order)) != 0) 649 return tcu::TestStatus::fail("Failed"); 650 } 651 } 652 653 for (deUint32 mipLevelNdx = aspectRequirements.imageMipTailFirstLod; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 654 { 655 const deUint32 mipLevelSizeInBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx); 656 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageCopy[mipLevelNdx].bufferOffset); 657 658 if (deMemCmp(outputData + bufferOffset, &referenceData[bufferOffset], mipLevelSizeInBytes) != 0) 659 return tcu::TestStatus::fail("Failed"); 660 } 661 } 662 663 return tcu::TestStatus::pass("Passed"); 664 } 665 666 void ImageSparseMemoryAliasingCase::initPrograms(SourceCollections& sourceCollections) const 667 { 668 const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion); 669 const std::string imageTypeStr = getShaderImageType(m_format, m_imageType); 670 const std::string formatQualifierStr = getShaderImageFormatQualifier(m_format); 671 const std::string formatDataStr = getShaderImageDataType(m_format); 672 const deUint32 maxWorkGroupInvocations = 128u; 673 const tcu::UVec3 maxWorkGroupSize = tcu::UVec3(128u, 128u, 64u); 674 675 const tcu::UVec3 layerSize = getLayerSize(m_imageType, m_imageSize); 676 const deUint32 widestEdge = std::max(std::max(layerSize.x(), layerSize.y()), layerSize.z()); 677 const deUint32 mipLevels = static_cast<deUint32>(deFloatLog2(static_cast<float>(widestEdge))) + 1u; 678 679 for (deUint32 mipLevelNdx = 0; mipLevelNdx < mipLevels; ++mipLevelNdx) 680 { 681 // Create compute program 682 const tcu::UVec3 gridSize = getShaderGridSize(m_imageType, m_imageSize, mipLevelNdx); 683 const deUint32 xWorkGroupSize = std::min(std::min(gridSize.x(), maxWorkGroupSize.x()), maxWorkGroupInvocations); 684 const deUint32 yWorkGroupSize = std::min(std::min(gridSize.y(), maxWorkGroupSize.y()), maxWorkGroupInvocations / xWorkGroupSize); 685 const deUint32 zWorkGroupSize = std::min(std::min(gridSize.z(), maxWorkGroupSize.z()), maxWorkGroupInvocations / (xWorkGroupSize * yWorkGroupSize)); 686 687 std::ostringstream src; 688 689 src << versionDecl << "\n" 690 << "layout (local_size_x = " << xWorkGroupSize << ", local_size_y = " << yWorkGroupSize << ", local_size_z = " << zWorkGroupSize << ") in; \n" 691 << "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n" 692 << "void main (void)\n" 693 << "{\n" 694 << " if( gl_GlobalInvocationID.x < " << gridSize.x() << " ) \n" 695 << " if( gl_GlobalInvocationID.y < " << gridSize.y() << " ) \n" 696 << " if( gl_GlobalInvocationID.z < " << gridSize.z() << " ) \n" 697 << " {\n" 698 << " int index = int(gl_GlobalInvocationID.x + (gl_GlobalInvocationID.y + gl_GlobalInvocationID.z*" << gridSize.y() << ")*" << gridSize.x() << ");\n" 699 << " imageStore(u_image, " << getCoordStr(m_imageType, "gl_GlobalInvocationID.x", "gl_GlobalInvocationID.y", "gl_GlobalInvocationID.z") << "," 700 << formatDataStr << "( index % " << MODULO_DIVISOR << ", index % " << MODULO_DIVISOR << ", index % " << MODULO_DIVISOR << ", 1 )); \n" 701 << " }\n" 702 << "}\n"; 703 704 std::ostringstream name; 705 name << "comp" << mipLevelNdx; 706 sourceCollections.glslSources.add(name.str()) << glu::ComputeSource(src.str()); 707 } 708 } 709 710 TestInstance* ImageSparseMemoryAliasingCase::createInstance (Context& context) const 711 { 712 return new ImageSparseMemoryAliasingInstance(context, m_imageType, m_imageSize, m_format, m_useDeviceGroups); 713 } 714 715 } // anonymous ns 716 717 tcu::TestCaseGroup* createImageSparseMemoryAliasingTestsCommon(tcu::TestContext& testCtx, de::MovePtr<tcu::TestCaseGroup> testGroup, const bool useDeviceGroup = false) 718 { 719 static const deUint32 sizeCountPerImageType = 4u; 720 721 struct ImageParameters 722 { 723 ImageType imageType; 724 tcu::UVec3 imageSizes[sizeCountPerImageType]; 725 }; 726 727 static const ImageParameters imageParametersArray[] = 728 { 729 { IMAGE_TYPE_2D, { tcu::UVec3(512u, 256u, 1u), tcu::UVec3(128u, 128u, 1u), tcu::UVec3(503u, 137u, 1u), tcu::UVec3(11u, 37u, 1u) } }, 730 { IMAGE_TYPE_2D_ARRAY, { tcu::UVec3(512u, 256u, 6u), tcu::UVec3(128u, 128u, 8u), tcu::UVec3(503u, 137u, 3u), tcu::UVec3(11u, 37u, 3u) } }, 731 { IMAGE_TYPE_CUBE, { tcu::UVec3(256u, 256u, 1u), tcu::UVec3(128u, 128u, 1u), tcu::UVec3(137u, 137u, 1u), tcu::UVec3(11u, 11u, 1u) } }, 732 { IMAGE_TYPE_CUBE_ARRAY,{ tcu::UVec3(256u, 256u, 6u), tcu::UVec3(128u, 128u, 8u), tcu::UVec3(137u, 137u, 3u), tcu::UVec3(11u, 11u, 3u) } }, 733 { IMAGE_TYPE_3D, { tcu::UVec3(256u, 256u, 16u), tcu::UVec3(128u, 128u, 8u), tcu::UVec3(503u, 137u, 3u), tcu::UVec3(11u, 37u, 3u) } } 734 }; 735 736 static const tcu::TextureFormat formats[] = 737 { 738 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT32), 739 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT16), 740 tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT8), 741 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32), 742 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT16), 743 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8) 744 }; 745 746 for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray); ++imageTypeNdx) 747 { 748 const ImageType imageType = imageParametersArray[imageTypeNdx].imageType; 749 de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), "")); 750 751 for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx) 752 { 753 const tcu::TextureFormat& format = formats[formatNdx]; 754 de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, getShaderImageFormatQualifier(format).c_str(), "")); 755 756 for (deInt32 imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray[imageTypeNdx].imageSizes); ++imageSizeNdx) 757 { 758 const tcu::UVec3 imageSize = imageParametersArray[imageTypeNdx].imageSizes[imageSizeNdx]; 759 760 std::ostringstream stream; 761 stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z(); 762 763 formatGroup->addChild(new ImageSparseMemoryAliasingCase(testCtx, stream.str(), "", imageType, imageSize, format, glu::GLSL_VERSION_440, useDeviceGroup)); 764 } 765 imageTypeGroup->addChild(formatGroup.release()); 766 } 767 testGroup->addChild(imageTypeGroup.release()); 768 } 769 770 return testGroup.release(); 771 } 772 773 tcu::TestCaseGroup* createImageSparseMemoryAliasingTests(tcu::TestContext& testCtx) 774 { 775 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_memory_aliasing", "Sparse Image Memory Aliasing")); 776 return createImageSparseMemoryAliasingTestsCommon(testCtx, testGroup); 777 } 778 779 tcu::TestCaseGroup* createDeviceGroupImageSparseMemoryAliasingTests(tcu::TestContext& testCtx) 780 { 781 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "device_group_image_sparse_memory_aliasing", "Sparse Image Memory Aliasing")); 782 return createImageSparseMemoryAliasingTestsCommon(testCtx, testGroup, true); 783 } 784 785 } // sparse 786 } // vkt 787