• 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  vktSparseResourcesImageSparseResidency.cpp
21  * \brief Sparse partially resident images tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSparseResourcesBufferSparseBinding.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 #include "tcuTestLog.hpp"
43 
44 #include "deMath.h"
45 #include "deUniquePtr.hpp"
46 #include "deStringUtil.hpp"
47 
48 #include "tcuTextureUtil.hpp"
49 #include "tcuTexVerifierUtil.hpp"
50 
51 #include <string>
52 #include <vector>
53 #include <sstream>
54 
55 using namespace vk;
56 
57 namespace vkt
58 {
59 namespace sparse
60 {
61 namespace
62 {
63 
getFormatValueString(const std::vector<std::pair<deUint32,deUint32>> & channelsOnPlane,const std::vector<std::string> & formatValueStrings)64 std::string getFormatValueString	(const std::vector<std::pair<deUint32, deUint32>>& channelsOnPlane,
65 									 const std::vector<std::string>& formatValueStrings)
66 {
67 	std::string result = "( ";
68 	deUint32 i;
69 	for (i=0; i<channelsOnPlane.size(); ++i)
70 	{
71 		result += formatValueStrings[channelsOnPlane[i].first];
72 		if (i < 3)
73 			result += ", ";
74 	}
75 	for (; i < 4; ++i)
76 	{
77 		result += "0";
78 		if (i < 3)
79 			result += ", ";
80 	}
81 	result += " )";
82 	return result;
83 }
84 
getCoordStr(const ImageType imageType,const std::string & x,const std::string & y,const std::string & z)85 const std::string getCoordStr	(const ImageType	imageType,
86 								 const std::string&	x,
87 								 const std::string&	y,
88 								 const std::string&	z)
89 {
90 	switch (imageType)
91 	{
92 		case IMAGE_TYPE_1D:
93 		case IMAGE_TYPE_BUFFER:
94 			return x;
95 
96 		case IMAGE_TYPE_1D_ARRAY:
97 		case IMAGE_TYPE_2D:
98 			return "ivec2(" + x + "," + y + ")";
99 
100 		case IMAGE_TYPE_2D_ARRAY:
101 		case IMAGE_TYPE_3D:
102 		case IMAGE_TYPE_CUBE:
103 		case IMAGE_TYPE_CUBE_ARRAY:
104 			return "ivec3(" + x + "," + y + "," + z + ")";
105 
106 		default:
107 			DE_ASSERT(false);
108 			return "";
109 	}
110 }
111 
computeWorkGroupSize(const VkExtent3D & planeExtent)112 tcu::UVec3 computeWorkGroupSize (const VkExtent3D& planeExtent)
113 {
114 	const deUint32		maxComputeWorkGroupInvocations	= 128u;
115 	const tcu::UVec3	maxComputeWorkGroupSize			= tcu::UVec3(128u, 128u, 64u);
116 
117 	const deUint32 xWorkGroupSize = std::min(std::min(planeExtent.width,	maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations);
118 	const deUint32 yWorkGroupSize = std::min(std::min(planeExtent.height,	maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations /  xWorkGroupSize);
119 	const deUint32 zWorkGroupSize = std::min(std::min(planeExtent.depth,	maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize));
120 
121 	return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize);
122 }
123 
124 class ImageSparseResidencyCase : public TestCase
125 {
126 public:
127 	ImageSparseResidencyCase		(tcu::TestContext&		testCtx,
128 									 const std::string&		name,
129 									 const std::string&		description,
130 									 const ImageType		imageType,
131 									 const tcu::UVec3&		imageSize,
132 									 const VkFormat			format,
133 									 const glu::GLSLVersion	glslVersion,
134 									 const bool				useDeviceGroups);
135 
136 	void			initPrograms	(SourceCollections&		sourceCollections) const;
137 	virtual void	checkSupport	(Context&				context) const;
138 	TestInstance*	createInstance	(Context&				context) const;
139 
140 private:
141 	const bool				m_useDeviceGroups;
142 	const ImageType			m_imageType;
143 	const tcu::UVec3		m_imageSize;
144 	const VkFormat			m_format;
145 	const glu::GLSLVersion	m_glslVersion;
146 };
147 
ImageSparseResidencyCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,const glu::GLSLVersion glslVersion,const bool useDeviceGroups)148 ImageSparseResidencyCase::ImageSparseResidencyCase	(tcu::TestContext&		testCtx,
149 													 const std::string&		name,
150 													 const std::string&		description,
151 													 const ImageType		imageType,
152 													 const tcu::UVec3&		imageSize,
153 													 const VkFormat			format,
154 													 const glu::GLSLVersion	glslVersion,
155 													 const bool				useDeviceGroups)
156 	: TestCase			(testCtx, name, description)
157 	, m_useDeviceGroups	(useDeviceGroups)
158 	, m_imageType		(imageType)
159 	, m_imageSize		(imageSize)
160 	, m_format			(format)
161 	, m_glslVersion		(glslVersion)
162 {
163 }
164 
initPrograms(SourceCollections & sourceCollections) const165 void ImageSparseResidencyCase::initPrograms (SourceCollections&	sourceCollections) const
166 {
167 	// Create compute program
168 	const char* const				versionDecl			= glu::getGLSLVersionDeclaration(m_glslVersion);
169 	const PlanarFormatDescription	formatDescription	= getPlanarFormatDescription(m_format);
170 	const std::string				imageTypeStr		= getShaderImageType(formatDescription, m_imageType);
171 	const std::string				formatDataStr		= getShaderImageDataType(formatDescription);
172 	const tcu::UVec3				shaderGridSize		= getShaderGridSize(m_imageType, m_imageSize);
173 
174 	std::vector<std::string>		formatValueStrings;
175 	switch (formatDescription.channels[0].type)
176 	{
177 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
178 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
179 			formatValueStrings = {
180 				"int(gl_GlobalInvocationID.x) % 127",
181 				"int(gl_GlobalInvocationID.y) % 127",
182 				"int(gl_GlobalInvocationID.z) % 127",
183 				"1"
184 			};
185 			break;
186 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
187 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
188 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
189 			formatValueStrings = {
190 				"float(int(gl_GlobalInvocationID.x) % 127) / 127.0" ,
191 				"float(int(gl_GlobalInvocationID.y) % 127) / 127.0",
192 				"float(int(gl_GlobalInvocationID.z) % 127) / 127.0",
193 				"1.0"
194 			};
195 			break;
196 		default:	DE_ASSERT(false);	break;
197 	}
198 
199 	for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
200 	{
201 		VkFormat						planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
202 		vk::PlanarFormatDescription		compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
203 		VkExtent3D						compatibleShaderGridSize	{ shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u };
204 
205 		std::vector<std::pair<deUint32, deUint32>> channelsOnPlane;
206 		for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
207 		{
208 			if (!formatDescription.hasChannelNdx(channelNdx))
209 				continue;
210 			if (formatDescription.channels[channelNdx].planeNdx != planeNdx)
211 				continue;
212 			channelsOnPlane.push_back({ channelNdx,formatDescription.channels[channelNdx].offsetBits });
213 		}
214 		// reorder channels for multi-planar images
215 		if(formatDescription.numPlanes>1)
216 			std::sort(begin(channelsOnPlane), end(channelsOnPlane), [](const std::pair<deUint32, deUint32>& lhs, const std::pair<deUint32, deUint32>& rhs) { return lhs.second < rhs.second; });
217 		std::string			formatValueStr		= getFormatValueString(channelsOnPlane, formatValueStrings);
218 		VkExtent3D			shaderExtent		= getPlaneExtent(compatibleFormatDescription, compatibleShaderGridSize, planeNdx, 0);
219 		const std::string	formatQualifierStr	= getShaderImageFormatQualifier(planeCompatibleFormat);
220 		const tcu::UVec3	workGroupSize		= computeWorkGroupSize(shaderExtent);
221 
222 		std::ostringstream src;
223 		src << versionDecl << "\n";
224 		if (formatIsR64(m_format))
225 		{
226 			src << "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n"
227 				<< "#extension GL_EXT_shader_image_int64 : require\n";
228 		}
229 		src << "layout (local_size_x = " << workGroupSize.x() << ", local_size_y = " << workGroupSize.y() << ", local_size_z = " << workGroupSize.z() << ") in; \n"
230 			<< "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n"
231 			<< "void main (void)\n"
232 			<< "{\n"
233 			<< "	if( gl_GlobalInvocationID.x < " << shaderExtent.width << " ) \n"
234 			<< "	if( gl_GlobalInvocationID.y < " << shaderExtent.height << " ) \n"
235 			<< "	if( gl_GlobalInvocationID.z < " << shaderExtent.depth << " ) \n"
236 			<< "	{\n"
237 			<< "		imageStore(u_image, " << getCoordStr(m_imageType, "gl_GlobalInvocationID.x", "gl_GlobalInvocationID.y", "gl_GlobalInvocationID.z") << ","
238 			<< formatDataStr << formatValueStr << ");\n"
239 			<< "	}\n"
240 			<< "}\n";
241 		std::ostringstream shaderName;
242 		shaderName << "comp" << planeNdx;
243 		sourceCollections.glslSources.add(shaderName.str()) << glu::ComputeSource(src.str())
244 			<< vk::ShaderBuildOptions(sourceCollections.usedVulkanVersion, vk::SPIRV_VERSION_1_3, vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS);
245 	}
246 }
247 
checkSupport(Context & context) const248 void ImageSparseResidencyCase::checkSupport(Context& context) const
249 {
250 	const InstanceInterface&	instance = context.getInstanceInterface();
251 	const VkPhysicalDevice		physicalDevice = context.getPhysicalDevice();
252 
253 	// Check if image size does not exceed device limits
254 	if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
255 		TCU_THROW(NotSupportedError, "Image size not supported for device");
256 
257 	// Check if device supports sparse operations for image type
258 	if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
259 		TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
260 
261 	 //Check if image format supports storage images
262 	const VkFormatProperties	formatProperties = getPhysicalDeviceFormatProperties(instance, physicalDevice, m_format);
263 	if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
264 		TCU_THROW(NotSupportedError, "Storage images are not supported for this format");
265 
266 	if (formatIsR64(m_format))
267 	{
268 		context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
269 
270 		if (context.getShaderImageAtomicInt64FeaturesEXT().shaderImageInt64Atomics == VK_FALSE)
271 		{
272 			TCU_THROW(NotSupportedError, "shaderImageInt64Atomics is not supported");
273 		}
274 
275 		if (context.getShaderImageAtomicInt64FeaturesEXT().sparseImageInt64Atomics == VK_FALSE)
276 		{
277 			TCU_THROW(NotSupportedError, "sparseImageInt64Atomics is not supported for device");
278 		}
279 	}
280 }
281 
282 class ImageSparseResidencyInstance : public SparseResourcesBaseInstance
283 {
284 public:
285 	ImageSparseResidencyInstance	(Context&			context,
286 									 const ImageType	imageType,
287 									 const tcu::UVec3&	imageSize,
288 									 const VkFormat		format,
289 									 const bool			useDeviceGroups);
290 
291 
292 	tcu::TestStatus	iterate			(void);
293 
294 private:
295 	const bool			m_useDeviceGroups;
296 	const ImageType		m_imageType;
297 	const tcu::UVec3	m_imageSize;
298 	const VkFormat		m_format;
299 };
300 
ImageSparseResidencyInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,const bool useDeviceGroups)301 ImageSparseResidencyInstance::ImageSparseResidencyInstance	(Context&			context,
302 															 const ImageType	imageType,
303 															 const tcu::UVec3&	imageSize,
304 															 const VkFormat		format,
305 															 const bool			useDeviceGroups)
306 	: SparseResourcesBaseInstance	(context, useDeviceGroups)
307 	, m_useDeviceGroups				(useDeviceGroups)
308 	, m_imageType					(imageType)
309 	, m_imageSize					(imageSize)
310 	, m_format						(format)
311 {
312 }
313 
iterate(void)314 tcu::TestStatus ImageSparseResidencyInstance::iterate (void)
315 {
316 	const float					epsilon				= 1e-5f;
317 	const InstanceInterface&	instance			= m_context.getInstanceInterface();
318 
319 	{
320 		// Create logical device supporting both sparse and compute queues
321 		QueueRequirementsVec queueRequirements;
322 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
323 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
324 
325 		createDeviceSupportingQueues(queueRequirements);
326 	}
327 
328 	VkImageCreateInfo			imageCreateInfo;
329 	std::vector<DeviceMemorySp>	deviceMemUniquePtrVec;
330 
331 	const DeviceInterface&			deviceInterface		= getDeviceInterface();
332 	const Queue&					sparseQueue			= getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
333 	const Queue&					computeQueue		= getQueue(VK_QUEUE_COMPUTE_BIT, 0);
334 	const PlanarFormatDescription	formatDescription	= getPlanarFormatDescription(m_format);
335 
336 	// Go through all physical devices
337 	for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++)
338 	{
339 		const deUint32						firstDeviceID				= physDevID;
340 		const deUint32						secondDeviceID				= (firstDeviceID + 1) % m_numPhysicalDevices;
341 
342 		const VkPhysicalDevice				physicalDevice				= getPhysicalDevice(firstDeviceID);
343 		const VkPhysicalDeviceProperties	physicalDeviceProperties	= getPhysicalDeviceProperties(instance, physicalDevice);
344 
345 		imageCreateInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
346 		imageCreateInfo.pNext					= DE_NULL;
347 		imageCreateInfo.flags					= VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
348 		imageCreateInfo.imageType				= mapImageType(m_imageType);
349 		imageCreateInfo.format					= m_format;
350 		imageCreateInfo.extent					= makeExtent3D(getLayerSize(m_imageType, m_imageSize));
351 		imageCreateInfo.mipLevels				= 1u;
352 		imageCreateInfo.arrayLayers				= getNumLayers(m_imageType, m_imageSize);
353 		imageCreateInfo.samples					= VK_SAMPLE_COUNT_1_BIT;
354 		imageCreateInfo.tiling					= VK_IMAGE_TILING_OPTIMAL;
355 		imageCreateInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
356 		imageCreateInfo.usage					= VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
357 												  VK_IMAGE_USAGE_STORAGE_BIT;
358 		imageCreateInfo.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;
359 		imageCreateInfo.queueFamilyIndexCount	= 0u;
360 		imageCreateInfo.pQueueFamilyIndices		= DE_NULL;
361 
362 		if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
363 		{
364 			imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
365 		}
366 
367 		// check if we need to create VkImageView with different VkFormat than VkImage format
368 		VkFormat planeCompatibleFormat0 = getPlaneCompatibleFormatForWriting(formatDescription, 0);
369 		if (planeCompatibleFormat0 != getPlaneCompatibleFormat(formatDescription, 0))
370 		{
371 			imageCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
372 		}
373 
374 		// Check if device supports sparse operations for image format
375 		if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
376 			TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
377 
378 		// Create sparse image
379 		const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageCreateInfo));
380 
381 		// Create sparse image memory bind semaphore
382 		const Unique<VkSemaphore> imageMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
383 
384 		std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements;
385 
386 		{
387 			// Get image general memory requirements
388 			const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
389 
390 			if (imageMemoryRequirements.size > physicalDeviceProperties.limits.sparseAddressSpaceSize)
391 				TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
392 
393 			DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0);
394 
395 			const deUint32						 memoryType = findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), imageMemoryRequirements, MemoryRequirement::Any);
396 
397 			if (memoryType == NO_MATCH_FOUND)
398 				return tcu::TestStatus::fail("No matching memory type found");
399 
400 			if (firstDeviceID != secondDeviceID)
401 			{
402 				VkPeerMemoryFeatureFlags	peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0;
403 				const deUint32				heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType);
404 				deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags);
405 
406 				if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT)    == 0) ||
407 					((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT) == 0))
408 				{
409 					TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC and GENERIC_DST");
410 				}
411 			}
412 
413 			// Get sparse image sparse memory requirements
414 			sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
415 			DE_ASSERT(sparseMemoryRequirements.size() != 0);
416 
417 			const deUint32 metadataAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_METADATA_BIT);
418 
419 			std::vector<VkSparseImageMemoryBind>	imageResidencyMemoryBinds;
420 			std::vector<VkSparseMemoryBind>			imageMipTailMemoryBinds;
421 
422 			// Bind device memory for each aspect
423 			for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
424 			{
425 				const VkImageAspectFlags		aspect				= (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
426 				const deUint32					aspectIndex			= getSparseAspectRequirementsIndex(sparseMemoryRequirements, aspect);
427 
428 				if (aspectIndex == NO_MATCH_FOUND)
429 					TCU_THROW(NotSupportedError, "Not supported image aspect");
430 
431 				VkSparseImageMemoryRequirements	aspectRequirements	= sparseMemoryRequirements[aspectIndex];
432 				VkExtent3D						imageGranularity	= aspectRequirements.formatProperties.imageGranularity;
433 
434 				for (deUint32 layerNdx = 0; layerNdx < imageCreateInfo.arrayLayers; ++layerNdx)
435 				{
436 					for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
437 					{
438 						const VkImageSubresource subresource		= { aspect, mipLevelNdx, layerNdx };
439 						const VkExtent3D		 planeExtent		= getPlaneExtent(formatDescription, imageCreateInfo.extent, planeNdx, mipLevelNdx);
440 						const tcu::UVec3		 numSparseBinds		= alignedDivide(planeExtent, imageGranularity);
441 						const tcu::UVec3		 lastBlockExtent	= tcu::UVec3(planeExtent.width  % imageGranularity.width  ? planeExtent.width  % imageGranularity.width  : imageGranularity.width,
442 																				 planeExtent.height % imageGranularity.height ? planeExtent.height % imageGranularity.height : imageGranularity.height,
443 																				 planeExtent.depth  % imageGranularity.depth  ? planeExtent.depth  % imageGranularity.depth  : imageGranularity.depth);
444 
445 						for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
446 						for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
447 						for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
448 						{
449 							const deUint32 linearIndex = x + y * numSparseBinds.x() + z * numSparseBinds.x() * numSparseBinds.y() + layerNdx * numSparseBinds.x() * numSparseBinds.y() * numSparseBinds.z();
450 
451 							if (linearIndex % 2u == 0u)
452 							{
453 								VkOffset3D offset;
454 								offset.x		= x * imageGranularity.width;
455 								offset.y		= y * imageGranularity.height;
456 								offset.z		= z * imageGranularity.depth;
457 
458 								VkExtent3D extent;
459 								extent.width	= (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : imageGranularity.width;
460 								extent.height	= (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : imageGranularity.height;
461 								extent.depth	= (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : imageGranularity.depth;
462 
463 								const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(),
464 									imageMemoryRequirements.alignment, memoryType, subresource, offset, extent);
465 
466 								deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
467 
468 								imageResidencyMemoryBinds.push_back(imageMemoryBind);
469 							}
470 						}
471 					}
472 
473 					if (!(aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageCreateInfo.mipLevels)
474 					{
475 						const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
476 							aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride);
477 
478 						deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
479 
480 						imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
481 					}
482 
483 					// Metadata
484 					if (metadataAspectIndex != NO_MATCH_FOUND)
485 					{
486 						const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
487 
488 						if (!(metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
489 						{
490 							const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
491 								metadataAspectRequirements.imageMipTailSize, memoryType,
492 								metadataAspectRequirements.imageMipTailOffset + layerNdx * metadataAspectRequirements.imageMipTailStride,
493 								VK_SPARSE_MEMORY_BIND_METADATA_BIT);
494 
495 							deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
496 
497 							imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
498 						}
499 					}
500 				}
501 
502 				if ((aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageCreateInfo.mipLevels)
503 				{
504 					const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
505 						aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset);
506 
507 					deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
508 
509 					imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
510 				}
511 			}
512 
513 			// Metadata
514 			if (metadataAspectIndex != NO_MATCH_FOUND)
515 			{
516 				const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
517 
518 				if ((metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
519 				{
520 					const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
521 						metadataAspectRequirements.imageMipTailSize, memoryType, metadataAspectRequirements.imageMipTailOffset,
522 						VK_SPARSE_MEMORY_BIND_METADATA_BIT);
523 
524 					deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
525 
526 					imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
527 				}
528 			}
529 
530 			const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo =
531 			{
532 				VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR,	//VkStructureType							sType;
533 				DE_NULL,												//const void*								pNext;
534 				firstDeviceID,											//deUint32									resourceDeviceIndex;
535 				secondDeviceID,											//deUint32									memoryDeviceIndex;
536 			};
537 
538 			VkBindSparseInfo bindSparseInfo =
539 			{
540 				VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,						//VkStructureType							sType;
541 				m_useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL,	//const void*								pNext;
542 				0u,														//deUint32									waitSemaphoreCount;
543 				DE_NULL,												//const VkSemaphore*						pWaitSemaphores;
544 				0u,														//deUint32									bufferBindCount;
545 				DE_NULL,												//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
546 				0u,														//deUint32									imageOpaqueBindCount;
547 				DE_NULL,												//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
548 				0u,														//deUint32									imageBindCount;
549 				DE_NULL,												//const VkSparseImageMemoryBindInfo*		pImageBinds;
550 				1u,														//deUint32									signalSemaphoreCount;
551 				&imageMemoryBindSemaphore.get()							//const VkSemaphore*						pSignalSemaphores;
552 			};
553 
554 			VkSparseImageMemoryBindInfo			imageResidencyBindInfo;
555 			VkSparseImageOpaqueMemoryBindInfo	imageMipTailBindInfo;
556 
557 			if (imageResidencyMemoryBinds.size() > 0)
558 			{
559 				imageResidencyBindInfo.image		= *imageSparse;
560 				imageResidencyBindInfo.bindCount	= static_cast<deUint32>(imageResidencyMemoryBinds.size());
561 				imageResidencyBindInfo.pBinds		= imageResidencyMemoryBinds.data();
562 
563 				bindSparseInfo.imageBindCount		= 1u;
564 				bindSparseInfo.pImageBinds			= &imageResidencyBindInfo;
565 			}
566 
567 			if (imageMipTailMemoryBinds.size() > 0)
568 			{
569 				imageMipTailBindInfo.image			= *imageSparse;
570 				imageMipTailBindInfo.bindCount		= static_cast<deUint32>(imageMipTailMemoryBinds.size());
571 				imageMipTailBindInfo.pBinds			= imageMipTailMemoryBinds.data();
572 
573 				bindSparseInfo.imageOpaqueBindCount = 1u;
574 				bindSparseInfo.pImageOpaqueBinds	= &imageMipTailBindInfo;
575 			}
576 
577 			// Submit sparse bind commands for execution
578 			VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
579 		}
580 
581 		// Create command buffer for compute and transfer operations
582 		const Unique<VkCommandPool>		commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
583 		const Unique<VkCommandBuffer>	commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
584 
585 		// Start recording commands
586 		beginCommandBuffer(deviceInterface, *commandBuffer);
587 
588 		// Create descriptor set layout
589 		const Unique<VkDescriptorSetLayout> descriptorSetLayout(
590 			DescriptorSetLayoutBuilder()
591 			.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
592 			.build(deviceInterface, getDevice()));
593 
594 		// Create and bind descriptor set
595 		const Unique<VkDescriptorPool> descriptorPool(
596 			DescriptorPoolBuilder()
597 			.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
598 			.build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, vk::PlanarFormatDescription::MAX_PLANES));
599 
600 		const Unique<VkPipelineLayout>	pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout));
601 		std::vector<de::SharedPtr<vk::Unique<vk::VkShaderModule>>>	shaderModules;
602 		std::vector<de::SharedPtr<vk::Unique<vk::VkPipeline>>>		computePipelines;
603 		std::vector<de::SharedPtr<vk::Unique<vk::VkDescriptorSet>>>	descriptorSets;
604 		std::vector<de::SharedPtr<vk::Unique<vk::VkImageView>>>		imageViews;
605 
606 		const tcu::UVec3 shaderGridSize = getShaderGridSize(m_imageType, m_imageSize);
607 
608 		// Run compute shader for each image plane
609 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
610 		{
611 			const VkImageAspectFlags		aspect						= (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
612 			const VkImageSubresourceRange	subresourceRange			= makeImageSubresourceRange(aspect, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
613 			VkFormat						planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
614 			vk::PlanarFormatDescription		compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
615 			const tcu::UVec3				compatibleShaderGridSize	( shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u);
616 			VkExtent3D						shaderExtent				= getPlaneExtent(compatibleFormatDescription, VkExtent3D{ compatibleShaderGridSize.x(), compatibleShaderGridSize.y(), compatibleShaderGridSize.z() }, planeNdx, 0u);
617 
618 			// Create and bind compute pipeline
619 			std::ostringstream shaderName;
620 			shaderName << "comp" << planeNdx;
621 			auto shaderModule		= makeVkSharedPtr(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get(shaderName.str()), DE_NULL));
622 			shaderModules.push_back(shaderModule);
623 			auto computePipeline	= makeVkSharedPtr(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, shaderModule->get()));
624 			computePipelines.push_back(computePipeline);
625 			deviceInterface.cmdBindPipeline	(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->get());
626 
627 			auto descriptorSet		= makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout));
628 			descriptorSets.push_back(descriptorSet);
629 
630 			auto imageView			= makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), *imageSparse, mapImageViewType(m_imageType), planeCompatibleFormat, subresourceRange));
631 			imageViews.push_back(imageView);
632 			const VkDescriptorImageInfo		imageSparseInfo			= makeDescriptorImageInfo(DE_NULL, imageView->get(), VK_IMAGE_LAYOUT_GENERAL);
633 
634 			DescriptorSetUpdateBuilder()
635 				.writeSingle(descriptorSet->get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageSparseInfo)
636 				.update(deviceInterface, getDevice());
637 
638 			deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet->get(), 0u, DE_NULL);
639 
640 			{
641 				const VkImageMemoryBarrier imageSparseLayoutChangeBarrier = makeImageMemoryBarrier
642 				(
643 					0u,
644 					VK_ACCESS_SHADER_WRITE_BIT,
645 					VK_IMAGE_LAYOUT_UNDEFINED,
646 					VK_IMAGE_LAYOUT_GENERAL,
647 					*imageSparse,
648 					subresourceRange,
649 					sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
650 					sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? computeQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED
651 					);
652 
653 				deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseLayoutChangeBarrier);
654 			}
655 
656 			{
657 				const tcu::UVec3 workGroupSize = computeWorkGroupSize(shaderExtent);
658 
659 				const deUint32 xWorkGroupCount = shaderExtent.width  / workGroupSize.x() + (shaderExtent.width  % workGroupSize.x() ? 1u : 0u);
660 				const deUint32 yWorkGroupCount = shaderExtent.height / workGroupSize.y() + (shaderExtent.height % workGroupSize.y() ? 1u : 0u);
661 				const deUint32 zWorkGroupCount = shaderExtent.depth  / workGroupSize.z() + (shaderExtent.depth  % workGroupSize.z() ? 1u : 0u);
662 
663 				const tcu::UVec3 maxComputeWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u);
664 
665 				if (maxComputeWorkGroupCount.x() < xWorkGroupCount ||
666 					maxComputeWorkGroupCount.y() < yWorkGroupCount ||
667 					maxComputeWorkGroupCount.z() < zWorkGroupCount)
668 				{
669 					TCU_THROW(NotSupportedError, "Image size is not supported");
670 				}
671 
672 				deviceInterface.cmdDispatch(*commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount);
673 			}
674 
675 			{
676 				const VkImageMemoryBarrier imageSparseTransferBarrier = makeImageMemoryBarrier
677 				(
678 					VK_ACCESS_SHADER_WRITE_BIT,
679 					VK_ACCESS_TRANSFER_READ_BIT,
680 					VK_IMAGE_LAYOUT_GENERAL,
681 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
682 					*imageSparse,
683 					subresourceRange
684 				);
685 
686 				deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferBarrier);
687 			}
688 		}
689 
690 		deUint32	imageSizeInBytes = 0;
691 		deUint32	planeOffsets[PlanarFormatDescription::MAX_PLANES];
692 		deUint32	planeRowPitches[PlanarFormatDescription::MAX_PLANES];
693 
694 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
695 		{
696 			planeOffsets[planeNdx]		= imageSizeInBytes;
697 			const deUint32	planeW		= imageCreateInfo.extent.width / (formatDescription.blockWidth * formatDescription.planes[planeNdx].widthDivisor);
698 			planeRowPitches[planeNdx]	= formatDescription.planes[planeNdx].elementSizeBytes * planeW;
699 			imageSizeInBytes			+= getImageMipLevelSizeInBytes(imageCreateInfo.extent, imageCreateInfo.arrayLayers, formatDescription, planeNdx, 0, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
700 		}
701 
702 		const VkBufferCreateInfo		outputBufferCreateInfo	= makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
703 		const Unique<VkBuffer>			outputBuffer			(createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
704 		const de::UniquePtr<Allocation>	outputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
705 		std::vector<VkBufferImageCopy>	bufferImageCopy			(formatDescription.numPlanes);
706 
707 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
708 		{
709 			const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
710 
711 			bufferImageCopy[planeNdx] =
712 			{
713 				planeOffsets[planeNdx],														//	VkDeviceSize				bufferOffset;
714 				0u,																			//	deUint32					bufferRowLength;
715 				0u,																			//	deUint32					bufferImageHeight;
716 				makeImageSubresourceLayers(aspect, 0u, 0u, imageCreateInfo.arrayLayers),	//	VkImageSubresourceLayers	imageSubresource;
717 				makeOffset3D(0, 0, 0),														//	VkOffset3D					imageOffset;
718 				vk::getPlaneExtent(formatDescription, imageCreateInfo.extent, planeNdx, 0)	//	VkExtent3D					imageExtent;
719 			};
720 		}
721 		deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), bufferImageCopy.data());
722 
723 		{
724 			const VkBufferMemoryBarrier outputBufferHostReadBarrier = makeBufferMemoryBarrier
725 			(
726 				VK_ACCESS_TRANSFER_WRITE_BIT,
727 				VK_ACCESS_HOST_READ_BIT,
728 				*outputBuffer,
729 				0u,
730 				imageSizeInBytes
731 			);
732 
733 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferHostReadBarrier, 0u, DE_NULL);
734 		}
735 
736 		// End recording commands
737 		endCommandBuffer(deviceInterface, *commandBuffer);
738 
739 		// The stage at which execution is going to wait for finish of sparse binding operations
740 		const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
741 
742 		// Submit commands for execution and wait for completion
743 		submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits,
744 			0, DE_NULL, m_useDeviceGroups, firstDeviceID);
745 
746 		// Retrieve data from buffer to host memory
747 		invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc);
748 		deUint8*	outputData	= static_cast<deUint8*>(outputBufferAlloc->getHostPtr());
749 		void*		planePointers[PlanarFormatDescription::MAX_PLANES];
750 
751 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
752 			planePointers[planeNdx] = outputData + static_cast<size_t>(planeOffsets[planeNdx]);
753 
754 		// Wait for sparse queue to become idle
755 		//vsk fails:
756 		deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
757 
758 		// write result images to log file
759 		for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
760 		{
761 			if (!formatDescription.hasChannelNdx(channelNdx))
762 				continue;
763 			deUint32					planeNdx					= formatDescription.channels[channelNdx].planeNdx;
764 			vk::VkFormat				planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
765 			vk::PlanarFormatDescription	compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
766 			const tcu::UVec3			compatibleShaderGridSize	(shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u);
767 			tcu::ConstPixelBufferAccess	pixelBuffer					= vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
768 			std::ostringstream str;
769 			str << "image" << channelNdx;
770 			m_context.getTestContext().getLog() << tcu::LogImage(str.str(), str.str(), pixelBuffer);
771 		}
772 
773 		// Validate results
774 		for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
775 		{
776 			if (!formatDescription.hasChannelNdx(channelNdx))
777 				continue;
778 
779 			deUint32						planeNdx					= formatDescription.channels[channelNdx].planeNdx;
780 			const VkImageAspectFlags		aspect						= (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
781 			const deUint32					aspectIndex					= getSparseAspectRequirementsIndex(sparseMemoryRequirements, aspect);
782 
783 			if (aspectIndex == NO_MATCH_FOUND)
784 				TCU_THROW(NotSupportedError, "Not supported image aspect");
785 
786 			VkSparseImageMemoryRequirements	aspectRequirements			= sparseMemoryRequirements[aspectIndex];
787 
788 			vk::VkFormat					planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
789 			vk::PlanarFormatDescription		compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
790 			const tcu::UVec3				compatibleShaderGridSize	( shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u );
791 			VkExtent3D						compatibleImageSize			{ imageCreateInfo.extent.width / formatDescription.blockWidth, imageCreateInfo.extent.height / formatDescription.blockHeight, imageCreateInfo.extent.depth / 1u };
792 			VkExtent3D						compatibleImageGranularity	{ aspectRequirements.formatProperties.imageGranularity.width / formatDescription.blockWidth,
793 																		  aspectRequirements.formatProperties.imageGranularity.height / formatDescription.blockHeight,
794 																		  aspectRequirements.formatProperties.imageGranularity.depth / 1u };
795 			tcu::ConstPixelBufferAccess		pixelBuffer					= vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
796 			VkExtent3D						planeExtent					= getPlaneExtent(compatibleFormatDescription, compatibleImageSize, planeNdx, 0u);
797 			tcu::IVec3						pixelDivider				= pixelBuffer.getDivider();
798 
799 			if( aspectRequirements.imageMipTailFirstLod > 0u )
800 			{
801 				const tcu::UVec3					numSparseBinds	= alignedDivide(planeExtent, compatibleImageGranularity);
802 				const tcu::UVec3					lastBlockExtent	= tcu::UVec3(planeExtent.width  % compatibleImageGranularity.width  ? planeExtent.width  % compatibleImageGranularity.width  : compatibleImageGranularity.width,
803 																				 planeExtent.height % compatibleImageGranularity.height ? planeExtent.height % compatibleImageGranularity.height : compatibleImageGranularity.height,
804 																				 planeExtent.depth  % compatibleImageGranularity.depth  ? planeExtent.depth  % compatibleImageGranularity.depth  : compatibleImageGranularity.depth);
805 
806 				for (deUint32 layerNdx = 0; layerNdx < imageCreateInfo.arrayLayers; ++layerNdx)
807 				{
808 					for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
809 					for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
810 					for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
811 					{
812 						VkExtent3D offset;
813 						offset.width	= x * compatibleImageGranularity.width;
814 						offset.height	= y * compatibleImageGranularity.height;
815 						offset.depth	= z * compatibleImageGranularity.depth + layerNdx * numSparseBinds.z()*compatibleImageGranularity.depth;
816 
817 						VkExtent3D extent;
818 						extent.width	= (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : compatibleImageGranularity.width;
819 						extent.height	= (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : compatibleImageGranularity.height;
820 						extent.depth	= (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : compatibleImageGranularity.depth;
821 
822 						const deUint32 linearIndex = x + y * numSparseBinds.x() + z * numSparseBinds.x() * numSparseBinds.y() + layerNdx * numSparseBinds.x() * numSparseBinds.y() * numSparseBinds.z();
823 
824 						if (linearIndex % 2u == 0u)
825 						{
826 							for (deUint32 offsetZ = offset.depth; offsetZ < offset.depth + extent.depth; ++offsetZ)
827 							for (deUint32 offsetY = offset.height; offsetY < offset.height + extent.height; ++offsetY)
828 							for (deUint32 offsetX = offset.width; offsetX < offset.width + extent.width; ++offsetX)
829 							{
830 								deUint32	iReferenceValue;
831 								float		fReferenceValue;
832 
833 								switch (channelNdx)
834 								{
835 									case 0:
836 										iReferenceValue = offsetX % 127u;
837 										fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
838 										break;
839 									case 1:
840 										iReferenceValue = offsetY % 127u;
841 										fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
842 										break;
843 									case 2:
844 										iReferenceValue = offsetZ % 127u;
845 										fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
846 										break;
847 									case 3:
848 										iReferenceValue = 1u;
849 										fReferenceValue = 1.f;
850 										break;
851 									default:	DE_FATAL("Unexpected channel index");	break;
852 								}
853 
854 								float acceptableError = epsilon;
855 
856 								switch (formatDescription.channels[channelNdx].type)
857 								{
858 									case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
859 									case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
860 									{
861 										const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
862 
863 										if (outputValue.x() != iReferenceValue)
864 											return tcu::TestStatus::fail("Failed");
865 
866 										break;
867 									}
868 									case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
869 									case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
870 									{
871                                         float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
872 										acceptableError += fixedPointError;
873 										const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
874 
875 										if (deAbs(outputValue.x() - fReferenceValue) > acceptableError)
876 											return tcu::TestStatus::fail("Failed");
877 
878 										break;
879 									}
880 									case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
881 									{
882 										const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
883 
884 										if (deAbs( outputValue.x() - fReferenceValue) > acceptableError)
885 											return tcu::TestStatus::fail("Failed");
886 
887 										break;
888 									}
889 									default:	DE_FATAL("Unexpected channel type");	break;
890 								}
891 							}
892 						}
893 						else if (physicalDeviceProperties.sparseProperties.residencyNonResidentStrict)
894 						{
895 							for (deUint32 offsetZ = offset.depth; offsetZ < offset.depth + extent.depth; ++offsetZ)
896 							for (deUint32 offsetY = offset.height; offsetY < offset.height + extent.height; ++offsetY)
897 							for (deUint32 offsetX = offset.width; offsetX < offset.width + extent.width; ++offsetX)
898 							{
899 								float acceptableError = epsilon;
900 
901 								switch (formatDescription.channels[channelNdx].type)
902 								{
903 									case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
904 									case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
905 									{
906 										const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
907 
908 										if (outputValue.x() != 0u)
909 											return tcu::TestStatus::fail("Failed");
910 
911 										break;
912 									}
913 									case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
914 									case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
915 									{
916 										float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
917 										acceptableError += fixedPointError;
918 										const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
919 
920 										if (deAbs(outputValue.x()) > acceptableError)
921 											return tcu::TestStatus::fail("Failed");
922 
923 										break;
924 									}
925 									case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
926 									{
927 										const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
928 
929 										if (deAbs(outputValue.x()) > acceptableError)
930 											return tcu::TestStatus::fail("Failed");
931 
932 										break;
933 									}
934 									default:	DE_FATAL("Unexpected channel type");	break;
935 								}
936 							}
937 						}
938 					}
939 				}
940 			}
941 			else
942 			{
943 				for (deUint32 offsetZ = 0u; offsetZ < planeExtent.depth * imageCreateInfo.arrayLayers; ++offsetZ)
944 				for (deUint32 offsetY = 0u; offsetY < planeExtent.height; ++offsetY)
945 				for (deUint32 offsetX = 0u; offsetX < planeExtent.width; ++offsetX)
946 				{
947 					deUint32	iReferenceValue;
948 					float		fReferenceValue;
949 					switch (channelNdx)
950 					{
951 						case 0:
952 							iReferenceValue = offsetX % 127u;
953 							fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
954 							break;
955 						case 1:
956 							iReferenceValue = offsetY % 127u;
957 							fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
958 							break;
959 						case 2:
960 							iReferenceValue = offsetZ % 127u;
961 							fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
962 							break;
963 						case 3:
964 							iReferenceValue = 1u;
965 							fReferenceValue = 1.f;
966 							break;
967 						default:	DE_FATAL("Unexpected channel index");	break;
968 					}
969 					float acceptableError = epsilon;
970 
971 					switch (formatDescription.channels[channelNdx].type)
972 					{
973 						case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
974 						case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
975 						{
976 							const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
977 
978 							if (outputValue.x() != iReferenceValue)
979 								return tcu::TestStatus::fail("Failed");
980 
981 							break;
982 						}
983 						case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
984 						case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
985 						{
986 							float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
987 							acceptableError += fixedPointError;
988 							const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
989 
990 							if (deAbs(outputValue.x() - fReferenceValue) > acceptableError)
991 								return tcu::TestStatus::fail("Failed");
992 
993 							break;
994 						}
995 						case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
996 						{
997 							const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
998 
999 							if (deAbs( outputValue.x() - fReferenceValue) > acceptableError)
1000 								return tcu::TestStatus::fail("Failed");
1001 
1002 							break;
1003 						}
1004 						default:	DE_FATAL("Unexpected channel type");	break;
1005 					}
1006 				}
1007 			}
1008 		}
1009 	}
1010 
1011 	return tcu::TestStatus::pass("Passed");
1012 }
1013 
createInstance(Context & context) const1014 TestInstance* ImageSparseResidencyCase::createInstance (Context& context) const
1015 {
1016 	return new ImageSparseResidencyInstance(context, m_imageType, m_imageSize, m_format, m_useDeviceGroups);
1017 }
1018 
1019 } // anonymous ns
1020 
createImageSparseResidencyTestsCommon(tcu::TestContext & testCtx,de::MovePtr<tcu::TestCaseGroup> testGroup,const bool useDeviceGroup=false)1021 tcu::TestCaseGroup* createImageSparseResidencyTestsCommon (tcu::TestContext& testCtx, de::MovePtr<tcu::TestCaseGroup> testGroup, const bool useDeviceGroup = false)
1022 {
1023 	const std::vector<TestImageParameters> imageParameters =
1024 	{
1025 		{ IMAGE_TYPE_2D,			{ tcu::UVec3(512u, 256u,  1u),	tcu::UVec3(1024u, 128u, 1u),	tcu::UVec3(11u,  137u, 1u) },	getTestFormats(IMAGE_TYPE_2D) },
1026 		{ IMAGE_TYPE_2D_ARRAY,		{ tcu::UVec3(512u, 256u,  6u),	tcu::UVec3(1024u, 128u, 8u),	tcu::UVec3(11u,  137u, 3u) },	getTestFormats(IMAGE_TYPE_2D_ARRAY) },
1027 		{ IMAGE_TYPE_CUBE,			{ tcu::UVec3(256u, 256u,  1u),	tcu::UVec3(128u,  128u, 1u),	tcu::UVec3(137u, 137u, 1u) },	getTestFormats(IMAGE_TYPE_CUBE) },
1028 		{ IMAGE_TYPE_CUBE_ARRAY,	{ tcu::UVec3(256u, 256u,  6u),	tcu::UVec3(128u,  128u, 8u),	tcu::UVec3(137u, 137u, 3u) },	getTestFormats(IMAGE_TYPE_CUBE_ARRAY) },
1029 		{ IMAGE_TYPE_3D,			{ tcu::UVec3(512u, 256u, 16u),	tcu::UVec3(1024u, 128u, 8u),	tcu::UVec3(11u,  137u, 3u) },	getTestFormats(IMAGE_TYPE_3D) }
1030 	};
1031 
1032 	for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
1033 	{
1034 		const ImageType					imageType = imageParameters[imageTypeNdx].imageType;
1035 		de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
1036 
1037 		for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
1038 		{
1039 			const VkFormat					format				= imageParameters[imageTypeNdx].formats[formatNdx].format;
1040 			tcu::UVec3						imageSizeAlignment	= getImageSizeAlignment(format);
1041 			de::MovePtr<tcu::TestCaseGroup> formatGroup			(new tcu::TestCaseGroup(testCtx, getImageFormatID(format).c_str(), ""));
1042 
1043 			for (size_t imageSizeNdx = 0; imageSizeNdx < imageParameters[imageTypeNdx].imageSizes.size(); ++imageSizeNdx)
1044 			{
1045 				const tcu::UVec3 imageSize = imageParameters[imageTypeNdx].imageSizes[imageSizeNdx];
1046 
1047 				// skip test for images with odd sizes for some YCbCr formats
1048 				if ((imageSize.x() % imageSizeAlignment.x()) != 0)
1049 					continue;
1050 				if ((imageSize.y() % imageSizeAlignment.y()) != 0)
1051 					continue;
1052 
1053 				std::ostringstream stream;
1054 				stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
1055 
1056 				formatGroup->addChild(new ImageSparseResidencyCase(testCtx, stream.str(), "", imageType, imageSize, format, glu::GLSL_VERSION_440, useDeviceGroup));
1057 			}
1058 			imageTypeGroup->addChild(formatGroup.release());
1059 		}
1060 		testGroup->addChild(imageTypeGroup.release());
1061 	}
1062 
1063 	return testGroup.release();
1064 }
1065 
createImageSparseResidencyTests(tcu::TestContext & testCtx)1066 tcu::TestCaseGroup* createImageSparseResidencyTests (tcu::TestContext& testCtx)
1067 {
1068 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_residency", "Image Sparse Residency"));
1069 	return createImageSparseResidencyTestsCommon(testCtx, testGroup);
1070 }
1071 
createDeviceGroupImageSparseResidencyTests(tcu::TestContext & testCtx)1072 tcu::TestCaseGroup* createDeviceGroupImageSparseResidencyTests (tcu::TestContext& testCtx)
1073 {
1074 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "device_group_image_sparse_residency", "Image Sparse Residency"));
1075 	return createImageSparseResidencyTestsCommon(testCtx, testGroup, true);
1076 }
1077 
1078 } // sparse
1079 } // vkt
1080