1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Imagination Technologies Ltd.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Image View Tests
25 *//*--------------------------------------------------------------------*/
26
27#include "vktPipelineImageViewTests.hpp"
28#include "vktPipelineImageSamplingInstance.hpp"
29#include "vktPipelineImageUtil.hpp"
30#include "vktPipelineVertexUtil.hpp"
31#include "vktTestCase.hpp"
32#include "vkImageUtil.hpp"
33#include "vkPrograms.hpp"
34#include "tcuPlatform.hpp"
35#include "tcuTextureUtil.hpp"
36#include "deStringUtil.hpp"
37#include "deMemory.h"
38
39#include <sstream>
40#include <vector>
41
42namespace vkt
43{
44namespace pipeline
45{
46
47using namespace vk;
48using de::MovePtr;
49
50namespace
51{
52
53
54class ImageViewTest : public vkt::TestCase
55{
56public:
57								ImageViewTest					(tcu::TestContext&				testContext,
58																 const char*					name,
59																 PipelineConstructionType		pipelineConstructionType,
60																 VkImageViewType				imageViewType,
61																 VkFormat						imageFormat,
62																 float							samplerLod,
63																 const VkComponentMapping&		componentMapping,
64																 const VkImageSubresourceRange&	subresourceRange);
65	virtual						~ImageViewTest					(void) {}
66
67	ImageSamplingInstanceParams	getImageSamplingInstanceParams	(VkImageViewType				imageViewType,
68																 VkFormat						imageFormat,
69																 float							samplerLod,
70																 const VkComponentMapping&		componentMapping,
71																 const VkImageSubresourceRange&	subresourceRange) const;
72
73	virtual void				initPrograms					(SourceCollections&				sourceCollections) const;
74	virtual void				checkSupport					(Context&						context) const;
75	virtual TestInstance*		createInstance					(Context&						context) const;
76	static std::string			getGlslSamplerType				(const tcu::TextureFormat&		format,
77																 VkImageViewType				type);
78	static tcu::UVec2			getRenderSize					(VkImageViewType				viewType);
79	static tcu::IVec3			getImageSize					(VkImageViewType				viewType);
80	static int					getArraySize					(VkImageViewType				viewType);
81	static int					getNumLevels					(VkImageViewType				viewType);
82	static tcu::Vec4			swizzle							(tcu::Vec4						inputData,
83																 VkComponentMapping				componentMapping);
84private:
85	PipelineConstructionType	m_pipelineConstructionType;
86	VkImageViewType				m_imageViewType;
87	VkFormat					m_imageFormat;
88	float						m_samplerLod;
89	VkComponentMapping			m_componentMapping;
90	VkImageSubresourceRange		m_subresourceRange;
91};
92
93ImageViewTest::ImageViewTest (tcu::TestContext&					testContext,
94							  const char*						name,
95							  PipelineConstructionType			pipelineConstructionType,
96							  VkImageViewType					imageViewType,
97							  VkFormat							imageFormat,
98							  float								samplerLod,
99							  const VkComponentMapping&			componentMapping,
100							  const VkImageSubresourceRange&	subresourceRange)
101
102	: vkt::TestCase					(testContext, name)
103	, m_pipelineConstructionType	(pipelineConstructionType)
104	, m_imageViewType				(imageViewType)
105	, m_imageFormat					(imageFormat)
106	, m_samplerLod					(samplerLod)
107	, m_componentMapping			(componentMapping)
108	, m_subresourceRange			(subresourceRange)
109{
110}
111
112ImageSamplingInstanceParams ImageViewTest::getImageSamplingInstanceParams (VkImageViewType					imageViewType,
113																		   VkFormat							imageFormat,
114																		   float							samplerLod,
115																		   const VkComponentMapping&		componentMapping,
116																		   const VkImageSubresourceRange&	subresourceRange) const
117{
118	const tcu::UVec2				renderSize		= getRenderSize(imageViewType);
119	const tcu::IVec3				imageSize		= getImageSize(imageViewType);
120	const int						arraySize		= getArraySize(imageViewType);
121	const std::vector<Vertex4Tex4>	vertices		= createTestQuadMosaic(imageViewType);
122
123	const VkSamplerCreateInfo		samplerParams	=
124	{
125		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,										// VkStructureType			sType;
126		DE_NULL,																	// const void*				pNext;
127		0u,																			// VkSamplerCreateFlags		flags;
128		VK_FILTER_NEAREST,															// VkFilter					magFilter;
129		VK_FILTER_NEAREST,															// VkFilter					minFilter;
130		VK_SAMPLER_MIPMAP_MODE_NEAREST,												// VkSamplerMipmapMode		mipmapMode;
131		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,										// VkSamplerAddressMode		addressModeU;
132		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,										// VkSamplerAddressMode		addressModeV;
133		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,										// VkSamplerAddressMode		addressModeW;
134		0.0f,																		// float					mipLodBias;
135		VK_FALSE,																	// VkBool32					anisotropyEnable;
136		1.0f,																		// float					maxAnisotropy;
137		false,																		// VkBool32					compareEnable;
138		VK_COMPARE_OP_NEVER,														// VkCompareOp				compareOp;
139		0.0f,																		// float					minLod;
140		(float)(subresourceRange.levelCount - 1),									// float					maxLod;
141		getFormatBorderColor(BORDER_COLOR_TRANSPARENT_BLACK, imageFormat, false),	// VkBorderColor			borderColor;
142		false																		// VkBool32					unnormalizedCoordinates;
143	};
144
145	return ImageSamplingInstanceParams(m_pipelineConstructionType, renderSize, imageViewType, imageFormat, imageSize, arraySize, componentMapping, subresourceRange, samplerParams, samplerLod, vertices);
146}
147
148void ImageViewTest::checkSupport (Context& context) const
149{
150	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
151
152#ifndef CTS_USES_VULKANSC
153	if (m_imageFormat == VK_FORMAT_A8_UNORM_KHR || m_imageFormat == VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR)
154		context.requireDeviceFunctionality("VK_KHR_maintenance5");
155#endif // CTS_USES_VULKANSC
156
157	checkSupportImageSamplingInstance(context, getImageSamplingInstanceParams(m_imageViewType, m_imageFormat, m_samplerLod, m_componentMapping, m_subresourceRange));
158}
159
160tcu::Vec4 ImageViewTest::swizzle (tcu::Vec4 inputData, VkComponentMapping componentMapping)
161{
162	// array map with enum VkComponentSwizzle
163	const float channelValues[] =
164	{
165		-1.0f,
166		0.0f,
167		1.0f,
168		inputData.x(),
169		inputData.y(),
170		inputData.z(),
171		inputData.w(),
172		-1.0f
173	};
174
175	return tcu::Vec4(channelValues[componentMapping.r],
176					 channelValues[componentMapping.g],
177					 channelValues[componentMapping.b],
178					 channelValues[componentMapping.a]);
179}
180
181void ImageViewTest::initPrograms (SourceCollections& sourceCollections) const
182{
183	std::ostringstream				vertexSrc;
184	std::ostringstream				fragmentSrc;
185	const char*						texCoordSwizzle	= DE_NULL;
186	const tcu::TextureFormat		format			= (isCompressedFormat(m_imageFormat)) ? tcu::getUncompressedFormat(mapVkCompressedFormat(m_imageFormat))
187																						  : mapVkFormat(m_imageFormat);
188
189	tcu::Vec4						lookupScale;
190	tcu::Vec4						lookupBias;
191
192	getLookupScaleBias(m_imageFormat, lookupScale, lookupBias);
193
194	tcu::Vec4						swizzledScale	= swizzle(lookupScale, m_componentMapping);
195	tcu::Vec4						swizzledBias	= swizzle(lookupBias, m_componentMapping);
196
197	switch (m_imageViewType)
198	{
199		case VK_IMAGE_VIEW_TYPE_1D:
200			texCoordSwizzle = "x";
201			break;
202		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
203		case VK_IMAGE_VIEW_TYPE_2D:
204			texCoordSwizzle = "xy";
205			break;
206		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
207		case VK_IMAGE_VIEW_TYPE_3D:
208		case VK_IMAGE_VIEW_TYPE_CUBE:
209			texCoordSwizzle = "xyz";
210			break;
211		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
212			texCoordSwizzle = "xyzw";
213			break;
214		default:
215			DE_ASSERT(false);
216			break;
217	}
218
219	vertexSrc << "#version 440\n"
220			  << "layout(location = 0) in vec4 position;\n"
221			  << "layout(location = 1) in vec4 texCoords;\n"
222			  << "layout(location = 0) out highp vec4 vtxTexCoords;\n"
223			  << "out gl_PerVertex {\n"
224			  << "	vec4 gl_Position;\n"
225			  << "};\n"
226			  << "void main (void)\n"
227			  << "{\n"
228			  << "	gl_Position = position;\n"
229			  << "	vtxTexCoords = texCoords;\n"
230			  << "}\n";
231
232	fragmentSrc << "#version 440\n"
233				<< "layout(set = 0, binding = 0) uniform highp " << getGlslSamplerType(format, m_imageViewType) << " texSampler;\n"
234				<< "layout(location = 0) in highp vec4 vtxTexCoords;\n"
235				<< "layout(location = 0) out highp vec4 fragColor;\n"
236				<< "void main (void)\n"
237				<< "{\n"
238				<< "	fragColor = ";
239
240	if (m_samplerLod > 0.0f)
241		fragmentSrc << "textureLod(texSampler, vtxTexCoords." << texCoordSwizzle << ", " << std::fixed <<  m_samplerLod << ")";
242	else
243		fragmentSrc << "texture(texSampler, vtxTexCoords." << texCoordSwizzle << ")" << std::fixed;
244
245	fragmentSrc << " * vec4" << std::scientific << swizzledScale << " + vec4" << swizzledBias << ";\n"
246				<< "}\n";
247
248	sourceCollections.glslSources.add("tex_vert") << glu::VertexSource(vertexSrc.str());
249	sourceCollections.glslSources.add("tex_frag") << glu::FragmentSource(fragmentSrc.str());
250}
251
252TestInstance* ImageViewTest::createInstance (Context& context) const
253{
254	return new ImageSamplingInstance(context, getImageSamplingInstanceParams(m_imageViewType, m_imageFormat, m_samplerLod, m_componentMapping, m_subresourceRange));
255}
256
257std::string ImageViewTest::getGlslSamplerType (const tcu::TextureFormat& format, VkImageViewType type)
258{
259	std::ostringstream samplerType;
260
261	if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
262		samplerType << "u";
263	else if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
264		samplerType << "i";
265
266	switch (type)
267	{
268		case VK_IMAGE_VIEW_TYPE_1D:
269			samplerType << "sampler1D";
270			break;
271
272		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
273			samplerType << "sampler1DArray";
274			break;
275
276		case VK_IMAGE_VIEW_TYPE_2D:
277			samplerType << "sampler2D";
278			break;
279
280		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
281			samplerType << "sampler2DArray";
282			break;
283
284		case VK_IMAGE_VIEW_TYPE_3D:
285			samplerType << "sampler3D";
286			break;
287
288		case VK_IMAGE_VIEW_TYPE_CUBE:
289			samplerType << "samplerCube";
290			break;
291
292		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
293			samplerType << "samplerCubeArray";
294			break;
295
296		default:
297			DE_FATAL("Unknown image view type");
298			break;
299	}
300
301	return samplerType.str();
302}
303
304tcu::UVec2 ImageViewTest::getRenderSize (VkImageViewType viewType)
305{
306	if (viewType == VK_IMAGE_VIEW_TYPE_1D || viewType == VK_IMAGE_VIEW_TYPE_2D)
307		return tcu::UVec2(16u, 16u);
308	else
309		return tcu::UVec2(16u * 3u, 16u * 2u);
310}
311
312tcu::IVec3 ImageViewTest::getImageSize (VkImageViewType viewType)
313{
314	switch (viewType)
315	{
316		case VK_IMAGE_VIEW_TYPE_1D:
317		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
318			return tcu::IVec3(16, 1, 1);
319
320		case VK_IMAGE_VIEW_TYPE_3D:
321			return tcu::IVec3(16);
322
323		default:
324			break;
325	}
326
327	return tcu::IVec3(16, 16, 1);
328}
329
330int ImageViewTest::getArraySize (VkImageViewType viewType)
331{
332	switch (viewType)
333	{
334		case VK_IMAGE_VIEW_TYPE_3D:
335			return 1;
336
337		case VK_IMAGE_VIEW_TYPE_CUBE:
338		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
339			return 18;
340
341		default:
342			break;
343	}
344
345	return 6;
346}
347
348int ImageViewTest::getNumLevels (VkImageViewType viewType)
349{
350	const tcu::IVec3 imageSize = getImageSize(viewType);
351
352	return deLog2Floor32(deMax32(imageSize.x(), deMax32(imageSize.y(), imageSize.z()))) + 1;
353}
354
355static std::string getFormatCaseName (const VkFormat format)
356{
357	const std::string fullName = getFormatName(format);
358
359	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
360
361	return de::toLower(fullName.substr(10));
362}
363
364static de::MovePtr<tcu::TestCaseGroup> createSubresourceRangeTests(tcu::TestContext& testCtx, PipelineConstructionType	pipelineConstructionType, VkImageViewType viewType, VkFormat imageFormat)
365{
366	struct TestCaseConfig
367	{
368		const char*				name;
369		float					samplerLod;
370		VkImageSubresourceRange	subresourceRange;
371	};
372
373	const deUint32				numLevels				= ImageViewTest::getNumLevels(viewType);
374	const deUint32				arraySize				= ImageViewTest::getArraySize(viewType);
375	const VkImageAspectFlags	imageAspectFlags		= VK_IMAGE_ASPECT_COLOR_BIT;
376	const VkComponentMapping	componentMapping		= { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
377
378	de::MovePtr<tcu::TestCaseGroup> rangeTests (new tcu::TestCaseGroup(testCtx, "subresource_range"));
379
380#define ADD_SUBRESOURCE_RANGE_TESTS(TEST_CASES)															\
381	do {																								\
382		for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(TEST_CASES); configNdx++)				\
383		{																								\
384			const TestCaseConfig	config	= (TEST_CASES)[configNdx];									\
385			rangeTests->addChild(new ImageViewTest(testCtx, config.name,			\
386												   pipelineConstructionType,viewType, imageFormat,		\
387												   config.samplerLod, componentMapping,					\
388												   config.subresourceRange));							\
389		}																								\
390	} while (deGetFalse())
391
392	if (viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY || viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
393	{
394		const TestCaseConfig mipLevelRangeCases[] =
395		{
396			//	name					samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
397			{ "lod_base_mip_level",		0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 0u, arraySize } },
398			{ "lod_mip_levels",			4.0f,		{ imageAspectFlags, 0u, 3u, 0u, arraySize } },
399		};
400
401		const TestCaseConfig arrayRangeCases[] =
402		{
403			//	name					samplerLod		subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
404			{ "base_array_layer",		0.0f,			{ imageAspectFlags, 0u, numLevels, 1u, arraySize - 1u } },
405			{ "array_size",				0.0f,			{ imageAspectFlags, 0u, numLevels, 0u, 4u } },
406			{ "array_base_and_size",	0.0f,			{ imageAspectFlags, 0u, numLevels, 2u, 3u } },
407		};
408
409		const TestCaseConfig mipLevelAndArrayRangeCases[] =
410		{
411			//	name										samplerLod		subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
412			{ "lod_base_mip_level_base_array_layer",		0.0f,			{ imageAspectFlags, 2u, numLevels - 2u, 1u, 5u } },
413			{ "lod_mip_levels_base_array_layer",			4.0f,			{ imageAspectFlags, 0u, 3u, 1u, 5u } },
414
415			{ "lod_base_mip_level_array_size",				0.0f,			{ imageAspectFlags, 2u, numLevels - 2u, 0u, 4u } },
416			{ "lod_mip_levels_array_size",					4.0f,			{ imageAspectFlags, 0u, 3u, 0u, 4u } },
417
418			{ "lod_base_mip_level_array_base_and_size",		0.0f,			{ imageAspectFlags, 2u, numLevels - 2u, 2u, 3u } },
419			{ "lod_mip_levels_array_base_and_size",			4.0f,			{ imageAspectFlags, 0u, 3u, 2u, 3u } },
420		};
421
422		const TestCaseConfig mipLevelAndArrayRemainingRangeCases[] =
423		{
424			//	name																samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
425			{ "lod_base_mip_level_remaining_levels",								0.0f,		{ imageAspectFlags,	1u,	VK_REMAINING_MIP_LEVELS,	0u,	arraySize					} },
426			{ "base_array_layer_remaining_layers",									0.0f,		{ imageAspectFlags,	0u,	numLevels,					1u,	VK_REMAINING_ARRAY_LAYERS	} },
427			{ "lod_base_mip_level_base_array_layer_remaining_levels_and_layers",	0.0f,		{ imageAspectFlags,	2u,	VK_REMAINING_MIP_LEVELS,	2u,	VK_REMAINING_ARRAY_LAYERS	} },
428		};
429
430		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelRangeCases);
431		ADD_SUBRESOURCE_RANGE_TESTS(arrayRangeCases);
432		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRangeCases);
433		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRemainingRangeCases);
434	}
435	else if (viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
436	{
437		const TestCaseConfig mipLevelRangeCases[] =
438		{
439			//	name					samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
440			{ "lod_base_mip_level",		0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 0u, arraySize } },
441			{ "lod_mip_levels",			4.0f,		{ imageAspectFlags, 0u, 3u, 0u, arraySize } },
442		};
443
444		const TestCaseConfig arrayRangeCases[] =
445		{
446			//	name					samplerLod		subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
447			{ "base_array_layer",		0.0f,			{ imageAspectFlags, 0u, numLevels, 6u, arraySize - 6u } },
448			{ "array_size",				0.0f,			{ imageAspectFlags, 0u, numLevels, 0u, 6u } },
449			{ "array_base_and_size",	0.0f,			{ imageAspectFlags, 0u, numLevels, 12u, 6u } },
450		};
451
452		const TestCaseConfig mipLevelAndArrayRangeCases[] =
453		{
454			//	name										samplerLod		subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
455			{ "lod_base_mip_level_base_array_layer",		0.0f,			{ imageAspectFlags, 2u, numLevels - 2u, 6u, arraySize - 6u } },
456			{ "lod_mip_levels_base_array_layer",			4.0f,			{ imageAspectFlags, 0u, 3u, 6u, arraySize - 6u } },
457
458			{ "lod_base_mip_level_array_size",				0.0f,			{ imageAspectFlags, 2u, numLevels - 2u, 0u, 6u } },
459			{ "lod_mip_levels_array_size",					4.0f,			{ imageAspectFlags, 0u, 3u, 0u, 6u } },
460
461			{ "lod_base_mip_level_array_base_and_size",		0.0f,			{ imageAspectFlags, 2u, numLevels - 2u, 12u, 6u } },
462			{ "lod_mip_levels_array_base_and_size",			4.0f,			{ imageAspectFlags, 0u, 3u, 12u, 6u } },
463		};
464
465		const TestCaseConfig mipLevelAndArrayRemainingRangeCases[] =
466		{
467			//	name																samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
468			{ "lod_base_mip_level_remaining_levels",								0.0f,		{ imageAspectFlags,	1u,	VK_REMAINING_MIP_LEVELS,	0u,		arraySize					} },
469			{ "base_array_layer_remaining_layers",									0.0f,		{ imageAspectFlags,	0u,	numLevels,					6u,		VK_REMAINING_ARRAY_LAYERS	} },
470			{ "lod_base_mip_level_base_array_layer_remaining_levels_and_layers",	0.0f,		{ imageAspectFlags,	2u,	VK_REMAINING_MIP_LEVELS,	12u,	VK_REMAINING_ARRAY_LAYERS	} },
471		};
472
473		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelRangeCases);
474		ADD_SUBRESOURCE_RANGE_TESTS(arrayRangeCases);
475		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRangeCases);
476		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRemainingRangeCases);
477	}
478	else if (viewType == VK_IMAGE_VIEW_TYPE_1D || viewType == VK_IMAGE_VIEW_TYPE_2D)
479	{
480		const TestCaseConfig mipLevelRangeCases[] =
481		{
482			//	name					samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
483			{ "lod_base_mip_level",		0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 0u, 1u } },
484			{ "lod_mip_levels",			4.0f,		{ imageAspectFlags, 0u, 3u, 0u, 1u } },
485		};
486
487		const TestCaseConfig arrayRangeCases[] =
488		{
489			//	name					samplerLod		subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
490			{ "array_layer_second",		0.0f,			{ imageAspectFlags, 0u, numLevels, 1u, 1u } },
491			{ "array_layer_last",		0.0f,			{ imageAspectFlags, 0u, numLevels, arraySize - 1u, 1u } },
492		};
493
494		const TestCaseConfig mipLevelAndArrayRangeCases[] =
495		{
496			//	name									samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
497			{ "lod_base_mip_level_array_layer_second",	0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 1u, 1u } },
498			{ "lod_mip_levels_array_layer_second",		4.0f,		{ imageAspectFlags, 0u, 3u, arraySize - 1u, 1u } },
499
500			{ "lod_base_mip_level_array_layer_last",	0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 5u, 1u } },
501			{ "lod_mip_levels_array_layer_last",		4.0f,		{ imageAspectFlags, 0u, 3u, arraySize - 1u, 1u } },
502		};
503
504		const TestCaseConfig mipLevelAndArrayRemainingRangeCases[] =
505		{
506			//	name																samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
507			{ "lod_base_mip_level_remaining_levels",								0.0f,		{ imageAspectFlags,	1u,	VK_REMAINING_MIP_LEVELS,	0u,				1u							} },
508			{ "array_layer_last_remaining_layers",									0.0f,		{ imageAspectFlags,	0u,	numLevels,					arraySize - 1u,	VK_REMAINING_ARRAY_LAYERS	} },
509			{ "lod_base_mip_level_array_layer_last_remaining_levels_and_layers",	0.0f,		{ imageAspectFlags,	2u,	VK_REMAINING_MIP_LEVELS,	arraySize - 1u,	VK_REMAINING_ARRAY_LAYERS	} },
510		};
511
512		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelRangeCases);
513		ADD_SUBRESOURCE_RANGE_TESTS(arrayRangeCases);
514		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRangeCases);
515		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRemainingRangeCases);
516	}
517	else if (viewType == VK_IMAGE_VIEW_TYPE_CUBE)
518	{
519		const TestCaseConfig mipLevelRangeCases[] =
520		{
521			//	name					samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
522			{ "lod_base_mip_level",		0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 0u, 6u } },
523			{ "lod_mip_levels",			4.0f,		{ imageAspectFlags, 0u, 3u, 0u, 6u } },
524		};
525
526		const TestCaseConfig arrayRangeCases[] =
527		{
528			//	name					samplerLod		subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
529			{ "array_layer_second",		0.0f,			{ imageAspectFlags, 0u, numLevels, 6u, 6u } },
530			{ "array_layer_last",		0.0f,			{ imageAspectFlags, 0u, numLevels, arraySize - 6u, 6u } },
531		};
532
533		const TestCaseConfig mipLevelAndArrayRangeCases[] =
534		{
535			//	name									samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
536			{ "lod_base_mip_level_array_layer_second",	0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 6u, 6u } },
537			{ "lod_mip_levels_array_layer_second",		4.0f,		{ imageAspectFlags, 0u, 3u, 6u, 6u } },
538
539			{ "lod_base_mip_level_array_layer_last",	0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, arraySize - 6u, 6u } },
540			{ "lod_mip_levels_array_layer_last",		4.0f,		{ imageAspectFlags, 0u, 3u, arraySize - 6u, 6u } },
541		};
542
543		const TestCaseConfig mipLevelAndArrayRemainingRangeCases[] =
544		{
545			//	name																samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
546			{ "lod_base_mip_level_remaining_levels",								0.0f,		{ imageAspectFlags,	1u,	VK_REMAINING_MIP_LEVELS,	0u,				6u							} },
547			{ "array_layer_last_remaining_layers",									0.0f,		{ imageAspectFlags,	0u,	numLevels,					arraySize - 6u,	VK_REMAINING_ARRAY_LAYERS	} },
548			{ "lod_base_mip_level_array_layer_last_remaining_levels_and_layers",	0.0f,		{ imageAspectFlags,	2u,	VK_REMAINING_MIP_LEVELS,	arraySize - 6u,	VK_REMAINING_ARRAY_LAYERS	} },
549		};
550
551		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelRangeCases);
552		ADD_SUBRESOURCE_RANGE_TESTS(arrayRangeCases);
553		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRangeCases);
554		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRemainingRangeCases);
555	}
556	else if (viewType == VK_IMAGE_VIEW_TYPE_3D)
557	{
558		const TestCaseConfig mipLevelRangeCases[] =
559		{
560			//	name					samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
561			{ "lod_base_mip_level",		0.0f,		{ imageAspectFlags, 2u, numLevels - 2u, 0u, arraySize } },
562			{ "lod_mip_levels",			4.0f,		{ imageAspectFlags, 0u, 3u, 0u, arraySize } },
563		};
564
565		const TestCaseConfig mipLevelAndArrayRemainingRangeCases[] =
566		{
567			//	name																samplerLod	subresourceRange (aspectMask, baseMipLevel, mipLevels, baseArrayLayer, arraySize)
568			{ "lod_base_mip_level_remaining_levels",								0.0f,		{ imageAspectFlags,	1u,	VK_REMAINING_MIP_LEVELS,	0u,	arraySize					} },
569			{ "single_array_layer_remaining_layers",								0.0f,		{ imageAspectFlags,	0u,	numLevels,					0u,	VK_REMAINING_ARRAY_LAYERS	} },
570			{ "lod_base_mip_level_single_array_layer_remaining_levels_and_layers",	0.0f,		{ imageAspectFlags,	2u,	VK_REMAINING_MIP_LEVELS,	0u,	VK_REMAINING_ARRAY_LAYERS	} },
571		};
572
573		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelRangeCases);
574		ADD_SUBRESOURCE_RANGE_TESTS(mipLevelAndArrayRemainingRangeCases);
575	}
576
577#undef ADD_SUBRESOURCE_RANGE_TESTS
578
579	return rangeTests;
580}
581
582static std::vector<VkComponentMapping> getComponentMappingPermutations (const VkComponentMapping& componentMapping)
583{
584	std::vector<VkComponentMapping> mappings;
585
586	const VkComponentSwizzle channelSwizzles[4] = { componentMapping.r, componentMapping.g, componentMapping.b, componentMapping.a };
587
588	// Rearranges the channels by shifting their positions.
589	for (int firstChannelNdx = 0; firstChannelNdx < 4; firstChannelNdx++)
590	{
591		VkComponentSwizzle currentChannel[4];
592
593		for (int channelNdx = 0; channelNdx < 4; channelNdx++)
594			currentChannel[channelNdx] = channelSwizzles[(firstChannelNdx + channelNdx) % 4];
595
596		const VkComponentMapping mappingPermutation  =
597		{
598			currentChannel[0],
599			currentChannel[1],
600			currentChannel[2],
601			currentChannel[3]
602		};
603
604		mappings.push_back(mappingPermutation);
605	}
606
607	return mappings;
608}
609
610static std::string getComponentSwizzleCaseName (VkComponentSwizzle componentSwizzle)
611{
612	const std::string fullName = getComponentSwizzleName(componentSwizzle);
613
614	DE_ASSERT(de::beginsWith(fullName, "VK_COMPONENT_SWIZZLE_"));
615
616	return de::toLower(fullName.substr(21));
617}
618
619static std::string getComponentMappingCaseName (const VkComponentMapping& componentMapping)
620{
621	std::ostringstream name;
622
623	name << getComponentSwizzleCaseName(componentMapping.r) << "_"
624		 << getComponentSwizzleCaseName(componentMapping.g) << "_"
625		 << getComponentSwizzleCaseName(componentMapping.b) << "_"
626		 << getComponentSwizzleCaseName(componentMapping.a);
627
628	return name.str();
629}
630
631static de::MovePtr<tcu::TestCaseGroup> createComponentSwizzleTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType, VkImageViewType viewType, VkFormat imageFormat)
632{
633	deUint32 arraySize = 0;
634
635	switch (viewType)
636	{
637		case VK_IMAGE_VIEW_TYPE_1D:
638		case VK_IMAGE_VIEW_TYPE_2D:
639		case VK_IMAGE_VIEW_TYPE_3D:
640			arraySize = 1;
641			break;
642
643		case VK_IMAGE_VIEW_TYPE_CUBE:
644			arraySize = 6;
645			break;
646
647		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
648		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
649		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
650			arraySize = ImageViewTest::getArraySize(viewType);
651			break;
652
653		default:
654			break;
655	}
656
657	const VkImageSubresourceRange subresourceRange =
658	{
659		VK_IMAGE_ASPECT_COLOR_BIT,							// VkImageAspectFlags	aspectMask;
660		0u,													// deUint32				baseMipLevel;
661		(deUint32)ImageViewTest::getNumLevels(viewType),	// deUint32				mipLevels;
662		0u,													// deUint32				baseArrayLayer;
663		arraySize,											// deUint32				arraySize;
664	};
665
666	const VkComponentMapping				baseMapping			= { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
667	const std::vector<VkComponentMapping>	componentMappings	= getComponentMappingPermutations(baseMapping);
668	de::MovePtr<tcu::TestCaseGroup>			swizzleTests		(new tcu::TestCaseGroup(testCtx, "component_swizzle"));
669
670	for (size_t mappingNdx = 0; mappingNdx < componentMappings.size(); mappingNdx++)
671	{
672		swizzleTests->addChild(new ImageViewTest(testCtx,
673												 getComponentMappingCaseName(componentMappings[mappingNdx]).c_str(),
674												 pipelineConstructionType,
675												 viewType,
676												 imageFormat,
677												 0.0f,
678												 componentMappings[mappingNdx],
679												 subresourceRange));
680	}
681
682	return swizzleTests;
683}
684
685} // anonymous
686
687tcu::TestCaseGroup* createImageViewTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
688{
689	const struct
690	{
691		VkImageViewType		type;
692		const char*			name;
693	}
694	imageViewTypes[] =
695	{
696		{ VK_IMAGE_VIEW_TYPE_1D,			"1d" },
697		{ VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array" },
698		{ VK_IMAGE_VIEW_TYPE_2D,			"2d" },
699		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array" },
700		{ VK_IMAGE_VIEW_TYPE_3D,			"3d" },
701		{ VK_IMAGE_VIEW_TYPE_CUBE,			"cube" },
702		{ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array" }
703	};
704
705	const VkFormat formats[] =
706	{
707		VK_FORMAT_R4G4_UNORM_PACK8,
708		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
709		VK_FORMAT_R5G6B5_UNORM_PACK16,
710		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
711#ifndef CTS_USES_VULKANSC
712		VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR,
713#endif // CTS_USES_VULKANSC
714		VK_FORMAT_R8_UNORM,
715		VK_FORMAT_R8_SNORM,
716		VK_FORMAT_R8_USCALED,
717		VK_FORMAT_R8_SSCALED,
718		VK_FORMAT_R8_UINT,
719		VK_FORMAT_R8_SINT,
720		VK_FORMAT_R8_SRGB,
721#ifndef CTS_USES_VULKANSC
722		VK_FORMAT_A8_UNORM_KHR,
723#endif // CTS_USES_VULKANSC
724		VK_FORMAT_R8G8_UNORM,
725		VK_FORMAT_R8G8_SNORM,
726		VK_FORMAT_R8G8_USCALED,
727		VK_FORMAT_R8G8_SSCALED,
728		VK_FORMAT_R8G8_UINT,
729		VK_FORMAT_R8G8_SINT,
730		VK_FORMAT_R8G8_SRGB,
731		VK_FORMAT_R8G8B8_UNORM,
732		VK_FORMAT_R8G8B8_SNORM,
733		VK_FORMAT_R8G8B8_USCALED,
734		VK_FORMAT_R8G8B8_SSCALED,
735		VK_FORMAT_R8G8B8_UINT,
736		VK_FORMAT_R8G8B8_SINT,
737		VK_FORMAT_R8G8B8_SRGB,
738		VK_FORMAT_B8G8R8_UNORM,
739		VK_FORMAT_B8G8R8_SNORM,
740		VK_FORMAT_B8G8R8_USCALED,
741		VK_FORMAT_B8G8R8_SSCALED,
742		VK_FORMAT_B8G8R8_UINT,
743		VK_FORMAT_B8G8R8_SINT,
744		VK_FORMAT_B8G8R8_SRGB,
745		VK_FORMAT_R8G8B8A8_UNORM,
746		VK_FORMAT_R8G8B8A8_SNORM,
747		VK_FORMAT_R8G8B8A8_USCALED,
748		VK_FORMAT_R8G8B8A8_SSCALED,
749		VK_FORMAT_R8G8B8A8_UINT,
750		VK_FORMAT_R8G8B8A8_SINT,
751		VK_FORMAT_R8G8B8A8_SRGB,
752		VK_FORMAT_B8G8R8A8_UNORM,
753		VK_FORMAT_B8G8R8A8_SNORM,
754		VK_FORMAT_B8G8R8A8_USCALED,
755		VK_FORMAT_B8G8R8A8_SSCALED,
756		VK_FORMAT_B8G8R8A8_UINT,
757		VK_FORMAT_B8G8R8A8_SINT,
758		VK_FORMAT_B8G8R8A8_SRGB,
759		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
760		VK_FORMAT_A2R10G10B10_UINT_PACK32,
761		VK_FORMAT_A2B10G10R10_USCALED_PACK32,
762		VK_FORMAT_R16_UNORM,
763		VK_FORMAT_R16_SNORM,
764		VK_FORMAT_R16_USCALED,
765		VK_FORMAT_R16_SSCALED,
766		VK_FORMAT_R16_UINT,
767		VK_FORMAT_R16_SINT,
768		VK_FORMAT_R16_SFLOAT,
769		VK_FORMAT_R16G16_UNORM,
770		VK_FORMAT_R16G16_SNORM,
771		VK_FORMAT_R16G16_USCALED,
772		VK_FORMAT_R16G16_SSCALED,
773		VK_FORMAT_R16G16_UINT,
774		VK_FORMAT_R16G16_SINT,
775		VK_FORMAT_R16G16_SFLOAT,
776		VK_FORMAT_R16G16B16_UNORM,
777		VK_FORMAT_R16G16B16_SNORM,
778		VK_FORMAT_R16G16B16_USCALED,
779		VK_FORMAT_R16G16B16_SSCALED,
780		VK_FORMAT_R16G16B16_UINT,
781		VK_FORMAT_R16G16B16_SINT,
782		VK_FORMAT_R16G16B16_SFLOAT,
783		VK_FORMAT_R16G16B16A16_UNORM,
784		VK_FORMAT_R16G16B16A16_SNORM,
785		VK_FORMAT_R16G16B16A16_USCALED,
786		VK_FORMAT_R16G16B16A16_SSCALED,
787		VK_FORMAT_R16G16B16A16_UINT,
788		VK_FORMAT_R16G16B16A16_SINT,
789		VK_FORMAT_R16G16B16A16_SFLOAT,
790		VK_FORMAT_R32_UINT,
791		VK_FORMAT_R32_SINT,
792		VK_FORMAT_R32_SFLOAT,
793		VK_FORMAT_R32G32_UINT,
794		VK_FORMAT_R32G32_SINT,
795		VK_FORMAT_R32G32_SFLOAT,
796		VK_FORMAT_R32G32B32_UINT,
797		VK_FORMAT_R32G32B32_SINT,
798		VK_FORMAT_R32G32B32_SFLOAT,
799		VK_FORMAT_R32G32B32A32_UINT,
800		VK_FORMAT_R32G32B32A32_SINT,
801		VK_FORMAT_R32G32B32A32_SFLOAT,
802		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
803		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
804		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
805		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
806		VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
807		VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT,
808		VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
809
810		// Compressed formats
811		VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
812		VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
813		VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
814		VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
815		VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
816		VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
817		VK_FORMAT_EAC_R11_UNORM_BLOCK,
818		VK_FORMAT_EAC_R11_SNORM_BLOCK,
819		VK_FORMAT_EAC_R11G11_UNORM_BLOCK,
820		VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
821		VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
822		VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
823		VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
824		VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
825		VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
826		VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
827		VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
828		VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
829		VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
830		VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
831		VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
832		VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
833		VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
834		VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
835		VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
836		VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
837		VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
838		VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
839		VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
840		VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
841		VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
842		VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
843		VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
844		VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
845		VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
846		VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
847		VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
848		VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
849		VK_FORMAT_BC5_UNORM_BLOCK,
850		VK_FORMAT_BC5_SNORM_BLOCK,
851	};
852
853	de::MovePtr<tcu::TestCaseGroup> imageTests			(new tcu::TestCaseGroup(testCtx, "image_view"));
854	de::MovePtr<tcu::TestCaseGroup> viewTypeTests		(new tcu::TestCaseGroup(testCtx, "view_type"));
855
856	for (int viewTypeNdx = 0; viewTypeNdx < DE_LENGTH_OF_ARRAY(imageViewTypes); viewTypeNdx++)
857	{
858		const VkImageViewType			viewType		= imageViewTypes[viewTypeNdx].type;
859		de::MovePtr<tcu::TestCaseGroup>	viewTypeGroup	(new tcu::TestCaseGroup(testCtx, imageViewTypes[viewTypeNdx].name));
860		// Uses samplable formats
861		de::MovePtr<tcu::TestCaseGroup>	formatTests		(new tcu::TestCaseGroup(testCtx, "format"));
862
863		for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
864		{
865			const VkFormat		format		= formats[formatNdx];
866
867			if (isCompressedFormat(format))
868			{
869				// Do not use compressed formats with 1D and 1D array textures.
870				if (viewType == VK_IMAGE_VIEW_TYPE_1D || viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
871					break;
872			}
873
874			de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx,
875																				getFormatCaseName(format).c_str(),
876																				(std::string("Samples a texture of format ") + getFormatName(format)).c_str()));
877
878			de::MovePtr<tcu::TestCaseGroup>	subresourceRangeTests	= createSubresourceRangeTests(testCtx, pipelineConstructionType, viewType, format);
879			de::MovePtr<tcu::TestCaseGroup>	componentSwizzleTests	= createComponentSwizzleTests(testCtx, pipelineConstructionType, viewType, format);
880
881			formatGroup->addChild(componentSwizzleTests.release());
882			formatGroup->addChild(subresourceRangeTests.release());
883			formatTests->addChild(formatGroup.release());
884		}
885
886		viewTypeGroup->addChild(formatTests.release());
887		viewTypeTests->addChild(viewTypeGroup.release());
888	}
889
890	imageTests->addChild(viewTypeTests.release());
891
892	return imageTests.release();
893}
894
895} // pipeline
896} // vkt
897