Home | History | Annotate | Download | only in sparse_resources
      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