1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 The Android Open Source Project
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Image size Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktImageSizeTests.hpp"
26#include "vktTestCaseUtil.hpp"
27#include "vktImageTestsUtil.hpp"
28#include "vktImageTexture.hpp"
29
30#include "vkDefs.hpp"
31#include "vkRef.hpp"
32#include "vkRefUtil.hpp"
33#include "vkPlatform.hpp"
34#include "vkPrograms.hpp"
35#include "vkMemUtil.hpp"
36#include "vkBuilderUtil.hpp"
37#include "vkImageUtil.hpp"
38
39#include "deUniquePtr.hpp"
40#include "deStringUtil.hpp"
41
42#include <string>
43
44using namespace vk;
45
46namespace vkt
47{
48namespace image
49{
50namespace
51{
52
53//! Get a texture based on image type and suggested size.
54Texture getTexture (const ImageType imageType, const tcu::IVec3& size)
55{
56	switch (imageType)
57	{
58		case IMAGE_TYPE_1D:
59		case IMAGE_TYPE_BUFFER:
60			return Texture(imageType, tcu::IVec3(size.x(), 1, 1), 1);
61
62		case IMAGE_TYPE_1D_ARRAY:
63			return Texture(imageType, tcu::IVec3(size.x(), 1, 1), size.y());
64
65		case IMAGE_TYPE_2D:
66			return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), 1);
67
68		case IMAGE_TYPE_2D_ARRAY:
69			return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), size.z());
70
71		case IMAGE_TYPE_CUBE:
72			return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 6);
73
74		case IMAGE_TYPE_CUBE_ARRAY:
75			return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 2*6);
76
77		case IMAGE_TYPE_3D:
78			return Texture(imageType, size, 1);
79
80		default:
81			DE_FATAL("Internal error");
82			return Texture(IMAGE_TYPE_LAST, tcu::IVec3(), 0);
83	}
84}
85
86inline VkImageCreateInfo makeImageCreateInfo (const Texture& texture, const VkFormat format)
87{
88	const VkImageCreateInfo imageParams =
89	{
90		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,												// VkStructureType			sType;
91		DE_NULL,																			// const void*				pNext;
92		(isCube(texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u),	// VkImageCreateFlags		flags;
93		mapImageType(texture.type()),														// VkImageType				imageType;
94		format,																				// VkFormat					format;
95		makeExtent3D(texture.layerSize()),													// VkExtent3D				extent;
96		1u,																					// deUint32					mipLevels;
97		(deUint32)texture.numLayers(),														// deUint32					arrayLayers;
98		VK_SAMPLE_COUNT_1_BIT,																// VkSampleCountFlagBits	samples;
99		VK_IMAGE_TILING_OPTIMAL,															// VkImageTiling			tiling;
100		VK_IMAGE_USAGE_STORAGE_BIT,															// VkImageUsageFlags		usage;
101		VK_SHARING_MODE_EXCLUSIVE,															// VkSharingMode			sharingMode;
102		0u,																					// deUint32					queueFamilyIndexCount;
103		DE_NULL,																			// const deUint32*			pQueueFamilyIndices;
104		VK_IMAGE_LAYOUT_UNDEFINED,															// VkImageLayout			initialLayout;
105	};
106	return imageParams;
107}
108
109//! Interpret the memory as IVec3
110inline tcu::IVec3 readIVec3 (const void* const data)
111{
112	const int* const p = reinterpret_cast<const int* const>(data);
113	return tcu::IVec3(p[0], p[1], p[2]);
114}
115
116tcu::IVec3 getExpectedImageSizeResult (const Texture& texture)
117{
118	// GLSL imageSize() function returns:
119	// z = 0 for cubes
120	// z = N for cube arrays, where N is the number of cubes
121	// y or z = L where L is the number of layers for other array types (e.g. 1D array, 2D array)
122	// z = D where D is the depth of 3d image
123
124	const tcu::IVec3 size = texture.size();
125	const int numCubeFaces = 6;
126
127	switch (texture.type())
128	{
129		case IMAGE_TYPE_1D:
130		case IMAGE_TYPE_BUFFER:
131			return tcu::IVec3(size.x(), 0, 0);
132
133		case IMAGE_TYPE_1D_ARRAY:
134		case IMAGE_TYPE_2D:
135		case IMAGE_TYPE_CUBE:
136			return tcu::IVec3(size.x(), size.y(), 0);
137
138		case IMAGE_TYPE_2D_ARRAY:
139		case IMAGE_TYPE_3D:
140			return size;
141
142		case IMAGE_TYPE_CUBE_ARRAY:
143			return tcu::IVec3(size.x(), size.y(), size.z() / numCubeFaces);
144
145		default:
146			DE_FATAL("Internal error");
147			return tcu::IVec3();
148	}
149}
150
151class SizeTest : public TestCase
152{
153public:
154	enum TestFlags
155	{
156		FLAG_READONLY_IMAGE		= 1u << 0,
157		FLAG_WRITEONLY_IMAGE	= 1u << 1,
158	};
159
160						SizeTest			(tcu::TestContext&	testCtx,
161											 const std::string&	name,
162											 const std::string&	description,
163											 const Texture&		texture,
164											 const VkFormat		format,
165											 const deUint32		flags = 0);
166
167	void				initPrograms		(SourceCollections& programCollection) const;
168	TestInstance*		createInstance		(Context&			context) const;
169
170private:
171	const Texture		m_texture;
172	const VkFormat		m_format;
173	const bool			m_useReadonly;
174	const bool			m_useWriteonly;
175};
176
177SizeTest::SizeTest (tcu::TestContext&		testCtx,
178					const std::string&		name,
179					const std::string&		description,
180					const Texture&			texture,
181					const VkFormat			format,
182					const deUint32			flags)
183	: TestCase			(testCtx, name, description)
184	, m_texture			(texture)
185	, m_format			(format)
186	, m_useReadonly		((flags & FLAG_READONLY_IMAGE) != 0)
187	, m_useWriteonly	((flags & FLAG_WRITEONLY_IMAGE) != 0)
188{
189	// We expect at least one flag to be set.
190	DE_ASSERT(m_useReadonly || m_useWriteonly);
191}
192
193void SizeTest::initPrograms (SourceCollections& programCollection) const
194{
195	const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
196	const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), m_texture.type());
197	const int dimension = m_texture.dimension();
198
199	std::ostringstream accessQualifier;
200	if (m_useReadonly)
201		accessQualifier << " readonly";
202	if (m_useWriteonly)
203		accessQualifier << " writeonly";
204
205	std::ostringstream src;
206	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
207		<< "\n"
208		<< "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
209		<< "layout (binding = 0, " << formatQualifierStr << ")" << accessQualifier.str() << " uniform highp " << imageTypeStr << " u_image;\n"
210		<< "layout (binding = 1) writeonly buffer Output {\n"
211		<< "    ivec3 size;\n"
212		<< "} sb_out;\n"
213		<< "\n"
214		<< "void main (void)\n"
215		<< "{\n"
216		<< (dimension == 1 ?
217			"    sb_out.size = ivec3(imageSize(u_image), 0, 0);\n"
218			: dimension == 2 || m_texture.type() == IMAGE_TYPE_CUBE ?		// cubes return ivec2
219			"    sb_out.size = ivec3(imageSize(u_image), 0);\n"
220			: dimension == 3 ?												// cube arrays return ivec3
221			"    sb_out.size = imageSize(u_image);\n"
222			: "")
223		<< "}\n";
224
225	programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
226}
227
228//! Build a case name, e.g. "readonly_writeonly_32x32"
229std::string getCaseName (const Texture& texture, const deUint32 flags)
230{
231	std::ostringstream str;
232	str << ((flags & SizeTest::FLAG_READONLY_IMAGE) != 0 ? "readonly_" : "")
233		<< ((flags & SizeTest::FLAG_WRITEONLY_IMAGE) != 0 ? "writeonly_" : "");
234
235	const int numComponents = texture.dimension();
236	for (int i = 0; i < numComponents; ++i)
237		str << (i == 0 ? "" : "x") << texture.size()[i];
238
239	return str.str();
240}
241
242//! Base test instance for image and buffer tests
243class SizeTestInstance : public TestInstance
244{
245public:
246									SizeTestInstance			(Context&				context,
247																 const Texture&			texture,
248																 const VkFormat			format);
249
250	tcu::TestStatus                 iterate						(void);
251
252	virtual							~SizeTestInstance			(void) {}
253
254protected:
255	virtual VkDescriptorSetLayout	prepareDescriptors			(void) = 0;
256	virtual VkDescriptorSet         getDescriptorSet			(void) const = 0;
257	virtual void					commandBeforeCompute		(const VkCommandBuffer	cmdBuffer) = 0;
258
259	const Texture					m_texture;
260	const VkFormat					m_format;
261	const VkDeviceSize				m_resultBufferSizeBytes;
262	de::MovePtr<Buffer>				m_resultBuffer;				//!< Shader writes the output here.
263};
264
265SizeTestInstance::SizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
266	: TestInstance				(context)
267	, m_texture					(texture)
268	, m_format					(format)
269	, m_resultBufferSizeBytes	(3 * sizeof(deUint32))	// ivec3 in shader
270{
271	const DeviceInterface&	vk			= m_context.getDeviceInterface();
272	const VkDevice			device		= m_context.getDevice();
273	Allocator&				allocator	= m_context.getDefaultAllocator();
274
275	// Create an SSBO for shader output.
276
277	m_resultBuffer = de::MovePtr<Buffer>(new Buffer(
278		vk, device, allocator,
279		makeBufferCreateInfo(m_resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
280		MemoryRequirement::HostVisible));
281}
282
283tcu::TestStatus SizeTestInstance::iterate (void)
284{
285	const DeviceInterface&	vk					= m_context.getDeviceInterface();
286	const VkDevice			device				= m_context.getDevice();
287	const VkQueue			queue				= m_context.getUniversalQueue();
288	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
289
290	// Create memory barriers.
291
292	const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
293		VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
294		m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
295
296	// Create the pipeline.
297
298	const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
299
300	const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
301	const VkDescriptorSet descriptorSet = getDescriptorSet();
302
303	const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
304	const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
305
306	const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
307	const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
308
309	beginCommandBuffer(vk, *cmdBuffer);
310
311	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
312	vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
313
314	commandBeforeCompute(*cmdBuffer);
315	vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
316	vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &shaderWriteBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
317
318	endCommandBuffer(vk, *cmdBuffer);
319
320	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
321
322	// Compare the result.
323
324	const Allocation& bufferAlloc = m_resultBuffer->getAllocation();
325	invalidateMappedMemoryRange(vk, device, bufferAlloc.getMemory(), bufferAlloc.getOffset(), m_resultBufferSizeBytes);
326
327	const tcu::IVec3 resultSize = readIVec3(bufferAlloc.getHostPtr());
328	const tcu::IVec3 expectedSize = getExpectedImageSizeResult(m_texture);
329
330	if (resultSize != expectedSize)
331		return tcu::TestStatus::fail("Incorrect imageSize(): expected " + de::toString(expectedSize) + " but got " + de::toString(resultSize));
332	else
333		return tcu::TestStatus::pass("Passed");
334}
335
336class ImageSizeTestInstance : public SizeTestInstance
337{
338public:
339									ImageSizeTestInstance		(Context&				context,
340																 const Texture&			texture,
341																 const VkFormat			format);
342
343protected:
344	VkDescriptorSetLayout			prepareDescriptors			(void);
345	void							commandBeforeCompute		(const VkCommandBuffer	cmdBuffer);
346
347	VkDescriptorSet                 getDescriptorSet			(void) const { return *m_descriptorSet; }
348
349	de::MovePtr<Image>				m_image;
350	Move<VkImageView>				m_imageView;
351	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
352	Move<VkDescriptorPool>			m_descriptorPool;
353	Move<VkDescriptorSet>			m_descriptorSet;
354};
355
356ImageSizeTestInstance::ImageSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
357	: SizeTestInstance	(context, texture, format)
358{
359	const DeviceInterface&	vk			= m_context.getDeviceInterface();
360	const VkDevice			device		= m_context.getDevice();
361	Allocator&				allocator	= m_context.getDefaultAllocator();
362
363	// Create an image. Its data be uninitialized, as we're not reading from it.
364
365	m_image = de::MovePtr<Image>(new Image(vk, device, allocator, makeImageCreateInfo(m_texture, m_format), MemoryRequirement::Any));
366
367	const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
368	m_imageView = makeImageView(vk, device, m_image->get(), mapImageViewType(m_texture.type()), m_format, subresourceRange);
369}
370
371VkDescriptorSetLayout ImageSizeTestInstance::prepareDescriptors (void)
372{
373	const DeviceInterface&	vk		= m_context.getDeviceInterface();
374	const VkDevice			device	= m_context.getDevice();
375
376	m_descriptorSetLayout = DescriptorSetLayoutBuilder()
377		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
378		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
379		.build(vk, device);
380
381	m_descriptorPool = DescriptorPoolBuilder()
382		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
383		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
384		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
385
386	m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
387
388	const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL);
389	const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
390
391	DescriptorSetUpdateBuilder()
392		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
393		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
394		.update(vk, device);
395
396	return *m_descriptorSetLayout;
397}
398
399void ImageSizeTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
400{
401	const DeviceInterface& vk = m_context.getDeviceInterface();
402
403	const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
404	const VkImageMemoryBarrier barrierSetImageLayout = makeImageMemoryBarrier(
405		0u, 0u,
406		VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
407		m_image->get(), subresourceRange);
408
409	vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &barrierSetImageLayout);
410}
411
412class BufferSizeTestInstance : public SizeTestInstance
413{
414public:
415									BufferSizeTestInstance		(Context&				context,
416																 const Texture&			texture,
417																 const VkFormat			format);
418
419protected:
420	VkDescriptorSetLayout			prepareDescriptors			(void);
421
422	void							commandBeforeCompute		(const VkCommandBuffer) {}
423	VkDescriptorSet					getDescriptorSet			(void) const { return *m_descriptorSet; }
424
425	de::MovePtr<Buffer>				m_imageBuffer;
426	Move<VkBufferView>				m_bufferView;
427	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
428	Move<VkDescriptorPool>			m_descriptorPool;
429	Move<VkDescriptorSet>			m_descriptorSet;
430};
431
432BufferSizeTestInstance::BufferSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
433	: SizeTestInstance	(context, texture, format)
434{
435	const DeviceInterface&	vk			= m_context.getDeviceInterface();
436	const VkDevice			device		= m_context.getDevice();
437	Allocator&				allocator	= m_context.getDefaultAllocator();
438
439	// Create a texel storage buffer. Its data be uninitialized, as we're not reading from it.
440
441	const VkDeviceSize imageSizeBytes = getImageSizeBytes(m_texture.size(), m_format);
442	m_imageBuffer = de::MovePtr<Buffer>(new Buffer(vk, device, allocator,
443		makeBufferCreateInfo(imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), MemoryRequirement::Any));
444
445	m_bufferView = makeBufferView(vk, device, m_imageBuffer->get(), m_format, 0ull, imageSizeBytes);
446}
447
448VkDescriptorSetLayout BufferSizeTestInstance::prepareDescriptors (void)
449{
450	const DeviceInterface&	vk		= m_context.getDeviceInterface();
451	const VkDevice			device	= m_context.getDevice();
452
453	m_descriptorSetLayout = DescriptorSetLayoutBuilder()
454		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
455		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
456		.build(vk, device);
457
458	m_descriptorPool = DescriptorPoolBuilder()
459		.addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
460		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
461		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
462
463	m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
464
465	const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
466
467	DescriptorSetUpdateBuilder()
468		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
469		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
470		.update(vk, device);
471
472	return *m_descriptorSetLayout;
473}
474
475TestInstance* SizeTest::createInstance (Context& context) const
476{
477	if (m_texture.type() == IMAGE_TYPE_BUFFER)
478		return new BufferSizeTestInstance(context, m_texture, m_format);
479	else
480		return new ImageSizeTestInstance(context, m_texture, m_format);
481}
482
483static const ImageType s_imageTypes[] =
484{
485	IMAGE_TYPE_1D,
486	IMAGE_TYPE_1D_ARRAY,
487	IMAGE_TYPE_2D,
488	IMAGE_TYPE_2D_ARRAY,
489	IMAGE_TYPE_3D,
490	IMAGE_TYPE_CUBE,
491	IMAGE_TYPE_CUBE_ARRAY,
492	IMAGE_TYPE_BUFFER,
493};
494
495//! Base sizes used to generate actual image/buffer sizes in the test.
496static const tcu::IVec3 s_baseImageSizes[] =
497{
498	tcu::IVec3(32, 32, 32),
499	tcu::IVec3(12, 34, 56),
500	tcu::IVec3(1,   1,  1),
501	tcu::IVec3(7,   1,  1),
502};
503
504static const deUint32 s_flags[] =
505{
506	SizeTest::FLAG_READONLY_IMAGE,
507	SizeTest::FLAG_WRITEONLY_IMAGE,
508	SizeTest::FLAG_READONLY_IMAGE | SizeTest::FLAG_WRITEONLY_IMAGE,
509};
510
511} // anonymous ns
512
513tcu::TestCaseGroup* createImageSizeTests (tcu::TestContext& testCtx)
514{
515	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_size", "imageSize() cases"));
516
517	const VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
518
519	for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(s_imageTypes); ++imageTypeNdx)
520	{
521		de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(s_imageTypes[imageTypeNdx]).c_str(), ""));
522
523		for (int flagNdx = 0; flagNdx < DE_LENGTH_OF_ARRAY(s_flags); ++flagNdx)
524		for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(s_baseImageSizes); ++imageSizeNdx)
525		{
526			const Texture texture = getTexture(s_imageTypes[imageTypeNdx], s_baseImageSizes[imageSizeNdx]);
527			imageGroup->addChild(new SizeTest(testCtx, getCaseName(texture, s_flags[flagNdx]), "", texture, format, s_flags[flagNdx]));
528		}
529
530		testGroup->addChild(imageGroup.release());
531	}
532	return testGroup.release();
533}
534
535} // image
536} // vkt
537