• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
alignedDivide(const VkExtent3D & extent,const VkExtent3D & divisor)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 
getOpTypeImageComponent(const tcu::TextureFormat & format)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 
getImageComponentTypeName(const tcu::TextureFormat & format)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 
getImageComponentVec4TypeName(const tcu::TextureFormat & format)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 
getOpTypeImageSparse(const ImageType imageType,const tcu::TextureFormat & format,const std::string & componentType,const bool requiresSampler)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 
getOpTypeImageResidency(const ImageType imageType)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 
iterate(void)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(makeSemaphore(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 
315 		if (colorAspectIndex == NO_MATCH_FOUND)
316 			TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT");
317 
318 		aspectRequirements = sparseMemoryRequirements[colorAspectIndex];
319 
320 		DE_ASSERT((aspectRequirements.imageMipTailSize % imageMemoryRequirements.alignment) == 0);
321 
322 		const VkImageAspectFlags aspectMask			= aspectRequirements.formatProperties.aspectMask;
323 		const VkExtent3D		 imageGranularity	= aspectRequirements.formatProperties.imageGranularity;
324 		const deUint32			 memoryType			= findMatchingMemoryType(instance, physicalDevice, imageMemoryRequirements, MemoryRequirement::Any);
325 
326 		if (memoryType == NO_MATCH_FOUND)
327 			return tcu::TestStatus::fail("No matching memory type found");
328 
329 		deUint32 pixelOffset = 0u;
330 
331 		std::vector<VkSparseImageMemoryBind>  imageResidencyMemoryBinds;
332 		std::vector<VkSparseMemoryBind>		  imageMipTailBinds;
333 
334 		// Bind memory for each mipmap level
335 		for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
336 		{
337 			const deUint32 mipLevelSizeInPixels = getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx) / tcu::getPixelSize(m_format);
338 
339 			if (mipLevelNdx % MEMORY_BLOCK_TYPE_COUNT == MEMORY_BLOCK_NOT_BOUND)
340 			{
341 				pixelOffset += mipLevelSizeInPixels;
342 				continue;
343 			}
344 
345 			for (deUint32 pixelNdx = 0u; pixelNdx < mipLevelSizeInPixels; ++pixelNdx)
346 			{
347 				residencyReferenceData[pixelOffset + pixelNdx] = MEMORY_BLOCK_BOUND_VALUE;
348 			}
349 
350 			pixelOffset += mipLevelSizeInPixels;
351 
352 			for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx)
353 			{
354 				const VkExtent3D		 mipExtent			= mipLevelExtents(imageSparseInfo.extent, mipLevelNdx);
355 				const tcu::UVec3		 sparseBlocks		= alignedDivide(mipExtent, imageGranularity);
356 				const deUint32			 numSparseBlocks	= sparseBlocks.x() * sparseBlocks.y() * sparseBlocks.z();
357 				const VkImageSubresource subresource		= { aspectMask, mipLevelNdx, layerNdx };
358 
359 				const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(),
360 					imageMemoryRequirements.alignment * numSparseBlocks, memoryType, subresource, makeOffset3D(0u, 0u, 0u), mipExtent);
361 
362 				deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
363 
364 				imageResidencyMemoryBinds.push_back(imageMemoryBind);
365 			}
366 		}
367 
368 		if (aspectRequirements.imageMipTailFirstLod < imageSparseInfo.mipLevels)
369 		{
370 			if (aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT)
371 			{
372 				const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
373 					aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset);
374 
375 				deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
376 
377 				imageMipTailBinds.push_back(imageMipTailMemoryBind);
378 			}
379 			else
380 			{
381 				for (deUint32 layerNdx = 0; layerNdx < imageSparseInfo.arrayLayers; ++layerNdx)
382 				{
383 					const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
384 						aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride);
385 
386 					deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
387 
388 					imageMipTailBinds.push_back(imageMipTailMemoryBind);
389 				}
390 			}
391 
392 			for (deUint32 pixelNdx = pixelOffset; pixelNdx < residencyReferenceData.size(); ++pixelNdx)
393 			{
394 				residencyReferenceData[pixelNdx] = MEMORY_BLOCK_BOUND_VALUE;
395 			}
396 		}
397 
398 		VkBindSparseInfo bindSparseInfo =
399 		{
400 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,	//VkStructureType							sType;
401 			DE_NULL,							//const void*								pNext;
402 			0u,									//deUint32									waitSemaphoreCount;
403 			DE_NULL,							//const VkSemaphore*						pWaitSemaphores;
404 			0u,									//deUint32									bufferBindCount;
405 			DE_NULL,							//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
406 			0u,									//deUint32									imageOpaqueBindCount;
407 			DE_NULL,							//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
408 			0u,									//deUint32									imageBindCount;
409 			DE_NULL,							//const VkSparseImageMemoryBindInfo*		pImageBinds;
410 			1u,									//deUint32									signalSemaphoreCount;
411 			&memoryBindSemaphore.get()			//const VkSemaphore*						pSignalSemaphores;
412 		};
413 
414 		VkSparseImageMemoryBindInfo		  imageResidencyBindInfo;
415 		VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo;
416 
417 		if (imageResidencyMemoryBinds.size() > 0)
418 		{
419 			imageResidencyBindInfo.image		= *imageSparse;
420 			imageResidencyBindInfo.bindCount	= static_cast<deUint32>(imageResidencyMemoryBinds.size());
421 			imageResidencyBindInfo.pBinds		= &imageResidencyMemoryBinds[0];
422 
423 			bindSparseInfo.imageBindCount		= 1u;
424 			bindSparseInfo.pImageBinds			= &imageResidencyBindInfo;
425 		}
426 
427 		if (imageMipTailBinds.size() > 0)
428 		{
429 			imageMipTailBindInfo.image			= *imageSparse;
430 			imageMipTailBindInfo.bindCount		= static_cast<deUint32>(imageMipTailBinds.size());
431 			imageMipTailBindInfo.pBinds			= &imageMipTailBinds[0];
432 
433 			bindSparseInfo.imageOpaqueBindCount = 1u;
434 			bindSparseInfo.pImageOpaqueBinds	= &imageMipTailBindInfo;
435 		}
436 
437 		// Submit sparse bind commands for execution
438 		VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
439 	}
440 
441 	// Create image to store texels copied from sparse image
442 	imageTexelsInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
443 	imageTexelsInfo.pNext					= DE_NULL;
444 	imageTexelsInfo.flags					= 0u;
445 	imageTexelsInfo.imageType				= imageSparseInfo.imageType;
446 	imageTexelsInfo.format					= imageSparseInfo.format;
447 	imageTexelsInfo.extent					= imageSparseInfo.extent;
448 	imageTexelsInfo.arrayLayers				= imageSparseInfo.arrayLayers;
449 	imageTexelsInfo.mipLevels				= imageSparseInfo.mipLevels;
450 	imageTexelsInfo.samples					= imageSparseInfo.samples;
451 	imageTexelsInfo.tiling					= VK_IMAGE_TILING_OPTIMAL;
452 	imageTexelsInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
453 	imageTexelsInfo.usage					= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | imageOutputUsageFlags();
454 	imageTexelsInfo.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;
455 	imageTexelsInfo.queueFamilyIndexCount	= 0u;
456 	imageTexelsInfo.pQueueFamilyIndices		= DE_NULL;
457 
458 	if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
459 	{
460 		imageTexelsInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
461 	}
462 
463 	const Unique<VkImage>			imageTexels			(createImage(deviceInterface, getDevice(), &imageTexelsInfo));
464 	const de::UniquePtr<Allocation>	imageTexelsAlloc	(bindImage(deviceInterface, getDevice(), getAllocator(), *imageTexels, MemoryRequirement::Any));
465 
466 	// Create image to store residency info copied from sparse image
467 	imageResidencyInfo			= imageTexelsInfo;
468 	imageResidencyInfo.format	= mapTextureFormat(m_residencyFormat);
469 
470 	const Unique<VkImage>			imageResidency		(createImage(deviceInterface, getDevice(), &imageResidencyInfo));
471 	const de::UniquePtr<Allocation>	imageResidencyAlloc	(bindImage(deviceInterface, getDevice(), getAllocator(), *imageResidency, MemoryRequirement::Any));
472 
473 	// Create command buffer for compute and transfer oparations
474 	const Unique<VkCommandPool>	  commandPool(makeCommandPool(deviceInterface, getDevice(), extractQueue.queueFamilyIndex));
475 	const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, getDevice(), *commandPool));
476 
477 	std::vector <VkBufferImageCopy> bufferImageSparseCopy(imageSparseInfo.mipLevels);
478 
479 	{
480 		deUint32 bufferOffset = 0u;
481 		for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
482 		{
483 			bufferImageSparseCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, static_cast<VkDeviceSize>(bufferOffset));
484 			bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
485 		}
486 	}
487 
488 	// Start recording commands
489 	beginCommandBuffer(deviceInterface, *commandBuffer);
490 
491 	// Create input buffer
492 	const VkBufferCreateInfo		inputBufferCreateInfo	= makeBufferCreateInfo(imageSparseSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
493 	const Unique<VkBuffer>			inputBuffer				(createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
494 	const de::UniquePtr<Allocation>	inputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
495 
496 	// Fill input buffer with reference data
497 	std::vector<deUint8> referenceData(imageSparseSizeInBytes);
498 
499 	for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
500 	{
501 		const deUint32 mipLevelSizeinBytes	= getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipLevelNdx);
502 		const deUint32 bufferOffset			= static_cast<deUint32>(bufferImageSparseCopy[mipLevelNdx].bufferOffset);
503 
504 		for (deUint32 byteNdx = 0u; byteNdx < mipLevelSizeinBytes; ++byteNdx)
505 		{
506 			referenceData[bufferOffset + byteNdx] = (deUint8)(mipLevelNdx + byteNdx);
507 		}
508 	}
509 
510 	deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], imageSparseSizeInBytes);
511 	flushMappedMemoryRange(deviceInterface, getDevice(), inputBufferAlloc->getMemory(), inputBufferAlloc->getOffset(), imageSparseSizeInBytes);
512 
513 	{
514 		// Prepare input buffer for data transfer operation
515 		const VkBufferMemoryBarrier inputBufferBarrier = makeBufferMemoryBarrier
516 		(
517 			VK_ACCESS_HOST_WRITE_BIT,
518 			VK_ACCESS_TRANSFER_READ_BIT,
519 			*inputBuffer,
520 			0u,
521 			imageSparseSizeInBytes
522 		);
523 
524 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
525 	}
526 
527 	const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers);
528 
529 	{
530 		// Prepare sparse image for data transfer operation
531 		const VkImageMemoryBarrier imageSparseTransferDstBarrier = makeImageMemoryBarrier
532 		(
533 			0u,
534 			VK_ACCESS_TRANSFER_WRITE_BIT,
535 			VK_IMAGE_LAYOUT_UNDEFINED,
536 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
537 			sparseQueue.queueFamilyIndex != extractQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex  : VK_QUEUE_FAMILY_IGNORED,
538 			sparseQueue.queueFamilyIndex != extractQueue.queueFamilyIndex ? extractQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
539 			*imageSparse,
540 			fullImageSubresourceRange
541 		);
542 
543 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferDstBarrier);
544 	}
545 
546 	// Copy reference data from input buffer to sparse image
547 	deviceInterface.cmdCopyBufferToImage(*commandBuffer, *inputBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageSparseCopy.size()), &bufferImageSparseCopy[0]);
548 
549 	recordCommands(*commandBuffer, imageSparseInfo, *imageSparse, *imageTexels, *imageResidency);
550 
551 	const VkBufferCreateInfo		bufferTexelsCreateInfo	= makeBufferCreateInfo(imageSparseSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
552 	const Unique<VkBuffer>			bufferTexels			(createBuffer(deviceInterface, getDevice(), &bufferTexelsCreateInfo));
553 	const de::UniquePtr<Allocation>	bufferTexelsAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *bufferTexels, MemoryRequirement::HostVisible));
554 
555 	// Copy data from texels image to buffer
556 	deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageTexels, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *bufferTexels, static_cast<deUint32>(bufferImageSparseCopy.size()), &bufferImageSparseCopy[0]);
557 
558 	const deUint32				imageResidencySizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
559 
560 	const VkBufferCreateInfo		bufferResidencyCreateInfo	= makeBufferCreateInfo(imageResidencySizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
561 	const Unique<VkBuffer>			bufferResidency				(createBuffer(deviceInterface, getDevice(), &bufferResidencyCreateInfo));
562 	const de::UniquePtr<Allocation>	bufferResidencyAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *bufferResidency, MemoryRequirement::HostVisible));
563 
564 	// Copy data from residency image to buffer
565 	std::vector <VkBufferImageCopy> bufferImageResidencyCopy(imageSparseInfo.mipLevels);
566 
567 	{
568 		deUint32 bufferOffset = 0u;
569 		for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
570 		{
571 			bufferImageResidencyCopy[mipLevelNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipLevelNdx), imageSparseInfo.arrayLayers, mipLevelNdx, static_cast<VkDeviceSize>(bufferOffset));
572 			bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, mipLevelNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
573 		}
574 	}
575 
576 	deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageResidency, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *bufferResidency, static_cast<deUint32>(bufferImageResidencyCopy.size()), &bufferImageResidencyCopy[0]);
577 
578 	{
579 		VkBufferMemoryBarrier bufferOutputHostReadBarriers[2];
580 
581 		bufferOutputHostReadBarriers[0] = makeBufferMemoryBarrier
582 		(
583 			VK_ACCESS_TRANSFER_WRITE_BIT,
584 			VK_ACCESS_HOST_READ_BIT,
585 			*bufferTexels,
586 			0u,
587 			imageSparseSizeInBytes
588 		);
589 
590 		bufferOutputHostReadBarriers[1] = makeBufferMemoryBarrier
591 		(
592 			VK_ACCESS_TRANSFER_WRITE_BIT,
593 			VK_ACCESS_HOST_READ_BIT,
594 			*bufferResidency,
595 			0u,
596 			imageResidencySizeInBytes
597 		);
598 
599 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 2u, bufferOutputHostReadBarriers, 0u, DE_NULL);
600 	}
601 
602 	// End recording commands
603 	endCommandBuffer(deviceInterface, *commandBuffer);
604 
605 	const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
606 
607 	// Submit commands for execution and wait for completion
608 	submitCommandsAndWait(deviceInterface, getDevice(), extractQueue.queueHandle, *commandBuffer, 1u, &memoryBindSemaphore.get(), stageBits);
609 
610 	// Wait for sparse queue to become idle
611 	deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
612 
613 	// Retrieve data from residency buffer to host memory
614 	invalidateMappedMemoryRange(deviceInterface, getDevice(), bufferResidencyAlloc->getMemory(), bufferResidencyAlloc->getOffset(), imageResidencySizeInBytes);
615 
616 	const deUint32* bufferResidencyData = static_cast<const deUint32*>(bufferResidencyAlloc->getHostPtr());
617 
618 	deUint32 pixelOffsetNotAligned = 0u;
619 	for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
620 	{
621 		const deUint32 mipLevelSizeInBytes	= getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_residencyFormat, mipmapNdx);
622 		const deUint32 pixelOffsetAligned	= static_cast<deUint32>(bufferImageResidencyCopy[mipmapNdx].bufferOffset) / tcu::getPixelSize(m_residencyFormat);
623 
624 		if (deMemCmp(&bufferResidencyData[pixelOffsetAligned], &residencyReferenceData[pixelOffsetNotAligned], mipLevelSizeInBytes) != 0)
625 			return tcu::TestStatus::fail("Failed");
626 
627 		pixelOffsetNotAligned += mipLevelSizeInBytes / tcu::getPixelSize(m_residencyFormat);
628 	}
629 
630 	// Retrieve data from texels buffer to host memory
631 	invalidateMappedMemoryRange(deviceInterface, getDevice(), bufferTexelsAlloc->getMemory(), bufferTexelsAlloc->getOffset(), imageSparseSizeInBytes);
632 
633 	const deUint8* bufferTexelsData = static_cast<const deUint8*>(bufferTexelsAlloc->getHostPtr());
634 
635 	for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
636 	{
637 		const deUint32 mipLevelSizeInBytes	= getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx);
638 		const deUint32 bufferOffset			= static_cast<deUint32>(bufferImageSparseCopy[mipmapNdx].bufferOffset);
639 
640 		if (mipmapNdx < aspectRequirements.imageMipTailFirstLod)
641 		{
642 			if (mipmapNdx % MEMORY_BLOCK_TYPE_COUNT == MEMORY_BLOCK_BOUND)
643 			{
644 				if (deMemCmp(&bufferTexelsData[bufferOffset], &referenceData[bufferOffset], mipLevelSizeInBytes) != 0)
645 					return tcu::TestStatus::fail("Failed");
646 			}
647 			else if (getPhysicalDeviceProperties(instance, physicalDevice).sparseProperties.residencyNonResidentStrict)
648 			{
649 				std::vector<deUint8> zeroData;
650 				zeroData.assign(mipLevelSizeInBytes, 0u);
651 
652 				if (deMemCmp(&bufferTexelsData[bufferOffset], &zeroData[0], mipLevelSizeInBytes) != 0)
653 					return tcu::TestStatus::fail("Failed");
654 			}
655 		}
656 		else
657 		{
658 			if (deMemCmp(&bufferTexelsData[bufferOffset], &referenceData[bufferOffset], mipLevelSizeInBytes) != 0)
659 				return tcu::TestStatus::fail("Failed");
660 		}
661 	}
662 
663 	return tcu::TestStatus::pass("Passed");
664 }
665 
666 } // sparse
667 } // vkt
668