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  vktSparseResourcesImageSparseBinding.cpp
21  * \brief Sparse fully resident images with mipmaps 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 "vkBuilderUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 
40 #include "deUniquePtr.hpp"
41 #include "deStringUtil.hpp"
42 
43 #include <string>
44 #include <vector>
45 
46 using namespace vk;
47 
48 namespace vkt
49 {
50 namespace sparse
51 {
52 namespace
53 {
54 
55 class ImageSparseBindingCase : public TestCase
56 {
57 public:
58 					ImageSparseBindingCase	(tcu::TestContext&			testCtx,
59 											 const std::string&			name,
60 											 const std::string&			description,
61 											 const ImageType			imageType,
62 											 const tcu::UVec3&			imageSize,
63 											 const tcu::TextureFormat&	format);
64 
65 	TestInstance*	createInstance			(Context&			context) const;
66 
67 private:
68 	const ImageType				m_imageType;
69 	const tcu::UVec3			m_imageSize;
70 	const tcu::TextureFormat	m_format;
71 };
72 
ImageSparseBindingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const ImageType imageType,const tcu::UVec3 & imageSize,const tcu::TextureFormat & format)73 ImageSparseBindingCase::ImageSparseBindingCase (tcu::TestContext&			testCtx,
74 												const std::string&			name,
75 												const std::string&			description,
76 												const ImageType				imageType,
77 												const tcu::UVec3&			imageSize,
78 												const tcu::TextureFormat&	format)
79 	: TestCase				(testCtx, name, description)
80 	, m_imageType			(imageType)
81 	, m_imageSize			(imageSize)
82 	, m_format				(format)
83 {
84 }
85 
86 class ImageSparseBindingInstance : public SparseResourcesBaseInstance
87 {
88 public:
89 					ImageSparseBindingInstance	(Context&					context,
90 												 const ImageType			imageType,
91 												 const tcu::UVec3&			imageSize,
92 												 const tcu::TextureFormat&	format);
93 
94 	tcu::TestStatus	iterate						(void);
95 
96 private:
97 	const ImageType				m_imageType;
98 	const tcu::UVec3			m_imageSize;
99 	const tcu::TextureFormat	m_format;
100 };
101 
ImageSparseBindingInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const tcu::TextureFormat & format)102 ImageSparseBindingInstance::ImageSparseBindingInstance (Context&					context,
103 														const ImageType				imageType,
104 														const tcu::UVec3&			imageSize,
105 														const tcu::TextureFormat&	format)
106 	: SparseResourcesBaseInstance	(context)
107 	, m_imageType					(imageType)
108 	, m_imageSize					(imageSize)
109 	, m_format						(format)
110 {
111 }
112 
iterate(void)113 tcu::TestStatus ImageSparseBindingInstance::iterate (void)
114 {
115 	const InstanceInterface&	instance		= m_context.getInstanceInterface();
116 	const DeviceInterface&		deviceInterface = m_context.getDeviceInterface();
117 	const VkPhysicalDevice		physicalDevice	= m_context.getPhysicalDevice();
118 
119 	// Check if device supports sparse binding
120 	const VkPhysicalDeviceFeatures  deviceFeatures = getPhysicalDeviceFeatures(instance, physicalDevice);
121 
122 	if (deviceFeatures.sparseBinding == false)
123 	{
124 		return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Device does not support sparse binding");
125 	}
126 
127 	// Check if image size does not exceed device limits
128 	const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
129 
130 	if (isImageSizeSupported(m_imageType, m_imageSize, deviceProperties.limits) == false)
131 	{
132 		return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Image size not supported for device");
133 	}
134 
135 	QueueRequirementsVec queueRequirements;
136 	queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
137 	queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
138 
139 	// Create logical device supporting both sparse and compute queues
140 	if (!createDeviceSupportingQueues(queueRequirements))
141 	{
142 		return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Could not create device supporting sparse and compute queue");
143 	}
144 
145 	const VkPhysicalDeviceMemoryProperties	deviceMemoryProperties = getPhysicalDeviceMemoryProperties(instance, physicalDevice);
146 
147 	// Create memory allocator for logical device
148 	const de::UniquePtr<Allocator> allocator(new SimpleAllocator(deviceInterface, *m_logicalDevice, deviceMemoryProperties));
149 
150 	// Create queue supporting sparse binding operations
151 	const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
152 
153 	// Create queue supporting compute and transfer operations
154 	const Queue& computeQueue = getQueue(VK_QUEUE_COMPUTE_BIT, 0);
155 
156 	VkImageCreateInfo imageSparseInfo;
157 
158 	imageSparseInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;					//VkStructureType		sType;
159 	imageSparseInfo.pNext					= DE_NULL;												//const void*			pNext;
160 	imageSparseInfo.flags					= VK_IMAGE_CREATE_SPARSE_BINDING_BIT;					//VkImageCreateFlags	flags;
161 	imageSparseInfo.imageType				= mapImageType(m_imageType);							//VkImageType			imageType;
162 	imageSparseInfo.format					= mapTextureFormat(m_format);							//VkFormat				format;
163 	imageSparseInfo.extent					= makeExtent3D(getLayerSize(m_imageType, m_imageSize));	//VkExtent3D			extent;
164 	imageSparseInfo.arrayLayers				= getNumLayers(m_imageType, m_imageSize);				//deUint32				arrayLayers;
165 	imageSparseInfo.samples					= VK_SAMPLE_COUNT_1_BIT;								//VkSampleCountFlagBits	samples;
166 	imageSparseInfo.tiling					= VK_IMAGE_TILING_OPTIMAL;								//VkImageTiling			tiling;
167 	imageSparseInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;							//VkImageLayout			initialLayout;
168 	imageSparseInfo.usage					= VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
169 											  VK_IMAGE_USAGE_TRANSFER_DST_BIT;						//VkImageUsageFlags		usage;
170 	imageSparseInfo.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;							//VkSharingMode			sharingMode;
171 	imageSparseInfo.queueFamilyIndexCount	= 0u;													//deUint32				queueFamilyIndexCount;
172 	imageSparseInfo.pQueueFamilyIndices		= DE_NULL;												//const deUint32*		pQueueFamilyIndices;
173 
174 	if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
175 	{
176 		imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
177 	}
178 
179 	VkImageFormatProperties imageFormatProperties;
180 	instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
181 													imageSparseInfo.format,
182 													imageSparseInfo.imageType,
183 													imageSparseInfo.tiling,
184 													imageSparseInfo.usage,
185 													imageSparseInfo.flags,
186 													&imageFormatProperties);
187 
188 	imageSparseInfo.mipLevels = getImageMaxMipLevels(imageFormatProperties, imageSparseInfo);
189 
190 	// Allow sharing of sparse image by two different queue families (if necessary)
191 	const deUint32 queueFamilyIndices[] = { sparseQueue.queueFamilyIndex, computeQueue.queueFamilyIndex };
192 
193 	if (sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex)
194 	{
195 		imageSparseInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;	//VkSharingMode			sharingMode;
196 		imageSparseInfo.queueFamilyIndexCount = 2u;					//deUint32				queueFamilyIndexCount;
197 		imageSparseInfo.pQueueFamilyIndices = queueFamilyIndices;	//const deUint32*		pQueueFamilyIndices;
198 	}
199 
200 	// Create sparse image
201 	const Unique<VkImage> imageSparse(createImage(deviceInterface, *m_logicalDevice, &imageSparseInfo));
202 
203 	// Get sparse image general memory requirements
204 	const VkMemoryRequirements imageSparseMemRequirements = getImageMemoryRequirements(deviceInterface, *m_logicalDevice, *imageSparse);
205 
206 	// Check if required image memory size does not exceed device limits
207 	if (imageSparseMemRequirements.size > deviceProperties.limits.sparseAddressSpaceSize)
208 	{
209 		return tcu::TestStatus(QP_TEST_RESULT_NOT_SUPPORTED, "Required memory size for sparse resource exceeds device limits");
210 	}
211 
212 	DE_ASSERT((imageSparseMemRequirements.size % imageSparseMemRequirements.alignment) == 0);
213 
214 	typedef de::SharedPtr< Unique<VkDeviceMemory> > DeviceMemoryUniquePtr;
215 
216 	std::vector<VkSparseMemoryBind>		sparseMemoryBinds;
217 	std::vector<DeviceMemoryUniquePtr>	deviceMemUniquePtrVec;
218 	const deUint32						numSparseBinds	= static_cast<deUint32>(imageSparseMemRequirements.size / imageSparseMemRequirements.alignment);
219 	const deUint32						memoryType		= findMatchingMemoryType(deviceMemoryProperties, imageSparseMemRequirements, MemoryRequirement::Any);
220 
221 	if (memoryType == NO_MATCH_FOUND)
222 	{
223 		return tcu::TestStatus(QP_TEST_RESULT_FAIL, "No matching memory type found");
224 	}
225 
226 	for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseBinds; ++sparseBindNdx)
227 	{
228 		const VkMemoryAllocateInfo allocInfo =
229 		{
230 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType			sType;
231 			DE_NULL,								//	const void*				pNext;
232 			imageSparseMemRequirements.alignment,	//	VkDeviceSize			allocationSize;
233 			memoryType,								//	deUint32				memoryTypeIndex;
234 		};
235 
236 		VkDeviceMemory deviceMemory = 0;
237 		VK_CHECK(deviceInterface.allocateMemory(*m_logicalDevice, &allocInfo, DE_NULL, &deviceMemory));
238 
239 		deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(deviceMemory), Deleter<VkDeviceMemory>(deviceInterface, *m_logicalDevice, DE_NULL))));
240 
241 		const VkSparseMemoryBind sparseMemoryBind = makeSparseMemoryBind
242 		(
243 			imageSparseMemRequirements.alignment * sparseBindNdx,	//VkDeviceSize				resourceOffset
244 			imageSparseMemRequirements.alignment,					//VkDeviceSize				size
245 			deviceMemory,											//VkDeviceMemory			memory;
246 			0u,														//VkDeviceSize				memoryOffset;
247 			0u														//VkSparseMemoryBindFlags	flags;
248 		);
249 
250 		sparseMemoryBinds.push_back(sparseMemoryBind);
251 	}
252 
253 	const VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo = makeSparseImageOpaqueMemoryBindInfo
254 	(
255 		*imageSparse,			// VkImage						image
256 		numSparseBinds,			// deUint32						bindCount
257 		&sparseMemoryBinds[0]   // const VkSparseMemoryBind*	pBinds
258 	);
259 
260 	const Unique<VkSemaphore> imageMemoryBindSemaphore(makeSemaphore(deviceInterface, *m_logicalDevice));
261 
262 	const VkBindSparseInfo bindSparseInfo =
263 	{
264 		VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,			//VkStructureType							sType;
265 		DE_NULL,									//const void*								pNext;
266 		0u,											//deUint32									waitSemaphoreCount;
267 		DE_NULL,									//const VkSemaphore*						pWaitSemaphores;
268 		0u,											//deUint32									bufferBindCount;
269 		DE_NULL,									//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
270 		1u,											//deUint32									imageOpaqueBindCount;
271 		&opaqueBindInfo,							//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
272 		0u,											//deUint32									imageBindCount;
273 		DE_NULL,									//const VkSparseImageMemoryBindInfo*		pImageBinds;
274 		1u,											//deUint32									signalSemaphoreCount;
275 		&imageMemoryBindSemaphore.get()				//const VkSemaphore*						pSignalSemaphores;
276 	};
277 
278 	// Submit sparse bind commands for execution
279 	VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
280 
281 	// Create command buffer for compute and transfer oparations
282 	const Unique<VkCommandPool>	  commandPool(makeCommandPool(deviceInterface, *m_logicalDevice, computeQueue.queueFamilyIndex));
283 	const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, *m_logicalDevice, *commandPool));
284 
285 	// Start recording commands
286 	beginCommandBuffer(deviceInterface, *commandBuffer);
287 
288 	const deUint32				imageSizeInBytes = getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels);
289 	const VkBufferCreateInfo	inputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
290 
291 	const de::UniquePtr<Buffer>	inputBuffer(new Buffer(deviceInterface, *m_logicalDevice, *allocator, inputBufferCreateInfo, MemoryRequirement::HostVisible));
292 
293 	std::vector<deUint8> referenceData;
294 	referenceData.resize(imageSizeInBytes);
295 
296 	for (deUint32 valueNdx = 0; valueNdx < imageSizeInBytes; ++valueNdx)
297 	{
298 		referenceData[valueNdx] = static_cast<deUint8>((valueNdx % imageSparseMemRequirements.alignment) + 1u);
299 	}
300 
301 	deMemcpy(inputBuffer->getAllocation().getHostPtr(), &referenceData[0], imageSizeInBytes);
302 
303 	flushMappedMemoryRange(deviceInterface, *m_logicalDevice, inputBuffer->getAllocation().getMemory(), inputBuffer->getAllocation().getOffset(), imageSizeInBytes);
304 
305 	const VkBufferMemoryBarrier inputBufferBarrier
306 		= makeBufferMemoryBarrier(
307 		VK_ACCESS_HOST_WRITE_BIT,
308 		VK_ACCESS_TRANSFER_READ_BIT,
309 		inputBuffer->get(),
310 		0u,
311 		imageSizeInBytes);
312 
313 	const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers);
314 
315 	const VkImageMemoryBarrier imageSparseTransferDstBarrier
316 		= makeImageMemoryBarrier(
317 		0u,
318 		VK_ACCESS_TRANSFER_WRITE_BIT,
319 		VK_IMAGE_LAYOUT_UNDEFINED,
320 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
321 		*imageSparse,
322 		fullImageSubresourceRange);
323 
324 	deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 1u, &imageSparseTransferDstBarrier);
325 
326 	std::vector <VkBufferImageCopy> bufferImageCopy;
327 	bufferImageCopy.resize(imageSparseInfo.mipLevels);
328 
329 	VkDeviceSize bufferOffset = 0;
330 	for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; mipmapNdx++)
331 	{
332 		bufferImageCopy[mipmapNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipmapNdx), imageSparseInfo.arrayLayers, mipmapNdx, bufferOffset);
333 
334 		bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx);
335 	}
336 
337 	deviceInterface.cmdCopyBufferToImage(*commandBuffer, inputBuffer->get(), *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]);
338 
339 	const VkImageMemoryBarrier imageSparseTransferSrcBarrier
340 		= makeImageMemoryBarrier(
341 		VK_ACCESS_TRANSFER_WRITE_BIT,
342 		VK_ACCESS_TRANSFER_READ_BIT,
343 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
344 		VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
345 		*imageSparse,
346 		fullImageSubresourceRange);
347 
348 	deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferSrcBarrier);
349 
350 	const VkBufferCreateInfo	outputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
351 	const de::UniquePtr<Buffer>	outputBuffer(new Buffer(deviceInterface, *m_logicalDevice, *allocator, outputBufferCreateInfo, MemoryRequirement::HostVisible));
352 
353 	deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffer->get(), static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]);
354 
355 	const VkBufferMemoryBarrier outputBufferBarrier
356 		= makeBufferMemoryBarrier(
357 		VK_ACCESS_TRANSFER_WRITE_BIT,
358 		VK_ACCESS_HOST_READ_BIT,
359 		outputBuffer->get(),
360 		0u,
361 		imageSizeInBytes);
362 
363 	deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
364 
365 	// End recording commands
366 	endCommandBuffer(deviceInterface, *commandBuffer);
367 
368 	const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
369 
370 	// Submit commands for execution and wait for completion
371 	submitCommandsAndWait(deviceInterface, *m_logicalDevice, computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits);
372 
373 	// Retrieve data from buffer to host memory
374 	const Allocation& allocation = outputBuffer->getAllocation();
375 
376 	invalidateMappedMemoryRange(deviceInterface, *m_logicalDevice, allocation.getMemory(), allocation.getOffset(), imageSizeInBytes);
377 
378 	const deUint8*  outputData = static_cast<const deUint8*>(allocation.getHostPtr());
379 	tcu::TestStatus testStatus = tcu::TestStatus::pass("Passed");
380 
381 	if (deMemCmp(outputData, &referenceData[0], imageSizeInBytes) != 0)
382 	{
383 		testStatus = tcu::TestStatus::fail("Failed");
384 	}
385 
386 	// Wait for sparse queue to become idle
387 	deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
388 
389 	return testStatus;
390 }
391 
createInstance(Context & context) const392 TestInstance* ImageSparseBindingCase::createInstance (Context& context) const
393 {
394 	return new ImageSparseBindingInstance(context, m_imageType, m_imageSize, m_format);
395 }
396 
397 } // anonymous ns
398 
createImageSparseBindingTests(tcu::TestContext & testCtx)399 tcu::TestCaseGroup* createImageSparseBindingTests(tcu::TestContext& testCtx)
400 {
401 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_binding", "Buffer Sparse Binding"));
402 
403 	static const deUint32 sizeCountPerImageType = 3u;
404 
405 	struct ImageParameters
406 	{
407 		ImageType	imageType;
408 		tcu::UVec3	imageSizes[sizeCountPerImageType];
409 	};
410 
411 	static const ImageParameters imageParametersArray[] =
412 	{
413 		{ IMAGE_TYPE_1D,		{ tcu::UVec3(512u, 1u,   1u ), tcu::UVec3(1024u, 1u,   1u), tcu::UVec3(11u, 1u,   1u) } },
414 		{ IMAGE_TYPE_1D_ARRAY,  { tcu::UVec3(512u, 1u,   64u), tcu::UVec3(1024u, 1u,   8u), tcu::UVec3(11u, 1u,   3u) } },
415 		{ IMAGE_TYPE_2D,		{ tcu::UVec3(512u, 256u, 1u ), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u, 137u, 1u) } },
416 		{ IMAGE_TYPE_2D_ARRAY,	{ tcu::UVec3(512u, 256u, 6u ), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) } },
417 		{ IMAGE_TYPE_3D,		{ tcu::UVec3(512u, 256u, 6u ), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) } },
418 		{ IMAGE_TYPE_CUBE,		{ tcu::UVec3(512u, 256u, 1u ), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u, 137u, 1u) } },
419 		{ IMAGE_TYPE_CUBE_ARRAY,{ tcu::UVec3(512u, 256u, 6u ), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) } }
420 	};
421 
422 	static const tcu::TextureFormat formats[] =
423 	{
424 		tcu::TextureFormat(tcu::TextureFormat::R,		tcu::TextureFormat::SIGNED_INT32),
425 		tcu::TextureFormat(tcu::TextureFormat::R,		tcu::TextureFormat::SIGNED_INT16),
426 		tcu::TextureFormat(tcu::TextureFormat::R,		tcu::TextureFormat::SIGNED_INT8),
427 		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT32),
428 		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT16),
429 		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT8)
430 	};
431 
432 	for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray); ++imageTypeNdx)
433 	{
434 		const ImageType					imageType = imageParametersArray[imageTypeNdx].imageType;
435 		de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
436 
437 		for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
438 		{
439 			const tcu::TextureFormat&		format = formats[formatNdx];
440 			de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, getShaderImageFormatQualifier(format).c_str(), ""));
441 
442 			for (deInt32 imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray[imageTypeNdx].imageSizes); ++imageSizeNdx)
443 			{
444 				const tcu::UVec3 imageSize = imageParametersArray[imageTypeNdx].imageSizes[imageSizeNdx];
445 
446 				std::ostringstream stream;
447 				stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
448 
449 				formatGroup->addChild(new ImageSparseBindingCase(testCtx, stream.str(), "", imageType, imageSize, format));
450 			}
451 			imageTypeGroup->addChild(formatGroup.release());
452 		}
453 		testGroup->addChild(imageTypeGroup.release());
454 	}
455 
456 	return testGroup.release();
457 }
458 
459 } // sparse
460 } // vkt
461