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 vktSparseResourcesShaderIntrinsicsBase.cpp 21 * \brief Sparse Resources Shader Intrinsics Base Classes 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktSparseResourcesShaderIntrinsicsBase.hpp" 25 26 using namespace vk; 27 28 namespace vkt 29 { 30 namespace sparse 31 { 32 33 tcu::UVec3 alignedDivide (const VkExtent3D& extent, const VkExtent3D& divisor) 34 { 35 tcu::UVec3 result; 36 37 result.x() = extent.width / divisor.width + ((extent.width % divisor.width) ? 1u : 0u); 38 result.y() = extent.height / divisor.height + ((extent.height % divisor.height) ? 1u : 0u); 39 result.z() = extent.depth / divisor.depth + ((extent.depth % divisor.depth) ? 1u : 0u); 40 41 return result; 42 } 43 44 std::string getOpTypeImageComponent (const tcu::TextureFormat& format) 45 { 46 switch (tcu::getTextureChannelClass(format.type)) 47 { 48 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 49 return "OpTypeInt 32 0"; 50 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 51 return "OpTypeInt 32 1"; 52 default: 53 DE_ASSERT(0); 54 return ""; 55 } 56 } 57 58 std::string getImageComponentTypeName (const tcu::TextureFormat& format) 59 { 60 switch (tcu::getTextureChannelClass(format.type)) 61 { 62 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 63 return "%type_uint"; 64 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 65 return "%type_int"; 66 default: 67 DE_ASSERT(0); 68 return ""; 69 } 70 } 71 72 std::string getImageComponentVec4TypeName (const tcu::TextureFormat& format) 73 { 74 switch (tcu::getTextureChannelClass(format.type)) 75 { 76 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 77 return "%type_uvec4"; 78 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 79 return "%type_ivec4"; 80 default: 81 DE_ASSERT(0); 82 return ""; 83 } 84 } 85 86 std::string getOpTypeImageSparse (const ImageType imageType, 87 const tcu::TextureFormat& format, 88 const std::string& componentType, 89 const bool requiresSampler) 90 { 91 std::ostringstream src; 92 93 src << "OpTypeImage " << componentType << " "; 94 95 switch (imageType) 96 { 97 case IMAGE_TYPE_1D : 98 src << "1D 0 0 0 "; 99 break; 100 case IMAGE_TYPE_1D_ARRAY : 101 src << "1D 0 1 0 "; 102 break; 103 case IMAGE_TYPE_2D : 104 src << "2D 0 0 0 "; 105 break; 106 case IMAGE_TYPE_2D_ARRAY : 107 src << "2D 0 1 0 "; 108 break; 109 case IMAGE_TYPE_3D : 110 src << "3D 0 0 0 "; 111 break; 112 case IMAGE_TYPE_CUBE : 113 src << "Cube 0 0 0 "; 114 break; 115 case IMAGE_TYPE_CUBE_ARRAY : 116 src << "Cube 0 1 0 "; 117 break; 118 default : 119 DE_ASSERT(0); 120 break; 121 }; 122 123 if (requiresSampler) 124 src << "1 "; 125 else 126 src << "2 "; 127 128 switch (format.order) 129 { 130 case tcu::TextureFormat::R: 131 src << "R"; 132 break; 133 case tcu::TextureFormat::RG: 134 src << "Rg"; 135 break; 136 case tcu::TextureFormat::RGB: 137 src << "Rgb"; 138 break; 139 case tcu::TextureFormat::RGBA: 140 src << "Rgba"; 141 break; 142 default: 143 DE_ASSERT(0); 144 break; 145 } 146 147 switch (format.type) 148 { 149 case tcu::TextureFormat::SIGNED_INT8: 150 src << "8i"; 151 break; 152 case tcu::TextureFormat::SIGNED_INT16: 153 src << "16i"; 154 break; 155 case tcu::TextureFormat::SIGNED_INT32: 156 src << "32i"; 157 break; 158 case tcu::TextureFormat::UNSIGNED_INT8: 159 src << "8ui"; 160 break; 161 case tcu::TextureFormat::UNSIGNED_INT16: 162 src << "16ui"; 163 break; 164 case tcu::TextureFormat::UNSIGNED_INT32: 165 src << "32ui"; 166 break; 167 default: 168 DE_ASSERT(0); 169 break; 170 }; 171 172 return src.str(); 173 } 174 175 std::string getOpTypeImageResidency (const ImageType imageType) 176 { 177 std::ostringstream src; 178 179 src << "OpTypeImage %type_uint "; 180 181 switch (imageType) 182 { 183 case IMAGE_TYPE_1D : 184 src << "1D 0 0 0 2 R32ui"; 185 break; 186 case IMAGE_TYPE_1D_ARRAY : 187 src << "1D 0 1 0 2 R32ui"; 188 break; 189 case IMAGE_TYPE_2D : 190 src << "2D 0 0 0 2 R32ui"; 191 break; 192 case IMAGE_TYPE_2D_ARRAY : 193 src << "2D 0 1 0 2 R32ui"; 194 break; 195 case IMAGE_TYPE_3D : 196 src << "3D 0 0 0 2 R32ui"; 197 break; 198 case IMAGE_TYPE_CUBE : 199 src << "Cube 0 0 0 2 R32ui"; 200 break; 201 case IMAGE_TYPE_CUBE_ARRAY : 202 src << "Cube 0 1 0 2 R32ui"; 203 break; 204 default : 205 DE_ASSERT(0); 206 break; 207 }; 208 209 return src.str(); 210 } 211 212 tcu::TestStatus SparseShaderIntrinsicsInstanceBase::iterate (void) 213 { 214 const InstanceInterface& instance = m_context.getInstanceInterface(); 215 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); 216 VkImageCreateInfo imageSparseInfo; 217 VkImageCreateInfo imageTexelsInfo; 218 VkImageCreateInfo imageResidencyInfo; 219 VkSparseImageMemoryRequirements aspectRequirements; 220 std::vector <deUint32> residencyReferenceData; 221 std::vector<DeviceMemorySp> deviceMemUniquePtrVec; 222 223 // Check if image size does not exceed device limits 224 if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize)) 225 TCU_THROW(NotSupportedError, "Image size not supported for device"); 226 227 // Check if device supports sparse operations for image type 228 if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType)) 229 TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported"); 230 231 if (!getPhysicalDeviceFeatures(instance, physicalDevice).shaderResourceResidency) 232 TCU_THROW(NotSupportedError, "Sparse resource residency information not supported in shader code."); 233 234 imageSparseInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 235 imageSparseInfo.pNext = DE_NULL; 236 imageSparseInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT; 237 imageSparseInfo.imageType = mapImageType(m_imageType); 238 imageSparseInfo.format = mapTextureFormat(m_format); 239 imageSparseInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize)); 240 imageSparseInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize); 241 imageSparseInfo.samples = VK_SAMPLE_COUNT_1_BIT; 242 imageSparseInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 243 imageSparseInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 244 imageSparseInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | imageSparseUsageFlags(); 245 imageSparseInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 246 imageSparseInfo.queueFamilyIndexCount = 0u; 247 imageSparseInfo.pQueueFamilyIndices = DE_NULL; 248 249 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY) 250 { 251 imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 252 } 253 254 { 255 // Assign maximum allowed mipmap levels to image 256 VkImageFormatProperties imageFormatProperties; 257 instance.getPhysicalDeviceImageFormatProperties(physicalDevice, 258 imageSparseInfo.format, 259 imageSparseInfo.imageType, 260 imageSparseInfo.tiling, 261 imageSparseInfo.usage, 262 imageSparseInfo.flags, 263 &imageFormatProperties); 264 265 imageSparseInfo.mipLevels = getImageMaxMipLevels(imageFormatProperties, imageSparseInfo.extent); 266 } 267 268 // Check if device supports sparse operations for image format 269 if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageSparseInfo)) 270 TCU_THROW(NotSupportedError, "The image format does not support sparse operations"); 271 272 { 273 // Create logical device supporting both sparse and compute/graphics queues 274 QueueRequirementsVec queueRequirements; 275 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u)); 276 queueRequirements.push_back(QueueRequirements(getQueueFlags(), 1u)); 277 278 createDeviceSupportingQueues(queueRequirements); 279 } 280 281 const DeviceInterface& deviceInterface = getDeviceInterface(); 282 283 // Create queues supporting sparse binding operations and compute/graphics operations 284 const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0); 285 const Queue& extractQueue = getQueue(getQueueFlags(), 0); 286 287 // Create sparse image 288 const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageSparseInfo)); 289 290 // Create sparse image memory bind semaphore 291 const Unique<VkSemaphore> memoryBindSemaphore(createSemaphore(deviceInterface, getDevice())); 292 293 const deUint32 imageSparseSizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY); 294 const deUint32 imageSizeInPixels = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels) / tcu::getPixelSize(m_format); 295 296 residencyReferenceData.assign(imageSizeInPixels, MEMORY_BLOCK_NOT_BOUND_VALUE); 297 298 { 299 // Get sparse image general memory requirements 300 const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageSparse); 301 302 // Check if required image memory size does not exceed device limits 303 if (imageMemoryRequirements.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize) 304 TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits"); 305 306 DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0); 307 308 // Get sparse image sparse memory requirements 309 const std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse); 310 311 DE_ASSERT(sparseMemoryRequirements.size() != 0); 312 313 const deUint32 colorAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_COLOR_BIT); 314 const deUint32 metadataAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_METADATA_BIT); 315 316 if (colorAspectIndex == NO_MATCH_FOUND) 317 TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT"); 318 319 aspectRequirements = sparseMemoryRequirements[colorAspectIndex]; 320 321 DE_ASSERT((aspectRequirements.imageMipTailSize % imageMemoryRequirements.alignment) == 0); 322 323 const VkImageAspectFlags aspectMask = aspectRequirements.formatProperties.aspectMask; 324 const VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity; 325 const deUint32 memoryType = findMatchingMemoryType(instance, physicalDevice, imageMemoryRequirements, MemoryRequirement::Any); 326 327 if (memoryType == NO_MATCH_FOUND) 328 return tcu::TestStatus::fail("No matching memory type found"); 329 330 deUint32 pixelOffset = 0u; 331 332 std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds; 333 std::vector<VkSparseMemoryBind> imageMipTailBinds; 334 335 // Bind memory for each mipmap level 336 for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx) 337 { 338 const deUint32 mipLevelSizeInPixels = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx) / tcu::getPixelSize(m_format); 339 340 if (mipLevelNdx % MEMORY_BLOCK_TYPE_COUNT == MEMORY_BLOCK_NOT_BOUND) 341 { 342 pixelOffset += mipLevelSizeInPixels; 343 continue; 344 } 345 346 for (deUint32 pixelNdx = 0u; pixelNdx < mipLevelSizeInPixels; ++pixelNdx) 347 { 348 residencyReferenceData[pixelOffset + pixelNdx] = MEMORY_BLOCK_BOUND_VALUE; 349 } 350 351 pixelOffset += mipLevelSizeInPixels; 352 353 for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx) 354 { 355 const VkExtent3D mipExtent = mipLevelExtents(imageSparseInfo.extent, mipLevelNdx); 356 const tcu::UVec3 sparseBlocks = alignedDivide(mipExtent, imageGranularity); 357 const deUint32 numSparseBlocks = sparseBlocks.x() * sparseBlocks.y() * sparseBlocks.z(); 358 const VkImageSubresource subresource = { aspectMask, mipLevelNdx, layerNdx }; 359 360 const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(), 361 imageMemoryRequirements.alignment * numSparseBlocks, memoryType, subresource, makeOffset3D(0u, 0u, 0u), mipExtent); 362 363 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 364 365 imageResidencyMemoryBinds.push_back(imageMemoryBind); 366 } 367 } 368 369 if (aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels) 370 { 371 if (aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) 372 { 373 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 374 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset); 375 376 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 377 378 imageMipTailBinds.push_back(imageMipTailMemoryBind); 379 } 380 else 381 { 382 for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx) 383 { 384 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 385 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride); 386 387 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 388 389 imageMipTailBinds.push_back(imageMipTailMemoryBind); 390 } 391 } 392 393 for (deUint32 pixelNdx = pixelOffset; pixelNdx < residencyReferenceData.size(); ++pixelNdx) 394 { 395 residencyReferenceData[pixelNdx] = MEMORY_BLOCK_BOUND_VALUE; 396 } 397 } 398 399 // Metadata 400 if (metadataAspectIndex != NO_MATCH_FOUND) 401 { 402 const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex]; 403 404 const deUint32 metadataBindCount = (metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT ? 1u : imageSparseInfo.arrayLayers); 405 for (deUint32 bindNdx = 0u; bindNdx < metadataBindCount; ++bindNdx) 406 { 407 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), 408 metadataAspectRequirements.imageMipTailSize, memoryType, 409 metadataAspectRequirements.imageMipTailOffset + bindNdx * metadataAspectRequirements.imageMipTailStride, 410 VK_SPARSE_MEMORY_BIND_METADATA_BIT); 411 412 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL)))); 413 414 imageMipTailBinds.push_back(imageMipTailMemoryBind); 415 } 416 } 417 418 VkBindSparseInfo bindSparseInfo = 419 { 420 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType; 421 DE_NULL, //const void* pNext; 422 0u, //deUint32 waitSemaphoreCount; 423 DE_NULL, //const VkSemaphore* pWaitSemaphores; 424 0u, //deUint32 bufferBindCount; 425 DE_NULL, //const VkSparseBufferMemoryBindInfo* pBufferBinds; 426 0u, //deUint32 imageOpaqueBindCount; 427 DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; 428 0u, //deUint32 imageBindCount; 429 DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds; 430 1u, //deUint32 signalSemaphoreCount; 431 &memoryBindSemaphore.get() //const VkSemaphore* pSignalSemaphores; 432 }; 433 434 VkSparseImageMemoryBindInfo imageResidencyBindInfo; 435 VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo; 436 437 if (imageResidencyMemoryBinds.size() > 0) 438 { 439 imageResidencyBindInfo.image = *imageSparse; 440 imageResidencyBindInfo.bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size()); 441 imageResidencyBindInfo.pBinds = &imageResidencyMemoryBinds[0]; 442 443 bindSparseInfo.imageBindCount = 1u; 444 bindSparseInfo.pImageBinds = &imageResidencyBindInfo; 445 } 446 447 if (imageMipTailBinds.size() > 0) 448 { 449 imageMipTailBindInfo.image = *imageSparse; 450 imageMipTailBindInfo.bindCount = static_cast<deUint32>(imageMipTailBinds.size()); 451 imageMipTailBindInfo.pBinds = &imageMipTailBinds[0]; 452 453 bindSparseInfo.imageOpaqueBindCount = 1u; 454 bindSparseInfo.pImageOpaqueBinds = &imageMipTailBindInfo; 455 } 456 457 // Submit sparse bind commands for execution 458 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL)); 459 } 460 461 // Create image to store texels copied from sparse image 462 imageTexelsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 463 imageTexelsInfo.pNext = DE_NULL; 464 imageTexelsInfo.flags = 0u; 465 imageTexelsInfo.imageType = imageSparseInfo.imageType; 466 imageTexelsInfo.format = imageSparseInfo.format; 467 imageTexelsInfo.extent = imageSparseInfo.extent; 468 imageTexelsInfo.arrayLayers = imageSparseInfo.arrayLayers; 469 imageTexelsInfo.mipLevels = imageSparseInfo.mipLevels; 470 imageTexelsInfo.samples = imageSparseInfo.samples; 471 imageTexelsInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 472 imageTexelsInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 473 imageTexelsInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | imageOutputUsageFlags(); 474 imageTexelsInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 475 imageTexelsInfo.queueFamilyIndexCount = 0u; 476 imageTexelsInfo.pQueueFamilyIndices = DE_NULL; 477 478 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY) 479 { 480 imageTexelsInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 481 } 482 483 const Unique<VkImage> imageTexels (createImage(deviceInterface, getDevice(), &imageTexelsInfo)); 484 const de::UniquePtr<Allocation> imageTexelsAlloc (bindImage(deviceInterface, getDevice(), getAllocator(), *imageTexels, MemoryRequirement::Any)); 485 486 // Create image to store residency info copied from sparse image 487 imageResidencyInfo = imageTexelsInfo; 488 imageResidencyInfo.format = mapTextureFormat(m_residencyFormat); 489 490 const Unique<VkImage> imageResidency (createImage(deviceInterface, getDevice(), &imageResidencyInfo)); 491 const de::UniquePtr<Allocation> imageResidencyAlloc (bindImage(deviceInterface, getDevice(), getAllocator(), *imageResidency, MemoryRequirement::Any)); 492 493 // Create command buffer for compute and transfer oparations 494 const Unique<VkCommandPool> commandPool(makeCommandPool(deviceInterface, getDevice(), extractQueue.queueFamilyIndex)); 495 const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 496 497 std::vector <VkBufferImageCopy> bufferImageSparseCopy(imageSparseInfo.mipLevels); 498 499 { 500 deUint32 bufferOffset = 0u; 501 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 502 { 503 bufferImageSparseCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, static_cast<VkDeviceSize>(bufferOffset)); 504 bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY); 505 } 506 } 507 508 // Start recording commands 509 beginCommandBuffer(deviceInterface, *commandBuffer); 510 511 // Create input buffer 512 const VkBufferCreateInfo inputBufferCreateInfo = makeBufferCreateInfo(imageSparseSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); 513 const Unique<VkBuffer> inputBuffer (createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo)); 514 const de::UniquePtr<Allocation> inputBufferAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible)); 515 516 // Fill input buffer with reference data 517 std::vector<deUint8> referenceData(imageSparseSizeInBytes); 518 519 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 520 { 521 const deUint32 mipLevelSizeinBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx); 522 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageSparseCopy[mipLevelNdx].bufferOffset); 523 524 for (deUint32 byteNdx = 0u; byteNdx < mipLevelSizeinBytes; ++byteNdx) 525 { 526 referenceData[bufferOffset + byteNdx] = (deUint8)(mipLevelNdx + byteNdx); 527 } 528 } 529 530 deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], imageSparseSizeInBytes); 531 flushMappedMemoryRange(deviceInterface, getDevice(), inputBufferAlloc->getMemory(), inputBufferAlloc->getOffset(), imageSparseSizeInBytes); 532 533 { 534 // Prepare input buffer for data transfer operation 535 const VkBufferMemoryBarrier inputBufferBarrier = makeBufferMemoryBarrier 536 ( 537 VK_ACCESS_HOST_WRITE_BIT, 538 VK_ACCESS_TRANSFER_READ_BIT, 539 *inputBuffer, 540 0u, 541 imageSparseSizeInBytes 542 ); 543 544 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL); 545 } 546 547 const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers); 548 549 { 550 // Prepare sparse image for data transfer operation 551 const VkImageMemoryBarrier imageSparseTransferDstBarrier = makeImageMemoryBarrier 552 ( 553 0u, 554 VK_ACCESS_TRANSFER_WRITE_BIT, 555 VK_IMAGE_LAYOUT_UNDEFINED, 556 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 557 sparseQueue.queueFamilyIndex != extractQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED, 558 sparseQueue.queueFamilyIndex != extractQueue.queueFamilyIndex ? extractQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED, 559 *imageSparse, 560 fullImageSubresourceRange 561 ); 562 563 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferDstBarrier); 564 } 565 566 // Copy reference data from input buffer to sparse image 567 deviceInterface.cmdCopyBufferToImage(*commandBuffer, *inputBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageSparseCopy.size()), &bufferImageSparseCopy[0]); 568 569 recordCommands(*commandBuffer, imageSparseInfo, *imageSparse, *imageTexels, *imageResidency); 570 571 const VkBufferCreateInfo bufferTexelsCreateInfo = makeBufferCreateInfo(imageSparseSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 572 const Unique<VkBuffer> bufferTexels (createBuffer(deviceInterface, getDevice(), &bufferTexelsCreateInfo)); 573 const de::UniquePtr<Allocation> bufferTexelsAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *bufferTexels, MemoryRequirement::HostVisible)); 574 575 // Copy data from texels image to buffer 576 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageTexels, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *bufferTexels, static_cast<deUint32>(bufferImageSparseCopy.size()), &bufferImageSparseCopy[0]); 577 578 const deUint32 imageResidencySizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY); 579 580 const VkBufferCreateInfo bufferResidencyCreateInfo = makeBufferCreateInfo(imageResidencySizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 581 const Unique<VkBuffer> bufferResidency (createBuffer(deviceInterface, getDevice(), &bufferResidencyCreateInfo)); 582 const de::UniquePtr<Allocation> bufferResidencyAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *bufferResidency, MemoryRequirement::HostVisible)); 583 584 // Copy data from residency image to buffer 585 std::vector <VkBufferImageCopy> bufferImageResidencyCopy(imageSparseInfo.mipLevels); 586 587 { 588 deUint32 bufferOffset = 0u; 589 for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) 590 { 591 bufferImageResidencyCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, static_cast<VkDeviceSize>(bufferOffset)); 592 bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY); 593 } 594 } 595 596 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageResidency, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *bufferResidency, static_cast<deUint32>(bufferImageResidencyCopy.size()), &bufferImageResidencyCopy[0]); 597 598 { 599 VkBufferMemoryBarrier bufferOutputHostReadBarriers[2]; 600 601 bufferOutputHostReadBarriers[0] = makeBufferMemoryBarrier 602 ( 603 VK_ACCESS_TRANSFER_WRITE_BIT, 604 VK_ACCESS_HOST_READ_BIT, 605 *bufferTexels, 606 0u, 607 imageSparseSizeInBytes 608 ); 609 610 bufferOutputHostReadBarriers[1] = makeBufferMemoryBarrier 611 ( 612 VK_ACCESS_TRANSFER_WRITE_BIT, 613 VK_ACCESS_HOST_READ_BIT, 614 *bufferResidency, 615 0u, 616 imageResidencySizeInBytes 617 ); 618 619 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 2u, bufferOutputHostReadBarriers, 0u, DE_NULL); 620 } 621 622 // End recording commands 623 endCommandBuffer(deviceInterface, *commandBuffer); 624 625 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT }; 626 627 // Submit commands for execution and wait for completion 628 submitCommandsAndWait(deviceInterface, getDevice(), extractQueue.queueHandle, *commandBuffer, 1u, &memoryBindSemaphore.get(), stageBits); 629 630 // Wait for sparse queue to become idle 631 deviceInterface.queueWaitIdle(sparseQueue.queueHandle); 632 633 // Retrieve data from residency buffer to host memory 634 invalidateMappedMemoryRange(deviceInterface, getDevice(), bufferResidencyAlloc->getMemory(), bufferResidencyAlloc->getOffset(), imageResidencySizeInBytes); 635 636 const deUint32* bufferResidencyData = static_cast<const deUint32*>(bufferResidencyAlloc->getHostPtr()); 637 638 deUint32 pixelOffsetNotAligned = 0u; 639 for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx) 640 { 641 const deUint32 mipLevelSizeInBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, mipmapNdx); 642 const deUint32 pixelOffsetAligned = static_cast<deUint32>(bufferImageResidencyCopy[mipmapNdx].bufferOffset) / tcu::getPixelSize(m_residencyFormat); 643 644 if (deMemCmp(&bufferResidencyData[pixelOffsetAligned], &residencyReferenceData[pixelOffsetNotAligned], mipLevelSizeInBytes) != 0) 645 return tcu::TestStatus::fail("Failed"); 646 647 pixelOffsetNotAligned += mipLevelSizeInBytes / tcu::getPixelSize(m_residencyFormat); 648 } 649 650 // Retrieve data from texels buffer to host memory 651 invalidateMappedMemoryRange(deviceInterface, getDevice(), bufferTexelsAlloc->getMemory(), bufferTexelsAlloc->getOffset(), imageSparseSizeInBytes); 652 653 const deUint8* bufferTexelsData = static_cast<const deUint8*>(bufferTexelsAlloc->getHostPtr()); 654 655 for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx) 656 { 657 const deUint32 mipLevelSizeInBytes = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx); 658 const deUint32 bufferOffset = static_cast<deUint32>(bufferImageSparseCopy[mipmapNdx].bufferOffset); 659 660 if (mipmapNdx < aspectRequirements.imageMipTailFirstLod) 661 { 662 if (mipmapNdx % MEMORY_BLOCK_TYPE_COUNT == MEMORY_BLOCK_BOUND) 663 { 664 if (deMemCmp(&bufferTexelsData[bufferOffset], &referenceData[bufferOffset], mipLevelSizeInBytes) != 0) 665 return tcu::TestStatus::fail("Failed"); 666 } 667 else if (getPhysicalDeviceProperties(instance, physicalDevice).sparseProperties.residencyNonResidentStrict) 668 { 669 std::vector<deUint8> zeroData; 670 zeroData.assign(mipLevelSizeInBytes, 0u); 671 672 if (deMemCmp(&bufferTexelsData[bufferOffset], &zeroData[0], mipLevelSizeInBytes) != 0) 673 return tcu::TestStatus::fail("Failed"); 674 } 675 } 676 else 677 { 678 if (deMemCmp(&bufferTexelsData[bufferOffset], &referenceData[bufferOffset], mipLevelSizeInBytes) != 0) 679 return tcu::TestStatus::fail("Failed"); 680 } 681 } 682 683 return tcu::TestStatus::pass("Passed"); 684 } 685 686 } // sparse 687 } // vkt 688