• 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 #include "vkCmdUtil.hpp"
26 #include "vkBarrierUtil.hpp"
27 
28 using namespace vk;
29 
30 namespace vkt
31 {
32 namespace sparse
33 {
34 
getOpTypeImageComponent(const tcu::TextureFormat & format)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 
getImageComponentTypeName(const tcu::TextureFormat & format)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 
getImageComponentVec4TypeName(const tcu::TextureFormat & format)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 
getOpTypeImageSparse(const ImageType imageType,const tcu::TextureFormat & format,const std::string & componentType,const bool requiresSampler)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 
getOpTypeImageResidency(const ImageType imageType)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 
iterate(void)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