• Home
  • History
  • Annotate
  • 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  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 VkPhysicalDevice		physicalDevice	= m_context.getPhysicalDevice();
117 	VkImageCreateInfo			imageSparseInfo;
118 	std::vector<DeviceMemorySp>	deviceMemUniquePtrVec;
119 
120 	// Check if image size does not exceed device limits
121 	if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
122 		TCU_THROW(NotSupportedError, "Image size not supported for device");
123 
124 	// Check if device supports sparse binding
125 	if (!getPhysicalDeviceFeatures(instance, physicalDevice).sparseBinding)
126 		TCU_THROW(NotSupportedError, "Device does not support sparse binding");
127 
128 	{
129 		// Create logical device supporting both sparse and compute queues
130 		QueueRequirementsVec queueRequirements;
131 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
132 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
133 
134 		createDeviceSupportingQueues(queueRequirements);
135 	}
136 
137 	const DeviceInterface&	deviceInterface	= getDeviceInterface();
138 	const Queue&			sparseQueue		= getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
139 	const Queue&			computeQueue	= getQueue(VK_QUEUE_COMPUTE_BIT, 0);
140 
141 	imageSparseInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;					//VkStructureType		sType;
142 	imageSparseInfo.pNext					= DE_NULL;												//const void*			pNext;
143 	imageSparseInfo.flags					= VK_IMAGE_CREATE_SPARSE_BINDING_BIT;					//VkImageCreateFlags	flags;
144 	imageSparseInfo.imageType				= mapImageType(m_imageType);							//VkImageType			imageType;
145 	imageSparseInfo.format					= mapTextureFormat(m_format);							//VkFormat				format;
146 	imageSparseInfo.extent					= makeExtent3D(getLayerSize(m_imageType, m_imageSize));	//VkExtent3D			extent;
147 	imageSparseInfo.arrayLayers				= getNumLayers(m_imageType, m_imageSize);				//deUint32				arrayLayers;
148 	imageSparseInfo.samples					= VK_SAMPLE_COUNT_1_BIT;								//VkSampleCountFlagBits	samples;
149 	imageSparseInfo.tiling					= VK_IMAGE_TILING_OPTIMAL;								//VkImageTiling			tiling;
150 	imageSparseInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;							//VkImageLayout			initialLayout;
151 	imageSparseInfo.usage					= VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
152 											  VK_IMAGE_USAGE_TRANSFER_DST_BIT;						//VkImageUsageFlags		usage;
153 	imageSparseInfo.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;							//VkSharingMode			sharingMode;
154 	imageSparseInfo.queueFamilyIndexCount	= 0u;													//deUint32				queueFamilyIndexCount;
155 	imageSparseInfo.pQueueFamilyIndices		= DE_NULL;												//const deUint32*		pQueueFamilyIndices;
156 
157 	if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
158 	{
159 		imageSparseInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
160 	}
161 
162 	{
163 		VkImageFormatProperties imageFormatProperties;
164 		instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
165 			imageSparseInfo.format,
166 			imageSparseInfo.imageType,
167 			imageSparseInfo.tiling,
168 			imageSparseInfo.usage,
169 			imageSparseInfo.flags,
170 			&imageFormatProperties);
171 
172 		imageSparseInfo.mipLevels = getImageMaxMipLevels(imageFormatProperties, imageSparseInfo.extent);
173 	}
174 
175 	// Create sparse image
176 	const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageSparseInfo));
177 
178 	// Create sparse image memory bind semaphore
179 	const Unique<VkSemaphore> imageMemoryBindSemaphore(makeSemaphore(deviceInterface, getDevice()));
180 
181 	// Get sparse image general memory requirements
182 	const VkMemoryRequirements imageSparseMemRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
183 
184 	// Check if required image memory size does not exceed device limits
185 	if (imageSparseMemRequirements.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize)
186 		TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
187 
188 	DE_ASSERT((imageSparseMemRequirements.size % imageSparseMemRequirements.alignment) == 0);
189 
190 	{
191 		std::vector<VkSparseMemoryBind>	sparseMemoryBinds;
192 		const deUint32					numSparseBinds	= static_cast<deUint32>(imageSparseMemRequirements.size / imageSparseMemRequirements.alignment);
193 		const deUint32					memoryType		= findMatchingMemoryType(instance, physicalDevice, imageSparseMemRequirements, MemoryRequirement::Any);
194 
195 		if (memoryType == NO_MATCH_FOUND)
196 			return tcu::TestStatus::fail("No matching memory type found");
197 
198 		for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseBinds; ++sparseBindNdx)
199 		{
200 			const VkSparseMemoryBind sparseMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
201 				imageSparseMemRequirements.alignment, memoryType, imageSparseMemRequirements.alignment * sparseBindNdx);
202 
203 			deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(sparseMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
204 
205 			sparseMemoryBinds.push_back(sparseMemoryBind);
206 		}
207 
208 		const VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo = makeSparseImageOpaqueMemoryBindInfo(*imageSparse, numSparseBinds, &sparseMemoryBinds[0]);
209 
210 		const VkBindSparseInfo bindSparseInfo =
211 		{
212 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,			//VkStructureType							sType;
213 			DE_NULL,									//const void*								pNext;
214 			0u,											//deUint32									waitSemaphoreCount;
215 			DE_NULL,									//const VkSemaphore*						pWaitSemaphores;
216 			0u,											//deUint32									bufferBindCount;
217 			DE_NULL,									//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
218 			1u,											//deUint32									imageOpaqueBindCount;
219 			&opaqueBindInfo,							//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
220 			0u,											//deUint32									imageBindCount;
221 			DE_NULL,									//const VkSparseImageMemoryBindInfo*		pImageBinds;
222 			1u,											//deUint32									signalSemaphoreCount;
223 			&imageMemoryBindSemaphore.get()				//const VkSemaphore*						pSignalSemaphores;
224 		};
225 
226 		// Submit sparse bind commands for execution
227 		VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
228 	}
229 
230 	// Create command buffer for compute and transfer oparations
231 	const Unique<VkCommandPool>	  commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
232 	const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, getDevice(), *commandPool));
233 
234 	std::vector<VkBufferImageCopy> bufferImageCopy(imageSparseInfo.mipLevels);
235 
236 	{
237 		deUint32 bufferOffset = 0;
238 		for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; mipmapNdx++)
239 		{
240 			bufferImageCopy[mipmapNdx] = makeBufferImageCopy(mipLevelExtents(imageSparseInfo.extent, mipmapNdx), imageSparseInfo.arrayLayers, mipmapNdx, static_cast<VkDeviceSize>(bufferOffset));
241 			bufferOffset += getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
242 		}
243 	}
244 
245 	// Start recording commands
246 	beginCommandBuffer(deviceInterface, *commandBuffer);
247 
248 	const deUint32					imageSizeInBytes		= getImageSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, imageSparseInfo.mipLevels, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
249 	const VkBufferCreateInfo		inputBufferCreateInfo	= makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
250 	const Unique<VkBuffer>			inputBuffer				(createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
251 	const de::UniquePtr<Allocation>	inputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
252 
253 	std::vector<deUint8> referenceData(imageSizeInBytes);
254 
255 	for (deUint32 valueNdx = 0; valueNdx < imageSizeInBytes; ++valueNdx)
256 	{
257 		referenceData[valueNdx] = static_cast<deUint8>((valueNdx % imageSparseMemRequirements.alignment) + 1u);
258 	}
259 
260 	deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], imageSizeInBytes);
261 
262 	flushMappedMemoryRange(deviceInterface, getDevice(), inputBufferAlloc->getMemory(), inputBufferAlloc->getOffset(), imageSizeInBytes);
263 
264 	{
265 		const VkBufferMemoryBarrier inputBufferBarrier = makeBufferMemoryBarrier
266 		(
267 			VK_ACCESS_HOST_WRITE_BIT,
268 			VK_ACCESS_TRANSFER_READ_BIT,
269 			*inputBuffer,
270 			0u,
271 			imageSizeInBytes
272 		);
273 
274 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
275 	}
276 
277 	{
278 		const VkImageMemoryBarrier imageSparseTransferDstBarrier = makeImageMemoryBarrier
279 		(
280 			0u,
281 			VK_ACCESS_TRANSFER_WRITE_BIT,
282 			VK_IMAGE_LAYOUT_UNDEFINED,
283 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
284 			sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
285 			sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? computeQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
286 			*imageSparse,
287 			makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers)
288 		);
289 
290 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferDstBarrier);
291 	}
292 
293 	deviceInterface.cmdCopyBufferToImage(*commandBuffer, *inputBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]);
294 
295 	{
296 		const VkImageMemoryBarrier imageSparseTransferSrcBarrier = makeImageMemoryBarrier
297 		(
298 			VK_ACCESS_TRANSFER_WRITE_BIT,
299 			VK_ACCESS_TRANSFER_READ_BIT,
300 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
301 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
302 			*imageSparse,
303 			makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers)
304 		);
305 
306 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferSrcBarrier);
307 	}
308 
309 	const VkBufferCreateInfo		outputBufferCreateInfo	= makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
310 	const Unique<VkBuffer>			outputBuffer			(createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
311 	const de::UniquePtr<Allocation>	outputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
312 
313 	deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), &bufferImageCopy[0]);
314 
315 	{
316 		const VkBufferMemoryBarrier outputBufferBarrier = makeBufferMemoryBarrier
317 		(
318 			VK_ACCESS_TRANSFER_WRITE_BIT,
319 			VK_ACCESS_HOST_READ_BIT,
320 			*outputBuffer,
321 			0u,
322 			imageSizeInBytes
323 		);
324 
325 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
326 	}
327 
328 	// End recording commands
329 	endCommandBuffer(deviceInterface, *commandBuffer);
330 
331 	const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
332 
333 	// Submit commands for execution and wait for completion
334 	submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits);
335 
336 	// Retrieve data from buffer to host memory
337 	invalidateMappedMemoryRange(deviceInterface, getDevice(), outputBufferAlloc->getMemory(), outputBufferAlloc->getOffset(), imageSizeInBytes);
338 
339 	const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr());
340 
341 	// Wait for sparse queue to become idle
342 	deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
343 
344 	for (deUint32 mipmapNdx = 0; mipmapNdx < imageSparseInfo.mipLevels; ++mipmapNdx)
345 	{
346 		const deUint32 mipLevelSizeInBytes	= getImageMipLevelSizeInBytes(imageSparseInfo.extent, imageSparseInfo.arrayLayers, m_format, mipmapNdx);
347 		const deUint32 bufferOffset			= static_cast<deUint32>(bufferImageCopy[mipmapNdx].bufferOffset);
348 
349 		if (deMemCmp(outputData + bufferOffset, &referenceData[bufferOffset], mipLevelSizeInBytes) != 0)
350 			return tcu::TestStatus::fail("Failed");
351 	}
352 
353 	return tcu::TestStatus::pass("Passed");
354 }
355 
createInstance(Context & context) const356 TestInstance* ImageSparseBindingCase::createInstance (Context& context) const
357 {
358 	return new ImageSparseBindingInstance(context, m_imageType, m_imageSize, m_format);
359 }
360 
361 } // anonymous ns
362 
createImageSparseBindingTests(tcu::TestContext & testCtx)363 tcu::TestCaseGroup* createImageSparseBindingTests(tcu::TestContext& testCtx)
364 {
365 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_binding", "Buffer Sparse Binding"));
366 
367 	static const deUint32 sizeCountPerImageType = 3u;
368 
369 	struct ImageParameters
370 	{
371 		ImageType	imageType;
372 		tcu::UVec3	imageSizes[sizeCountPerImageType];
373 	};
374 
375 	static const ImageParameters imageParametersArray[] =
376 	{
377 		{ IMAGE_TYPE_1D,		{ tcu::UVec3(512u, 1u,   1u ), tcu::UVec3(1024u, 1u,   1u), tcu::UVec3(11u,  1u,   1u) } },
378 		{ IMAGE_TYPE_1D_ARRAY,  { tcu::UVec3(512u, 1u,   64u), tcu::UVec3(1024u, 1u,   8u), tcu::UVec3(11u,  1u,   3u) } },
379 		{ IMAGE_TYPE_2D,		{ tcu::UVec3(512u, 256u, 1u ), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u,  137u, 1u) } },
380 		{ IMAGE_TYPE_2D_ARRAY,	{ tcu::UVec3(512u, 256u, 6u ), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u,  137u, 3u) } },
381 		{ IMAGE_TYPE_3D,		{ tcu::UVec3(512u, 256u, 6u ), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u,  137u, 3u) } },
382 		{ IMAGE_TYPE_CUBE,		{ tcu::UVec3(256u, 256u, 1u ), tcu::UVec3(128u,  128u, 1u), tcu::UVec3(137u, 137u, 1u) } },
383 		{ IMAGE_TYPE_CUBE_ARRAY,{ tcu::UVec3(256u, 256u, 6u ), tcu::UVec3(128u,  128u, 8u), tcu::UVec3(137u, 137u, 3u) } }
384 	};
385 
386 	static const tcu::TextureFormat formats[] =
387 	{
388 		tcu::TextureFormat(tcu::TextureFormat::R,		tcu::TextureFormat::SIGNED_INT32),
389 		tcu::TextureFormat(tcu::TextureFormat::R,		tcu::TextureFormat::SIGNED_INT16),
390 		tcu::TextureFormat(tcu::TextureFormat::R,		tcu::TextureFormat::SIGNED_INT8),
391 		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT32),
392 		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT16),
393 		tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNSIGNED_INT8)
394 	};
395 
396 	for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray); ++imageTypeNdx)
397 	{
398 		const ImageType					imageType = imageParametersArray[imageTypeNdx].imageType;
399 		de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
400 
401 		for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
402 		{
403 			const tcu::TextureFormat&		format = formats[formatNdx];
404 			de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, getShaderImageFormatQualifier(format).c_str(), ""));
405 
406 			for (deInt32 imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(imageParametersArray[imageTypeNdx].imageSizes); ++imageSizeNdx)
407 			{
408 				const tcu::UVec3 imageSize = imageParametersArray[imageTypeNdx].imageSizes[imageSizeNdx];
409 
410 				std::ostringstream stream;
411 				stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
412 
413 				formatGroup->addChild(new ImageSparseBindingCase(testCtx, stream.str(), "", imageType, imageSize, format));
414 			}
415 			imageTypeGroup->addChild(formatGroup.release());
416 		}
417 		testGroup->addChild(imageTypeGroup.release());
418 	}
419 
420 	return testGroup.release();
421 }
422 
423 } // sparse
424 } // vkt
425