• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 Google 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  vktImageTransfer.cpp
21  * \brief Tests for image transfers
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktTestCase.hpp"
25 
26 #include "vkImageUtil.hpp"
27 #include "vkBarrierUtil.hpp"
28 #include "vkTypeUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkStrUtil.hpp"
31 #include "vkBufferWithMemory.hpp"
32 #include "vkImageWithMemory.hpp"
33 
34 #include "tcuTestLog.hpp"
35 #include "vktTestCase.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuCommandLine.hpp"
38 #include "vktImageTestsUtil.hpp"
39 #include "vkRefUtil.hpp"
40 #include "deRandom.hpp"
41 #include "ycbcr/vktYCbCrUtil.hpp"
42 
43 #include <vector>
44 #include <string>
45 
46 using namespace vk;
47 
48 namespace vkt
49 {
50 using namespace ycbcr;
51 namespace image
52 {
53 namespace
54 {
55 
56 class TransferQueueCase : public vkt::TestCase
57 {
58 public:
59 	struct TestParams
60 	{
61 		VkImageType	imageType;
62 		VkFormat	imageFormat;
63 		VkExtent3D	dimensions;		// .depth will be the number of layers for 2D images and the depth for 3D images.
64 	};
65 
66 							TransferQueueCase				(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~TransferQueueCase(void)67 	virtual					~TransferQueueCase				(void) {}
68 
initPrograms(vk::SourceCollections &) const69 	virtual void			initPrograms					(vk::SourceCollections&) const {}
70 	virtual TestInstance*	createInstance					(Context& context) const;
71 	virtual void			checkSupport					(Context& context) const;
72 private:
73 	TestParams m_params;
74 };
75 
76 class TransferQueueInstance : public vkt::TestInstance
77 {
78 public:
79 								TransferQueueInstance			(Context& context, const TransferQueueCase::TestParams& params);
~TransferQueueInstance(void)80 	virtual						~TransferQueueInstance			(void) {}
81 
82 	virtual tcu::TestStatus		iterate							(void);
83 private:
84 	TransferQueueCase::TestParams m_params;
85 	Move<VkCommandPool>					m_cmdPool;
86 	Move<VkCommandBuffer>				m_cmdBuffer;
87 };
88 
TransferQueueCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)89 TransferQueueCase::TransferQueueCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
90 	: vkt::TestCase	(testCtx, name, description)
91 	, m_params		(params)
92 {
93 }
94 
createInstance(Context & context) const95 TestInstance* TransferQueueCase::createInstance (Context& context) const
96 {
97 	return new TransferQueueInstance (context, m_params);
98 }
99 
checkSupport(Context & context) const100 void TransferQueueCase::checkSupport (Context& context) const
101 {
102 	const auto& vki				= context.getInstanceInterface();
103 	const auto	physicalDevice	= context.getPhysicalDevice();
104 
105 	VkImageFormatProperties	formatProperties;
106 	const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_params.imageFormat, m_params.imageType, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0u, &formatProperties);
107 	if (result != VK_SUCCESS)
108 	{
109 		if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
110 			TCU_THROW(NotSupportedError, "Error: format " + de::toString(m_params.imageFormat) + " does not support the required features");
111 		else
112 			TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned unexpected error");
113 	}
114 }
115 
TransferQueueInstance(Context & context,const TransferQueueCase::TestParams & params)116 TransferQueueInstance::TransferQueueInstance (Context& context, const TransferQueueCase::TestParams& params)
117 	: vkt::TestInstance	(context)
118 	, m_params			(params)
119 {
120 	const auto& vk					= context.getDeviceInterface();
121 	const auto& device				= context.getDevice();
122 	const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
123 
124 	// Create command pool
125 	m_cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
126 
127 	// Create command buffer
128 	m_cmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
129 }
130 
iterate(void)131 tcu::TestStatus TransferQueueInstance::iterate (void)
132 {
133 	// Test every aspect supported by the image format.
134 	const auto tcuFormat			= mapVkFormat(m_params.imageFormat);
135 
136 	Allocator& allocator			= m_context.getDefaultAllocator();
137 	const auto& vk					= m_context.getDeviceInterface();
138 	const auto device				= m_context.getDevice();
139 	const auto queue				= getDeviceQueue(m_context.getDeviceInterface(), device, m_context.getUniversalQueueFamilyIndex(), 0u);
140 
141 	const auto width				= m_params.dimensions.width;
142 	const auto height				= m_params.dimensions.height;
143 	const auto layers				= m_params.imageType == vk::VK_IMAGE_TYPE_3D ? 1u : m_params.dimensions.depth;
144 	const auto depth				= m_params.imageType == vk::VK_IMAGE_TYPE_3D ? m_params.dimensions.depth : 1u;
145 	const uint32_t pixelDataSize	= tcuFormat.getPixelSize() * width * height * layers * depth;
146 
147 	const vk::VkBufferCreateInfo bufferCreateInfo =
148 	{
149 		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
150 		DE_NULL,
151 		0u,																						// flags
152 		static_cast<VkDeviceSize>(pixelDataSize),												// size
153 		vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,			// usage
154 		vk::VK_SHARING_MODE_EXCLUSIVE,															// sharingMode
155 		0u,																						// queueFamilyCount
156 		DE_NULL,																				// pQueueFamilyIndices
157 	};
158 
159 	BufferWithMemory srcBuffer(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible);
160 	BufferWithMemory dstBuffer(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible);
161 
162 	vk::VkExtent3D extent = { m_params.dimensions.width, m_params.dimensions.height, depth };
163 	const vk::VkImageCreateInfo	imageCreateInfo =
164 	{
165 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType		sType;
166 		DE_NULL,								// const void*			pNext;
167 		0,										// VkImageCreateFlags	flags;
168 		m_params.imageType,						// VkImageType			imageType;
169 		m_params.imageFormat,					// VkFormat				format;
170 		extent,									// VkExtent3D			extent;
171 		1u,										// deUint32				mipLevels;
172 		layers,									// deUint32				arraySize;
173 		VK_SAMPLE_COUNT_1_BIT,					// deUint32				samples;
174 		VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling		tiling;
175 		VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
176 			VK_IMAGE_USAGE_TRANSFER_DST_BIT,	// VkImageUsageFlags	usage;
177 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
178 		0u,										// deUint32				queueFamilyIndexCount;
179 		(const deUint32*)DE_NULL,				// const deUint32*		pQueueFamilyIndices;
180 		VK_IMAGE_LAYOUT_UNDEFINED,				// VkImageLayout		initialLayout;
181 	};
182 	Image image(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any);
183 
184 	// Generate data for source buffer and copy it into buffer
185 	std::vector<deUint8>			generatedData	(pixelDataSize);
186 	de::Random						randomGen		(deInt32Hash((deUint32)m_params.imageFormat) ^
187 													 deInt32Hash((deUint32)m_params.imageType) ^
188 													 deInt32Hash((deUint32)m_params.dimensions.width) ^
189 													 deInt32Hash((deUint32)m_params.dimensions.height) ^
190 													 deInt32Hash((deUint32)m_params.dimensions.depth));
191 	{
192 		fillRandomNoNaN(&randomGen, generatedData.data(), (deUint32)generatedData.size(), m_params.imageFormat);
193 		const Allocation& alloc = srcBuffer.getAllocation();
194 		deMemcpy(alloc.getHostPtr(), generatedData.data(), generatedData.size());
195 	}
196 
197 	beginCommandBuffer(vk, *m_cmdBuffer);
198 	const VkImageSubresourceRange			subresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, layers);
199 	const VkImageMemoryBarrier				imageBarrier		= makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, *image, subresourceRange);
200 	vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &imageBarrier);
201 	// Copy buffer to image
202 	{
203 		const bool		isCompressed	= isCompressedFormat(m_params.imageFormat);
204 		const deUint32	blockHeight		= (isCompressed) ? getBlockHeight(m_params.imageFormat) : 1u;
205 		deUint32		imageHeight		= ((height + blockHeight - 1) / blockHeight) * blockHeight;
206 
207 		const vk::VkBufferImageCopy	copyRegion =
208 		{
209 			0u,												// VkDeviceSize				bufferOffset;
210 			0,												// deUint32					bufferRowLength;
211 			imageHeight,									// deUint32					bufferImageHeight;
212 			{
213 				VK_IMAGE_ASPECT_COLOR_BIT,					// VkImageAspectFlags		aspect;
214 				0,											// deUint32					mipLevel;
215 				0u,											// deUint32					baseArrayLayer;
216 				layers,										// deUint32					layerCount;
217 			},												// VkImageSubresourceLayers	imageSubresource;
218 			{ 0, 0, 0 },									// VkOffset3D				imageOffset;
219 			extent											// VkExtent3D				imageExtent;
220 		};
221 
222 		const VkImageMemoryBarrier		postImageBarrier =
223 		{
224 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
225 			DE_NULL,										// const void*				pNext;
226 			VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags			srcAccessMask;
227 			VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags			dstAccessMask;
228 			VK_IMAGE_LAYOUT_GENERAL,						// VkImageLayout			oldLayout;
229 			VK_IMAGE_LAYOUT_GENERAL,						// VkImageLayout			newLayout;
230 			VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
231 			VK_QUEUE_FAMILY_IGNORED,						// deUint32					dstQueueFamilyIndex;
232 			*image,											// VkImage					image;
233 			{												// VkImageSubresourceRange	subresourceRange;
234 				VK_IMAGE_ASPECT_COLOR_BIT,	// VkImageAspectFlags	aspect;
235 				0u,							// deUint32				baseMipLevel;
236 				1,							// deUint32				mipLevels;
237 				0u,							// deUint32				baseArraySlice;
238 				layers,						// deUint32				arraySize;
239 			}
240 		};
241 
242 		vk.cmdCopyBufferToImage(*m_cmdBuffer, *srcBuffer, *image, VK_IMAGE_LAYOUT_GENERAL, 1, &copyRegion);
243 
244 		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
245 
246 		vk.cmdCopyImageToBuffer(*m_cmdBuffer, *image, VK_IMAGE_LAYOUT_GENERAL, *dstBuffer, 1, &copyRegion);
247 	}
248 	endCommandBuffer(vk, *m_cmdBuffer);
249 
250 	submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
251 
252 	{
253 		std::vector<deUint8> resultData(pixelDataSize);
254 		const Allocation& alloc = dstBuffer.getAllocation();
255 		deMemcpy(resultData.data(), alloc.getHostPtr(), resultData.size());
256 
257 		for (uint32_t i = 0; i < pixelDataSize; ++i) {
258 			if (resultData[i] != generatedData[i]) {
259 				return tcu::TestStatus::fail("Transfer queue test");
260 			}
261 		}
262 	}
263 
264 	return tcu::TestStatus::pass("Pass");
265 }
266 
267 } // anonymous namespace
268 
getAspectFlags(tcu::TextureFormat format)269 VkImageAspectFlags getAspectFlags (tcu::TextureFormat format)
270 {
271 	VkImageAspectFlags	aspectFlag = 0;
272 	aspectFlag |= (tcu::hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0);
273 	aspectFlag |= (tcu::hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
274 
275 	if (!aspectFlag)
276 		aspectFlag = VK_IMAGE_ASPECT_COLOR_BIT;
277 
278 	return aspectFlag;
279 }
280 
createTransferQueueImageTests(tcu::TestContext & testCtx)281 tcu::TestCaseGroup* createTransferQueueImageTests (tcu::TestContext& testCtx)
282 {
283 	de::MovePtr<tcu::TestCaseGroup> layoutTestGroup (new tcu::TestCaseGroup(testCtx, "queue_transfer", "Tests for transfering from buffer to image and back"));
284 
285 	struct
286 	{
287 		VkImageType	type;
288 		bool		array;
289 		const char*	name;
290 		const char*	desc;
291 	} imageClass[] =
292 	{
293 		{ VK_IMAGE_TYPE_2D,	false,	"2d",		"2D images"							},
294 		{ VK_IMAGE_TYPE_2D,	true,	"2d_array",	"2D images with multiple layers"	},
295 		{ VK_IMAGE_TYPE_3D,	false,	"3d",		"3D images"							},
296 	};
297 
298 	struct
299 	{
300 		VkExtent3D	extent;
301 		const char*	name;
302 		const char*	desc;
303 	} extents[] =
304 	{
305 		{ {4u,	3u,		1u},							"4x3x1",			"4x3x1 extent"				},
306 		{ {16u, 15u,	1u},							"16x15x1",			"16x15x1 extent"			},
307 		{ {64u, 31u,	1u},							"64x31x1",			"64x31x1 extent"			},
308 		{ {4u,	3u,		2u},							"4x3x2",			"4x3x2extent"				},
309 		{ {16u, 15u,	16u},							"16x15x16",			"16x15x16 extent"			},
310 	};
311 
312 	VkFormat testFormats[] =
313 	{
314 		VK_FORMAT_R4G4_UNORM_PACK8,
315 		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
316 		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
317 		VK_FORMAT_R5G6B5_UNORM_PACK16,
318 		VK_FORMAT_B5G6R5_UNORM_PACK16,
319 		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
320 		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
321 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
322 		VK_FORMAT_R8_UNORM,
323 		VK_FORMAT_R8_SNORM,
324 		VK_FORMAT_R8_USCALED,
325 		VK_FORMAT_R8_SSCALED,
326 		VK_FORMAT_R8_UINT,
327 		VK_FORMAT_R8_SINT,
328 		VK_FORMAT_R8_SRGB,
329 		VK_FORMAT_R8G8_UNORM,
330 		VK_FORMAT_R8G8_SNORM,
331 		VK_FORMAT_R8G8_USCALED,
332 		VK_FORMAT_R8G8_SSCALED,
333 		VK_FORMAT_R8G8_UINT,
334 		VK_FORMAT_R8G8_SINT,
335 		VK_FORMAT_R8G8_SRGB,
336 		VK_FORMAT_R8G8B8_UNORM,
337 		VK_FORMAT_R8G8B8_SNORM,
338 		VK_FORMAT_R8G8B8_USCALED,
339 		VK_FORMAT_R8G8B8_SSCALED,
340 		VK_FORMAT_R8G8B8_UINT,
341 		VK_FORMAT_R8G8B8_SINT,
342 		VK_FORMAT_R8G8B8_SRGB,
343 		VK_FORMAT_B8G8R8_UNORM,
344 		VK_FORMAT_B8G8R8_SNORM,
345 		VK_FORMAT_B8G8R8_USCALED,
346 		VK_FORMAT_B8G8R8_SSCALED,
347 		VK_FORMAT_B8G8R8_UINT,
348 		VK_FORMAT_B8G8R8_SINT,
349 		VK_FORMAT_B8G8R8_SRGB,
350 		VK_FORMAT_R8G8B8A8_UNORM,
351 		VK_FORMAT_R8G8B8A8_SNORM,
352 		VK_FORMAT_R8G8B8A8_USCALED,
353 		VK_FORMAT_R8G8B8A8_SSCALED,
354 		VK_FORMAT_R8G8B8A8_UINT,
355 		VK_FORMAT_R8G8B8A8_SINT,
356 		VK_FORMAT_R8G8B8A8_SRGB,
357 		VK_FORMAT_B8G8R8A8_UNORM,
358 		VK_FORMAT_B8G8R8A8_SNORM,
359 		VK_FORMAT_B8G8R8A8_USCALED,
360 		VK_FORMAT_B8G8R8A8_SSCALED,
361 		VK_FORMAT_B8G8R8A8_UINT,
362 		VK_FORMAT_B8G8R8A8_SINT,
363 		VK_FORMAT_B8G8R8A8_SRGB,
364 		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
365 		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
366 		VK_FORMAT_A8B8G8R8_USCALED_PACK32,
367 		VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
368 		VK_FORMAT_A8B8G8R8_UINT_PACK32,
369 		VK_FORMAT_A8B8G8R8_SINT_PACK32,
370 		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
371 		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
372 		VK_FORMAT_A2R10G10B10_SNORM_PACK32,
373 		VK_FORMAT_A2R10G10B10_USCALED_PACK32,
374 		VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
375 		VK_FORMAT_A2R10G10B10_UINT_PACK32,
376 		VK_FORMAT_A2R10G10B10_SINT_PACK32,
377 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
378 		VK_FORMAT_A2B10G10R10_SNORM_PACK32,
379 		VK_FORMAT_A2B10G10R10_USCALED_PACK32,
380 		VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
381 		VK_FORMAT_A2B10G10R10_UINT_PACK32,
382 		VK_FORMAT_A2B10G10R10_SINT_PACK32,
383 		VK_FORMAT_R16_UNORM,
384 		VK_FORMAT_R16_SNORM,
385 		VK_FORMAT_R16_USCALED,
386 		VK_FORMAT_R16_SSCALED,
387 		VK_FORMAT_R16_UINT,
388 		VK_FORMAT_R16_SINT,
389 		VK_FORMAT_R16_SFLOAT,
390 		VK_FORMAT_R16G16_UNORM,
391 		VK_FORMAT_R16G16_SNORM,
392 		VK_FORMAT_R16G16_USCALED,
393 		VK_FORMAT_R16G16_SSCALED,
394 		VK_FORMAT_R16G16_UINT,
395 		VK_FORMAT_R16G16_SINT,
396 		VK_FORMAT_R16G16_SFLOAT,
397 		VK_FORMAT_R16G16B16_UNORM,
398 		VK_FORMAT_R16G16B16_SNORM,
399 		VK_FORMAT_R16G16B16_USCALED,
400 		VK_FORMAT_R16G16B16_SSCALED,
401 		VK_FORMAT_R16G16B16_UINT,
402 		VK_FORMAT_R16G16B16_SINT,
403 		VK_FORMAT_R16G16B16_SFLOAT,
404 		VK_FORMAT_R16G16B16A16_UNORM,
405 		VK_FORMAT_R16G16B16A16_SNORM,
406 		VK_FORMAT_R16G16B16A16_USCALED,
407 		VK_FORMAT_R16G16B16A16_SSCALED,
408 		VK_FORMAT_R16G16B16A16_UINT,
409 		VK_FORMAT_R16G16B16A16_SINT,
410 		VK_FORMAT_R16G16B16A16_SFLOAT,
411 		VK_FORMAT_R32_UINT,
412 		VK_FORMAT_R32_SINT,
413 		VK_FORMAT_R32_SFLOAT,
414 		VK_FORMAT_R32G32_UINT,
415 		VK_FORMAT_R32G32_SINT,
416 		VK_FORMAT_R32G32_SFLOAT,
417 		VK_FORMAT_R32G32B32_UINT,
418 		VK_FORMAT_R32G32B32_SINT,
419 		VK_FORMAT_R32G32B32_SFLOAT,
420 		VK_FORMAT_R32G32B32A32_UINT,
421 		VK_FORMAT_R32G32B32A32_SINT,
422 		VK_FORMAT_R32G32B32A32_SFLOAT,
423 		VK_FORMAT_R64_UINT,
424 		VK_FORMAT_R64_SINT,
425 		VK_FORMAT_R64_SFLOAT,
426 		VK_FORMAT_R64G64_UINT,
427 		VK_FORMAT_R64G64_SINT,
428 		VK_FORMAT_R64G64_SFLOAT,
429 		VK_FORMAT_R64G64B64_UINT,
430 		VK_FORMAT_R64G64B64_SINT,
431 		VK_FORMAT_R64G64B64_SFLOAT,
432 		VK_FORMAT_R64G64B64A64_UINT,
433 		VK_FORMAT_R64G64B64A64_SINT,
434 		VK_FORMAT_R64G64B64A64_SFLOAT,
435 	};
436 
437 	for (int classIdx = 0; classIdx < DE_LENGTH_OF_ARRAY(imageClass); ++classIdx)
438 	{
439 		const auto& imgClass = imageClass[classIdx];
440 		de::MovePtr<tcu::TestCaseGroup> classGroup (new tcu::TestCaseGroup(testCtx, imgClass.name, imgClass.desc));
441 
442 		for (int extentIdx = 0; extentIdx < DE_LENGTH_OF_ARRAY(extents); ++extentIdx)
443 		{
444 			const auto &extent = extents[extentIdx];
445 			de::MovePtr<tcu::TestCaseGroup> mipGroup (new tcu::TestCaseGroup(testCtx, extent.name, extent.desc));
446 
447 			for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(testFormats); ++formatIdx)
448 			{
449 				static const auto	prefixLen	= std::string("VK_FORMAT_").size();
450 				const auto			format		= testFormats[formatIdx];
451 				const auto			fmtName		= std::string(getFormatName(format));
452 				const auto			name		= de::toLower(fmtName.substr(prefixLen)); // Remove VK_FORMAT_ prefix.
453 				const auto			desc		= "Using format " + fmtName;
454 
455 				TransferQueueCase::TestParams params;
456 				params.imageFormat	= format;
457 				params.imageType	= imgClass.type;
458 				params.dimensions	= {extent.extent.width, extent.extent.height, extent.extent.depth};
459 
460 				mipGroup->addChild(new TransferQueueCase(testCtx, name, desc, params));
461 			}
462 
463 			classGroup->addChild(mipGroup.release());
464 		}
465 
466 		layoutTestGroup->addChild(classGroup.release());
467 	}
468 
469 	return layoutTestGroup.release();
470 }
471 
472 } // namespace image
473 } // namespace vkt
474