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