Home | History | Annotate | Download | only in texture
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2016 The Khronos Group Inc.
      6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
      7  * Copyright 2014 The Android Open Source Project
      8  *
      9  * Licensed under the Apache License, Version 2.0 (the "License");
     10  * you may not use this file except in compliance with the License.
     11  * You may obtain a copy of the License at
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     15  * Unless required by applicable law or agreed to in writing, software
     16  * distributed under the License is distributed on an "AS IS" BASIS,
     17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18  * See the License for the specific language governing permissions and
     19  * limitations under the License.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Mipmapping tests.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "vktTextureMipmapTests.hpp"
     27 
     28 #include "deRandom.hpp"
     29 #include "deString.h"
     30 #include "gluShaderUtil.hpp"
     31 #include "gluTextureTestUtil.hpp"
     32 #include "tcuMatrix.hpp"
     33 #include "tcuMatrixUtil.hpp"
     34 #include "tcuPixelFormat.hpp"
     35 #include "tcuTexLookupVerifier.hpp"
     36 #include "tcuTextureUtil.hpp"
     37 #include "tcuVectorUtil.hpp"
     38 #include "vkImageUtil.hpp"
     39 #include "vktTestGroupUtil.hpp"
     40 #include "vktTextureTestUtil.hpp"
     41 
     42 using namespace vk;
     43 
     44 namespace vkt
     45 {
     46 namespace texture
     47 {
     48 namespace
     49 {
     50 
     51 using std::string;
     52 using std::vector;
     53 using tcu::TestLog;
     54 using tcu::Vec2;
     55 using tcu::Vec3;
     56 using tcu::Vec4;
     57 using tcu::IVec4;
     58 using tcu::Sampler;
     59 using tcu::TextureFormat;
     60 using namespace texture::util;
     61 using namespace glu::TextureTestUtil;
     62 
     63 float getMinLodForCell (int cellNdx)
     64 {
     65 	static const float s_values[] =
     66 	{
     67 		1.0f,
     68 		3.5f,
     69 		2.0f,
     70 		-2.0f,
     71 		0.0f,
     72 		3.0f,
     73 		10.0f,
     74 		4.8f,
     75 		5.8f,
     76 		5.7f,
     77 		-1.9f,
     78 		4.0f,
     79 		6.5f,
     80 		7.1f,
     81 		-1e10,
     82 		1000.f
     83 	};
     84 	return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
     85 }
     86 
     87 float getMaxLodForCell (int cellNdx)
     88 {
     89 	static const float s_values[] =
     90 	{
     91 		0.0f,
     92 		0.2f,
     93 		0.7f,
     94 		0.4f,
     95 		1.3f,
     96 		0.0f,
     97 		0.5f,
     98 		1.2f,
     99 		-2.0f,
    100 		1.0f,
    101 		0.1f,
    102 		0.3f,
    103 		2.7f,
    104 		1.2f,
    105 		10.0f,
    106 		-1000.f,
    107 		1e10f
    108 	};
    109 	return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
    110 }
    111 
    112 enum CoordType
    113 {
    114 	COORDTYPE_BASIC,		//!< texCoord = translateScale(position).
    115 	COORDTYPE_BASIC_BIAS,	//!< Like basic, but with bias values.
    116 	COORDTYPE_AFFINE,		//!< texCoord = translateScaleRotateShear(position).
    117 	COORDTYPE_PROJECTED,	//!< Projected coordinates, w != 1
    118 
    119 	COORDTYPE_LAST
    120 };
    121 
    122 struct TextureMipmapCommonTestCaseParameters
    123 {
    124 							TextureMipmapCommonTestCaseParameters		(void);
    125 	CoordType				coordType;
    126 	const char*				minFilterName;
    127 };
    128 
    129 TextureMipmapCommonTestCaseParameters::TextureMipmapCommonTestCaseParameters (void)
    130 	: coordType				(COORDTYPE_BASIC)
    131 	, minFilterName			(NULL)
    132 {
    133 }
    134 
    135 struct Texture2DMipmapTestCaseParameters : public Texture2DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
    136 {
    137 };
    138 
    139 struct TextureCubeMipmapTestCaseParameters : public TextureCubeTestCaseParameters, public TextureMipmapCommonTestCaseParameters
    140 {
    141 };
    142 
    143 struct Texture3DMipmapTestCaseParameters : public Texture3DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
    144 {
    145 };
    146 
    147 // Texture2DMipmapTestInstance
    148 class Texture2DMipmapTestInstance : public TestInstance
    149 {
    150 public:
    151 	typedef Texture2DMipmapTestCaseParameters	ParameterType;
    152 
    153 									Texture2DMipmapTestInstance		(Context& context, const ParameterType& testParameters);
    154 									~Texture2DMipmapTestInstance	(void);
    155 
    156 	virtual tcu::TestStatus			iterate							(void);
    157 
    158 private:
    159 									Texture2DMipmapTestInstance		(const Texture2DMipmapTestInstance& other);
    160 	Texture2DMipmapTestInstance&	operator=						(const Texture2DMipmapTestInstance& other);
    161 
    162 	const ParameterType				m_testParameters;
    163 	TestTexture2DSp					m_texture;
    164 	TextureRenderer					m_renderer;
    165 };
    166 
    167 Texture2DMipmapTestInstance::Texture2DMipmapTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
    168 	: TestInstance		(context)
    169 	, m_testParameters	(testParameters)
    170 	, m_renderer		(context, testParameters.sampleCount, testParameters.width*4, testParameters.height*4)
    171 {
    172 	TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
    173 
    174 	m_texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height));
    175 
    176 	const int numLevels = deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height))+1;
    177 
    178 	// Fill texture with colored grid.
    179 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    180 	{
    181 		const deUint32	step	= 0xff / (numLevels-1);
    182 		const deUint32	inc		= deClamp32(step*levelNdx, 0x00, 0xff);
    183 		const deUint32	dec		= 0xff - inc;
    184 		const deUint32	rgb		= (inc << 16) | (dec << 8) | 0xff;
    185 		const deUint32	color	= 0xff000000 | rgb;
    186 
    187 		tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec());
    188 	}
    189 
    190 	// Upload texture data.
    191 	m_renderer.add2DTexture(m_texture);
    192 }
    193 
    194 Texture2DMipmapTestInstance::~Texture2DMipmapTestInstance (void)
    195 {
    196 }
    197 
    198 static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
    199 {
    200 	static const struct
    201 	{
    202 		const Vec2	bottomLeft;
    203 		const Vec2	topRight;
    204 	} s_basicCoords[] =
    205 	{
    206 		{ Vec2(-0.1f,  0.1f), Vec2( 0.8f,  1.0f) },
    207 		{ Vec2(-0.3f, -0.6f), Vec2( 0.7f,  0.4f) },
    208 		{ Vec2(-0.3f,  0.6f), Vec2( 0.7f, -0.9f) },
    209 		{ Vec2(-0.8f,  0.6f), Vec2( 0.7f, -0.9f) },
    210 
    211 		{ Vec2(-0.5f, -0.5f), Vec2( 1.5f,  1.5f) },
    212 		{ Vec2( 1.0f, -1.0f), Vec2(-1.3f,  1.0f) },
    213 		{ Vec2( 1.2f, -1.0f), Vec2(-1.3f,  1.6f) },
    214 		{ Vec2( 2.2f, -1.1f), Vec2(-1.3f,  0.8f) },
    215 
    216 		{ Vec2(-1.5f,  1.6f), Vec2( 1.7f, -1.4f) },
    217 		{ Vec2( 2.0f,  1.6f), Vec2( 2.3f, -1.4f) },
    218 		{ Vec2( 1.3f, -2.6f), Vec2(-2.7f,  2.9f) },
    219 		{ Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
    220 
    221 		{ Vec2( -8.0f,   9.0f), Vec2(  8.3f,  -7.0f) },
    222 		{ Vec2(-16.0f,  10.0f), Vec2( 18.3f,  24.0f) },
    223 		{ Vec2( 30.2f,  55.0f), Vec2(-24.3f,  -1.6f) },
    224 		{ Vec2(-33.2f,  64.1f), Vec2( 32.1f, -64.1f) },
    225 	};
    226 
    227 	DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
    228 
    229 	const Vec2& bottomLeft	= s_basicCoords[cellNdx].bottomLeft;
    230 	const Vec2& topRight	= s_basicCoords[cellNdx].topRight;
    231 
    232 	computeQuadTexCoord2D(dst, bottomLeft, topRight);
    233 }
    234 
    235 static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
    236 {
    237 	// Use basic coords as base.
    238 	getBasicTexCoord2D(dst, cellNdx);
    239 
    240 	// Rotate based on cell index.
    241 	const float		angle		= 2.0f*DE_PI * ((float)cellNdx / 16.0f);
    242 	const tcu::Mat2	rotMatrix	= tcu::rotationMatrix(angle);
    243 
    244 	// Second and third row are sheared.
    245 	const float		shearX		= de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
    246 	const tcu::Mat2	shearMatrix	= tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
    247 
    248 	const tcu::Mat2	transform	= rotMatrix * shearMatrix;
    249 	const Vec2		p0			= transform * Vec2(dst[0], dst[1]);
    250 	const Vec2		p1			= transform * Vec2(dst[2], dst[3]);
    251 	const Vec2		p2			= transform * Vec2(dst[4], dst[5]);
    252 	const Vec2		p3			= transform * Vec2(dst[6], dst[7]);
    253 
    254 	dst[0] = p0.x();	dst[1] = p0.y();
    255 	dst[2] = p1.x();	dst[3] = p1.y();
    256 	dst[4] = p2.x();	dst[5] = p2.y();
    257 	dst[6] = p3.x();	dst[7] = p3.y();
    258 }
    259 
    260 tcu::TestStatus Texture2DMipmapTestInstance::iterate (void)
    261 {
    262 	const Sampler::FilterMode	magFilter		= Sampler::NEAREST;
    263 	const int					viewportWidth	= m_renderer.getRenderWidth();
    264 	const int					viewportHeight	= m_renderer.getRenderHeight();
    265 
    266 	ReferenceParams				refParams		(TEXTURETYPE_2D);
    267 	vector<float>				texCoord;
    268 
    269 	const bool					isProjected		= m_testParameters.coordType == COORDTYPE_PROJECTED;
    270 	const bool					useLodBias		= m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
    271 
    272 	tcu::Surface				renderedFrame	(viewportWidth, viewportHeight);
    273 
    274 	// Viewport is divided into 4x4 grid.
    275 	const int					gridWidth		= 4;
    276 	const int					gridHeight		= 4;
    277 	const int					cellWidth		= viewportWidth / gridWidth;
    278 	const int					cellHeight		= viewportHeight / gridHeight;
    279 
    280 	// Sampling parameters.
    281 	refParams.sampler		= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, magFilter);
    282 	refParams.samplerType	= getSamplerType(vk::mapVkFormat(m_testParameters.format));
    283 	refParams.flags			= (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
    284 	refParams.lodMode		= LODMODE_EXACT; // Use ideal lod.
    285 
    286 	// Bias values.
    287 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
    288 
    289 	// Projection values.
    290 	static const Vec4 s_projections[] =
    291 	{
    292 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
    293 		Vec4(1.3f, 0.8f, 0.6f, 2.0f),
    294 		Vec4(0.8f, 1.0f, 1.7f, 0.6f),
    295 		Vec4(1.2f, 1.0f, 1.7f, 1.5f)
    296 	};
    297 
    298 	// Render cells.
    299 	for (int gridY = 0; gridY < gridHeight; gridY++)
    300 	{
    301 		for (int gridX = 0; gridX < gridWidth; gridX++)
    302 		{
    303 			const int	curX		= cellWidth*gridX;
    304 			const int	curY		= cellHeight*gridY;
    305 			const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
    306 			const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
    307 			const int	cellNdx		= gridY*gridWidth + gridX;
    308 
    309 			// Compute texcoord.
    310 			switch (m_testParameters.coordType)
    311 			{
    312 				case COORDTYPE_BASIC_BIAS:	// Fall-through.
    313 				case COORDTYPE_PROJECTED:
    314 				case COORDTYPE_BASIC:		getBasicTexCoord2D	(texCoord, cellNdx);	break;
    315 				case COORDTYPE_AFFINE:		getAffineTexCoord2D	(texCoord, cellNdx);	break;
    316 				default:					DE_ASSERT(DE_FALSE);
    317 			}
    318 
    319 			if (isProjected)
    320 				refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
    321 
    322 			if (useLodBias)
    323 				refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
    324 
    325 			m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
    326 			m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
    327 		}
    328 	}
    329 
    330 	// Compare and log.
    331 	{
    332 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
    333 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
    334 		const bool				isTrilinear		= m_testParameters.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_testParameters.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
    335 		tcu::Surface			referenceFrame	(viewportWidth, viewportHeight);
    336 		tcu::Surface			errorMask		(viewportWidth, viewportHeight);
    337 		tcu::LookupPrecision	lookupPrec;
    338 		tcu::LodPrecision		lodPrec;
    339 		int						numFailedPixels	= 0;
    340 
    341 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 0);
    342 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
    343 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
    344 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
    345 		lodPrec.derivateBits		= 10;
    346 		lodPrec.lodBits				= isProjected ? 6 : 8;
    347 
    348 		for (int gridY = 0; gridY < gridHeight; gridY++)
    349 		{
    350 			for (int gridX = 0; gridX < gridWidth; gridX++)
    351 			{
    352 				const int	curX		= cellWidth*gridX;
    353 				const int	curY		= cellHeight*gridY;
    354 				const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
    355 				const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
    356 				const int	cellNdx		= gridY*gridWidth + gridX;
    357 
    358 				// Compute texcoord.
    359 				switch (m_testParameters.coordType)
    360 				{
    361 					case COORDTYPE_BASIC_BIAS:	// Fall-through.
    362 					case COORDTYPE_PROJECTED:
    363 					case COORDTYPE_BASIC:		getBasicTexCoord2D	(texCoord, cellNdx);	break;
    364 					case COORDTYPE_AFFINE:		getAffineTexCoord2D	(texCoord, cellNdx);	break;
    365 					default:					DE_ASSERT(DE_FALSE);
    366 				}
    367 
    368 				if (isProjected)
    369 					refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
    370 
    371 				if (useLodBias)
    372 					refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
    373 
    374 				// Render ideal result
    375 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
    376 							  m_texture->getTexture(), &texCoord[0], refParams);
    377 
    378 				// Compare this cell
    379 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
    380 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
    381 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
    382 															m_texture->getTexture(), &texCoord[0], refParams,
    383 															lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
    384 			}
    385 		}
    386 
    387 		if (numFailedPixels > 0)
    388 			m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
    389 
    390 		m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
    391 											<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
    392 
    393 		if (numFailedPixels > 0)
    394 		{
    395 			m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
    396 												<< TestLog::Image("ErrorMask", "Error mask", errorMask);
    397 		}
    398 
    399 		m_context.getTestContext().getLog() << TestLog::EndImageSet;
    400 
    401 		{
    402 			const bool isOk = numFailedPixels == 0;
    403 			return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
    404 		}
    405 	}
    406 }
    407 
    408 // TextureCubeMipmapTestInstance
    409 class TextureCubeMipmapTestInstance : public TestInstance
    410 {
    411 public:
    412 	typedef	TextureCubeMipmapTestCaseParameters	ParameterType;
    413 
    414 									TextureCubeMipmapTestInstance	(Context& context, const ParameterType& testParameters);
    415 									~TextureCubeMipmapTestInstance	(void);
    416 
    417 	virtual tcu::TestStatus			iterate							(void);
    418 
    419 private:
    420 									TextureCubeMipmapTestInstance	(const TextureCubeMipmapTestInstance& other);
    421 	TextureCubeMipmapTestInstance&	operator=						(const TextureCubeMipmapTestInstance& other);
    422 
    423 	const ParameterType				m_testParameters;
    424 	TestTextureCubeSp				m_texture;
    425 	TextureRenderer					m_renderer;
    426 };
    427 
    428 TextureCubeMipmapTestInstance::TextureCubeMipmapTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
    429 	: TestInstance		(context)
    430 	, m_testParameters	(testParameters)
    431 	, m_renderer		(context, m_testParameters.sampleCount, m_testParameters.size*2, m_testParameters.size*2)
    432 {
    433 	TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
    434 
    435 	m_texture = TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(m_testParameters.format), m_testParameters.size));
    436 
    437 	const int numLevels = deLog2Floor32(m_testParameters.size)+1;
    438 
    439 	// Fill texture with colored grid.
    440 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
    441 	{
    442 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    443 		{
    444 			const deUint32	step	= 0xff / (numLevels-1);
    445 			const deUint32	inc		= deClamp32(step*levelNdx, 0x00, 0xff);
    446 			const deUint32	dec		= 0xff - inc;
    447 			deUint32		rgb		= 0;
    448 
    449 			switch (faceNdx)
    450 			{
    451 				case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
    452 				case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
    453 				case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
    454 				case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
    455 				case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
    456 				case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
    457 			}
    458 
    459 			const deUint32	color	= 0xff000000 | rgb;
    460 			tcu::clear(m_texture->getLevel(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
    461 		}
    462 	}
    463 
    464 	m_renderer.addCubeTexture(m_texture);
    465 }
    466 
    467 TextureCubeMipmapTestInstance::~TextureCubeMipmapTestInstance (void)
    468 {
    469 }
    470 
    471 static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
    472 {
    473 	const int	minWidth	= 8;
    474 	const int	minHeight	= 8;
    475 
    476 	const bool	partition	= rnd.getFloat() > 0.4f;
    477 	const bool	partitionX	= partition && width > minWidth && rnd.getBool();
    478 	const bool	partitionY	= partition && height > minHeight && !partitionX;
    479 
    480 	if (partitionX)
    481 	{
    482 		const int split = width/2 + rnd.getInt(-width/4, +width/4);
    483 		randomPartition(dst, rnd, x, y, split, height);
    484 		randomPartition(dst, rnd, x+split, y, width-split, height);
    485 	}
    486 	else if (partitionY)
    487 	{
    488 		const int split = height/2 + rnd.getInt(-height/4, +height/4);
    489 		randomPartition(dst, rnd, x, y, width, split);
    490 		randomPartition(dst, rnd, x, y+split, width, height-split);
    491 	}
    492 	else
    493 		dst.push_back(IVec4(x, y, width, height));
    494 }
    495 
    496 static void computeGridLayout (vector<IVec4>& dst, int width, int height)
    497 {
    498 	de::Random rnd(7);
    499 	randomPartition(dst, rnd, 0, 0, width, height);
    500 }
    501 
    502 tcu::TestStatus TextureCubeMipmapTestInstance::iterate (void)
    503 {
    504 	const int			viewportWidth	= m_renderer.getRenderWidth();
    505 	const int			viewportHeight	= m_renderer.getRenderHeight();
    506 
    507 	const bool			isProjected		= m_testParameters.coordType == COORDTYPE_PROJECTED;
    508 	const bool			useLodBias		= m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
    509 
    510 	ReferenceParams		refParams		(TEXTURETYPE_CUBE);
    511 	vector<float>		texCoord;
    512 	tcu::Surface		renderedFrame	(viewportWidth, viewportHeight);
    513 
    514 	refParams.sampler		= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
    515 	refParams.samplerType	= getSamplerType(vk::mapVkFormat(m_testParameters.format));
    516 	refParams.flags			= (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
    517 	refParams.lodMode		= LODMODE_EXACT; // Use ideal lod.
    518 
    519 	// Compute grid.
    520 	vector<IVec4> gridLayout;
    521 	computeGridLayout(gridLayout, viewportWidth, viewportHeight);
    522 
    523 	// Bias values.
    524 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
    525 
    526 	// Projection values \note Less agressive than in 2D case due to smaller quads.
    527 	static const Vec4 s_projections[] =
    528 	{
    529 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
    530 		Vec4(1.3f, 0.8f, 0.6f, 1.1f),
    531 		Vec4(0.8f, 1.0f, 1.2f, 0.8f),
    532 		Vec4(1.2f, 1.0f, 1.3f, 0.9f)
    533 	};
    534 
    535 	// Render with GL
    536 	for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
    537 	{
    538 		const float			curX		= (float)gridLayout[cellNdx].x();
    539 		const float			curY		= (float)gridLayout[cellNdx].y();
    540 		const float			curW		= (float)gridLayout[cellNdx].z();
    541 		const float			curH		= (float)gridLayout[cellNdx].w();
    542 		const tcu::CubeFace	cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
    543 
    544 		DE_ASSERT(m_testParameters.coordType != COORDTYPE_AFFINE); // Not supported.
    545 		computeQuadTexCoordCube(texCoord, cubeFace);
    546 
    547 		if (isProjected)
    548 		{
    549 			refParams.flags	|= ReferenceParams::PROJECTED;
    550 			refParams.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
    551 		}
    552 
    553 		if (useLodBias)
    554 		{
    555 			refParams.flags	|= ReferenceParams::USE_BIAS;
    556 			refParams.bias	 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
    557 		}
    558 
    559 		// Render
    560 		m_renderer.setViewport(curX, curY, curW, curH);
    561 		m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
    562 	}
    563 
    564 	// Render reference and compare
    565 	{
    566 		const tcu::IVec4		formatBitDepth		= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
    567 		const tcu::PixelFormat	pixelFormat			(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
    568 		tcu::Surface			referenceFrame		(viewportWidth, viewportHeight);
    569 		tcu::Surface			errorMask			(viewportWidth, viewportHeight);
    570 		int						numFailedPixels		= 0;
    571 		tcu::LookupPrecision	lookupPrec;
    572 		tcu::LodPrecision		lodPrec;
    573 
    574 		// Params for rendering reference
    575 		refParams.sampler					= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
    576 		refParams.sampler.seamlessCubeMap	= true;
    577 		refParams.lodMode					= LODMODE_EXACT;
    578 
    579 		// Comparison parameters
    580 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
    581 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat)-2, tcu::IVec4(0)));
    582 		lookupPrec.coordBits		= isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
    583 		lookupPrec.uvwBits			= tcu::IVec3(5,5,0);
    584 		lodPrec.derivateBits		= 10;
    585 		lodPrec.lodBits				= isProjected ? 3 : 6;
    586 
    587 		for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
    588 		{
    589 			const int				curX		= gridLayout[cellNdx].x();
    590 			const int				curY		= gridLayout[cellNdx].y();
    591 			const int				curW		= gridLayout[cellNdx].z();
    592 			const int				curH		= gridLayout[cellNdx].w();
    593 			const tcu::CubeFace		cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
    594 
    595 			DE_ASSERT(m_testParameters.coordType != COORDTYPE_AFFINE); // Not supported.
    596 			computeQuadTexCoordCube(texCoord, cubeFace);
    597 
    598 			if (isProjected)
    599 			{
    600 				refParams.flags	|= ReferenceParams::PROJECTED;
    601 				refParams.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
    602 			}
    603 
    604 			if (useLodBias)
    605 			{
    606 				refParams.flags	|= ReferenceParams::USE_BIAS;
    607 				refParams.bias	 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
    608 			}
    609 
    610 			// Render ideal reference.
    611 			{
    612 				tcu::SurfaceAccess idealDst(referenceFrame, pixelFormat, curX, curY, curW, curH);
    613 				sampleTexture(idealDst, m_texture->getTexture(), &texCoord[0], refParams);
    614 			}
    615 
    616 			// Compare this cell
    617 			numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
    618 														tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
    619 														tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
    620 														m_texture->getTexture(), &texCoord[0], refParams,
    621 														lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
    622 		}
    623 
    624 		if (numFailedPixels > 0)
    625 		{
    626 			m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
    627 		}
    628 
    629 		m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
    630 											<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
    631 
    632 		if (numFailedPixels > 0)
    633 		{
    634 			m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
    635 												<< TestLog::Image("ErrorMask", "Error mask", errorMask);
    636 		}
    637 
    638 		m_context.getTestContext().getLog() << TestLog::EndImageSet;
    639 
    640 		{
    641 			const bool isOk = numFailedPixels == 0;
    642 			return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
    643 		}
    644 	}
    645 }
    646 
    647 // Texture3DMipmapTestInstance
    648 class Texture3DMipmapTestInstance : public TestInstance
    649 {
    650 public:
    651 	typedef Texture3DMipmapTestCaseParameters	ParameterType;
    652 
    653 									Texture3DMipmapTestInstance		(Context& context, const ParameterType& testParameters);
    654 									~Texture3DMipmapTestInstance	(void);
    655 
    656 	virtual tcu::TestStatus			iterate							(void);
    657 
    658 private:
    659 									Texture3DMipmapTestInstance		(const Texture3DMipmapTestInstance& other);
    660 	Texture3DMipmapTestInstance&	operator=						(const Texture3DMipmapTestInstance& other);
    661 
    662 	const ParameterType				m_testParameters;
    663 	TestTexture3DSp					m_texture;
    664 	TextureRenderer					m_renderer;
    665 };
    666 
    667 Texture3DMipmapTestInstance::Texture3DMipmapTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
    668 	: TestInstance		(context)
    669 	, m_testParameters	(testParameters)
    670 	, m_renderer		(context, testParameters.sampleCount, testParameters.width*4, testParameters.height*4)
    671 {
    672 	TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
    673 
    674 	const tcu::TextureFormat&	texFmt		= mapVkFormat(testParameters.format);
    675 	tcu::TextureFormatInfo		fmtInfo		= tcu::getTextureFormatInfo(texFmt);
    676 	const tcu::Vec4&			cScale		= fmtInfo.lookupScale;
    677 	const tcu::Vec4&			cBias		= fmtInfo.lookupBias;
    678 	const int					numLevels	= deLog2Floor32(de::max(de::max(testParameters.width, testParameters.height), testParameters.depth))+1;
    679 
    680 	m_texture = TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.depth));
    681 
    682 	// Fill texture with colored grid.
    683 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    684 	{
    685 		const deUint32	step	= 0xff / (numLevels-1);
    686 		const deUint32	inc		= deClamp32(step*levelNdx, 0x00, 0xff);
    687 		const deUint32	dec		= 0xff - inc;
    688 		const deUint32	rgb		= (0xff << 16) | (dec << 8) | inc;
    689 		const deUint32	color	= 0xff000000 | rgb;
    690 
    691 		tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec()*cScale + cBias);
    692 	}
    693 
    694 	m_renderer.add3DTexture(m_texture);
    695 }
    696 
    697 Texture3DMipmapTestInstance::~Texture3DMipmapTestInstance (void)
    698 {
    699 }
    700 
    701 static void getBasicTexCoord3D (std::vector<float>& dst, int cellNdx)
    702 {
    703 	static const struct
    704 	{
    705 		const float sScale;
    706 		const float sBias;
    707 		const float tScale;
    708 		const float tBias;
    709 		const float rScale;
    710 		const float rBias;
    711 	} s_params[] =
    712 	{
    713 	//		sScale	sBias	tScale	tBias	rScale	rBias
    714 		{	 0.9f,	-0.1f,	 0.7f,	 0.3f,	 0.8f,	 0.9f	},
    715 		{	 1.2f,	-0.1f,	 1.1f,	 0.3f,	 1.0f,	 0.9f	},
    716 		{	 1.5f,	 0.7f,	 0.9f,	-0.3f,	 1.1f,	 0.1f	},
    717 		{	 1.2f,	 0.7f,	-2.3f,	-0.3f,	 1.1f,	 0.2f	},
    718 		{	 1.1f,	 0.8f,	-1.3f,	-0.3f,	 2.9f,	 0.9f	},
    719 		{	 3.4f,	 0.8f,	 4.0f,	 0.0f,	-3.3f,	-1.0f	},
    720 		{	-3.4f,	-0.1f,	-4.0f,	 0.0f,	-5.1f,	 1.0f	},
    721 		{	-4.0f,	-0.1f,	 3.4f,	 0.1f,	 5.7f,	 0.0f	},
    722 		{	-5.6f,	 0.0f,	 0.5f,	 1.2f,	 3.9f,	 4.0f	},
    723 		{	 5.0f,	-2.0f,	 3.1f,	 1.2f,	 5.1f,	 0.2f	},
    724 		{	 2.5f,	-2.0f,	 6.3f,	 3.0f,	 5.1f,	 0.2f	},
    725 		{	-8.3f,	 0.0f,	 7.1f,	 3.0f,	 2.0f,	 0.2f	},
    726 		{	 3.8f,	 0.0f,	 9.7f,	 1.0f,	 7.0f,	 0.7f	},
    727 		{	13.3f,	 0.0f,	 7.1f,	 3.0f,	 2.0f,	 0.2f	},
    728 		{	16.0f,	 8.0f,	12.7f,	 1.0f,	17.1f,	 0.7f	},
    729 		{	15.3f,	 0.0f,	20.1f,	 3.0f,	33.0f,	 3.2f	}
    730 	};
    731 
    732 	const float sScale	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sScale;
    733 	const float sBias	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sBias;
    734 	const float tScale	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tScale;
    735 	const float tBias	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tBias;
    736 	const float rScale	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rScale;
    737 	const float rBias	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rBias;
    738 
    739 	dst.resize(3*4);
    740 
    741 	dst[0] = sBias;			dst[ 1] = tBias;			dst[ 2] = rBias;
    742 	dst[3] = sBias;			dst[ 4] = tBias+tScale;		dst[ 5] = rBias+rScale*0.5f;
    743 	dst[6] = sBias+sScale;	dst[ 7] = tBias;			dst[ 8] = rBias+rScale*0.5f;
    744 	dst[9] = sBias+sScale;	dst[10] = tBias+tScale;		dst[11] = rBias+rScale;
    745 }
    746 
    747 static void getAffineTexCoord3D (std::vector<float>& dst, int cellNdx)
    748 {
    749 	// Use basic coords as base.
    750 	getBasicTexCoord3D(dst, cellNdx);
    751 
    752 	// Rotate based on cell index.
    753 	const float		angleX		= 0.0f + 2.0f*DE_PI * ((float)cellNdx / 16.0f);
    754 	const float		angleY		= 1.0f + 2.0f*DE_PI * ((float)cellNdx / 32.0f);
    755 	const tcu::Mat3	rotMatrix	= tcu::rotationMatrixX(angleX) * tcu::rotationMatrixY(angleY);
    756 
    757 	const Vec3		p0			= rotMatrix * Vec3(dst[0], dst[ 1], dst[ 2]);
    758 	const Vec3		p1			= rotMatrix * Vec3(dst[3], dst[ 4], dst[ 5]);
    759 	const Vec3		p2			= rotMatrix * Vec3(dst[6], dst[ 7], dst[ 8]);
    760 	const Vec3		p3			= rotMatrix * Vec3(dst[9], dst[10], dst[11]);
    761 
    762 	dst[0] = p0.x();	dst[ 1] = p0.y();	dst[ 2] = p0.z();
    763 	dst[3] = p1.x();	dst[ 4] = p1.y();	dst[ 5] = p1.z();
    764 	dst[6] = p2.x();	dst[ 7] = p2.y();	dst[ 8] = p2.z();
    765 	dst[9] = p3.x();	dst[10] = p3.y();	dst[11] = p3.z();
    766 }
    767 
    768 tcu::TestStatus Texture3DMipmapTestInstance::iterate (void)
    769 {
    770 	const tcu::TextureFormat&		texFmt			= m_texture->getTextureFormat();
    771 	const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(texFmt);
    772 	const Sampler::FilterMode		magFilter		= Sampler::NEAREST;
    773 	const int						viewportWidth	= m_renderer.getRenderWidth();
    774 	const int						viewportHeight	= m_renderer.getRenderHeight();
    775 
    776 	const bool						isProjected		= m_testParameters.coordType == COORDTYPE_PROJECTED;
    777 	const bool						useLodBias		= m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
    778 
    779 	// Viewport is divided into 4x4 grid.
    780 	const int						gridWidth		= 4;
    781 	const int						gridHeight		= 4;
    782 	const int						cellWidth		= viewportWidth / gridWidth;
    783 	const int						cellHeight		= viewportHeight / gridHeight;
    784 
    785 	ReferenceParams					refParams		(TEXTURETYPE_3D);
    786 
    787 	tcu::Surface					renderedFrame	(viewportWidth, viewportHeight);
    788 	vector<float>					texCoord;
    789 
    790 	// Sampling parameters.
    791 	refParams.sampler		= util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, magFilter);
    792 	refParams.samplerType	= getSamplerType(texFmt);
    793 
    794 	refParams.colorBias		= fmtInfo.lookupBias;
    795 	refParams.colorScale	= fmtInfo.lookupScale;
    796 	refParams.flags			= (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
    797 
    798 	// Bias values.
    799 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
    800 
    801 	// Projection values.
    802 	static const Vec4 s_projections[] =
    803 	{
    804 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
    805 		Vec4(1.3f, 0.8f, 0.6f, 2.0f),
    806 		Vec4(0.8f, 1.0f, 1.7f, 0.6f),
    807 		Vec4(1.2f, 1.0f, 1.7f, 1.5f)
    808 	};
    809 
    810 	// Render cells.
    811 	for (int gridY = 0; gridY < gridHeight; gridY++)
    812 	{
    813 		for (int gridX = 0; gridX < gridWidth; gridX++)
    814 		{
    815 			const int	curX		= cellWidth*gridX;
    816 			const int	curY		= cellHeight*gridY;
    817 			const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
    818 			const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
    819 			const int	cellNdx		= gridY*gridWidth + gridX;
    820 
    821 			// Compute texcoord.
    822 			switch (m_testParameters.coordType)
    823 			{
    824 				case COORDTYPE_BASIC_BIAS:	// Fall-through.
    825 				case COORDTYPE_PROJECTED:
    826 				case COORDTYPE_BASIC:		getBasicTexCoord3D	(texCoord, cellNdx);	break;
    827 				case COORDTYPE_AFFINE:		getAffineTexCoord3D	(texCoord, cellNdx);	break;
    828 				default:					DE_ASSERT(DE_FALSE);
    829 			}
    830 
    831 			// Set projection.
    832 			if (isProjected)
    833 				refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
    834 
    835 			// Set LOD bias.
    836 			if (useLodBias)
    837 				refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
    838 
    839 			m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
    840 			m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
    841 		}
    842 	}
    843 
    844 	// Compare and log
    845 	{
    846 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
    847 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
    848 		const bool				isTrilinear		= m_testParameters.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_testParameters.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
    849 		tcu::Surface			referenceFrame	(viewportWidth, viewportHeight);
    850 		tcu::Surface			errorMask		(viewportWidth, viewportHeight);
    851 		tcu::LookupPrecision	lookupPrec;
    852 		tcu::LodPrecision		lodPrec;
    853 		int						numFailedPixels	= 0;
    854 
    855 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 20);
    856 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
    857 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
    858 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
    859 		lodPrec.derivateBits		= 10;
    860 		lodPrec.lodBits				= isProjected ? 6 : 8;
    861 
    862 		for (int gridY = 0; gridY < gridHeight; gridY++)
    863 		{
    864 			for (int gridX = 0; gridX < gridWidth; gridX++)
    865 			{
    866 				const int	curX		= cellWidth*gridX;
    867 				const int	curY		= cellHeight*gridY;
    868 				const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
    869 				const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
    870 				const int	cellNdx		= gridY*gridWidth + gridX;
    871 
    872 				switch (m_testParameters.coordType)
    873 				{
    874 					case COORDTYPE_BASIC_BIAS:	// Fall-through.
    875 					case COORDTYPE_PROJECTED:
    876 					case COORDTYPE_BASIC:		getBasicTexCoord3D	(texCoord, cellNdx);	break;
    877 					case COORDTYPE_AFFINE:		getAffineTexCoord3D	(texCoord, cellNdx);	break;
    878 					default:					DE_ASSERT(DE_FALSE);
    879 				}
    880 
    881 				if (isProjected)
    882 					refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
    883 
    884 				if (useLodBias)
    885 					refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
    886 
    887 				// Render ideal result
    888 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
    889 							  m_texture->getTexture(), &texCoord[0], refParams);
    890 
    891 				// Compare this cell
    892 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
    893 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
    894 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
    895 															m_texture->getTexture(), &texCoord[0], refParams,
    896 															lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
    897 			}
    898 		}
    899 
    900 		if (numFailedPixels > 0)
    901 			m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
    902 
    903 		m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
    904 											<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
    905 
    906 		if (numFailedPixels > 0)
    907 		{
    908 			m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
    909 												<< TestLog::Image("ErrorMask", "Error mask", errorMask);
    910 		}
    911 
    912 		m_context.getTestContext().getLog() << TestLog::EndImageSet;
    913 
    914 		{
    915 			const bool isOk = numFailedPixels == 0;
    916 			return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
    917 		}
    918 	}
    919 }
    920 
    921 // Texture2DLodControlTestInstance
    922 class Texture2DLodControlTestInstance : public TestInstance
    923 {
    924 public:
    925 	typedef Texture2DMipmapTestCaseParameters	ParameterType;
    926 
    927 										Texture2DLodControlTestInstance		(Context& context, const ParameterType& testParameters);
    928 										~Texture2DLodControlTestInstance	(void);
    929 
    930 	virtual tcu::TestStatus				iterate								(void);
    931 
    932 protected:
    933 	virtual void						getReferenceParams					(ReferenceParams& params, int cellNdx) = 0;
    934 
    935 	const int							m_texWidth;
    936 	const int							m_texHeight;
    937 
    938 private:
    939 										Texture2DLodControlTestInstance		(const Texture2DLodControlTestInstance& other);
    940 	Texture2DLodControlTestInstance&	operator=							(const Texture2DLodControlTestInstance& other);
    941 
    942 	const ParameterType					m_testParameters;
    943 	tcu::Sampler::FilterMode			m_minFilter;
    944 	TestTexture2DSp						m_texture;
    945 	TextureRenderer						m_renderer;
    946 };
    947 
    948 Texture2DLodControlTestInstance::Texture2DLodControlTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
    949 	: TestInstance		(context)
    950 	, m_texWidth		(64) //64
    951 	, m_texHeight		(64)//64
    952 	, m_testParameters	(testParameters)
    953 	, m_minFilter		(testParameters.minFilter)
    954 	, m_texture			(DE_NULL)
    955 	, m_renderer		(context, testParameters.sampleCount, m_texWidth*4, m_texHeight*4)
    956 {
    957 	const VkFormat	format		= VK_FORMAT_R8G8B8A8_UNORM;
    958 	const int		numLevels	= deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
    959 
    960 	m_texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(format), m_texWidth, m_texHeight));
    961 
    962 	// Fill texture with colored grid.
    963 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    964 	{
    965 		const deUint32	step	= 0xff / (numLevels-1);
    966 		const deUint32	inc		= deClamp32(step*levelNdx, 0x00, 0xff);
    967 		const deUint32	dec		= 0xff - inc;
    968 		const deUint32	rgb		= (inc << 16) | (dec << 8) | 0xff;
    969 		const deUint32	color	= 0xff000000 | rgb;
    970 
    971 		tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec());
    972 	}
    973 
    974 	m_renderer.add2DTexture(m_texture);
    975 }
    976 
    977 Texture2DLodControlTestInstance::~Texture2DLodControlTestInstance (void)
    978 {
    979 }
    980 
    981 tcu::TestStatus Texture2DLodControlTestInstance::iterate (void)
    982 {
    983 	const tcu::Sampler::WrapMode	wrapS			= Sampler::REPEAT_GL;
    984 	const tcu::Sampler::WrapMode	wrapT			= Sampler::REPEAT_GL;
    985 	const tcu::Sampler::FilterMode	magFilter		= Sampler::NEAREST;
    986 
    987 	const tcu::Texture2D&			refTexture		= m_texture->getTexture();
    988 
    989 	const int						viewportWidth	= m_renderer.getRenderWidth();
    990 	const int						viewportHeight	= m_renderer.getRenderHeight();
    991 
    992 	tcu::Sampler					sampler			= util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
    993 
    994 	ReferenceParams					refParams		(TEXTURETYPE_2D, sampler);
    995 	vector<float>					texCoord;
    996 	tcu::Surface					renderedFrame	(viewportWidth, viewportHeight);
    997 
    998 	// Viewport is divided into 4x4 grid.
    999 	const int						gridWidth		= 4;
   1000 	const int						gridHeight		= 4;
   1001 	const int						cellWidth		= viewportWidth / gridWidth;
   1002 	const int						cellHeight		= viewportHeight / gridHeight;
   1003 
   1004 	refParams.maxLevel = deLog2Floor32(de::max(m_texWidth, m_texHeight));
   1005 
   1006 	// Render cells.
   1007 	for (int gridY = 0; gridY < gridHeight; gridY++)
   1008 	{
   1009 		for (int gridX = 0; gridX < gridWidth; gridX++)
   1010 		{
   1011 			const int	curX		= cellWidth*gridX;
   1012 			const int	curY		= cellHeight*gridY;
   1013 			const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
   1014 			const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
   1015 			const int	cellNdx		= gridY*gridWidth + gridX;
   1016 
   1017 			// Compute texcoord.
   1018 			getBasicTexCoord2D(texCoord, cellNdx);
   1019 			// Render
   1020 			getReferenceParams(refParams,cellNdx);
   1021 			m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
   1022 			m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel);
   1023 			m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
   1024 		}
   1025 	}
   1026 
   1027 	// Compare and log.
   1028 	{
   1029 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
   1030 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
   1031 		const bool				isTrilinear		= m_minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
   1032 		tcu::Surface			referenceFrame	(viewportWidth, viewportHeight);
   1033 		tcu::Surface			errorMask		(viewportWidth, viewportHeight);
   1034 		tcu::LookupPrecision	lookupPrec;
   1035 		tcu::LodPrecision		lodPrec;
   1036 		int						numFailedPixels	= 0;
   1037 
   1038 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 0);
   1039 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
   1040 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
   1041 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
   1042 		lodPrec.derivateBits		= 10;
   1043 		lodPrec.lodBits				= 8;
   1044 
   1045 		for (int gridY = 0; gridY < gridHeight; gridY++)
   1046 		{
   1047 			for (int gridX = 0; gridX < gridWidth; gridX++)
   1048 			{
   1049 				const int	curX		= cellWidth*gridX;
   1050 				const int	curY		= cellHeight*gridY;
   1051 				const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
   1052 				const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
   1053 				const int	cellNdx		= gridY*gridWidth + gridX;
   1054 
   1055 				getBasicTexCoord2D(texCoord, cellNdx);
   1056 				getReferenceParams(refParams, cellNdx);
   1057 
   1058 				// Render ideal result
   1059 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
   1060 							  refTexture, &texCoord[0], refParams);
   1061 
   1062 				// Compare this cell
   1063 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
   1064 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
   1065 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
   1066 															m_texture->getTexture(), &texCoord[0], refParams,
   1067 															lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
   1068 			}
   1069 		}
   1070 
   1071 		if (numFailedPixels > 0)
   1072 			m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
   1073 
   1074 		m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
   1075 											<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
   1076 
   1077 		if (numFailedPixels > 0)
   1078 		{
   1079 			m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
   1080 												<< TestLog::Image("ErrorMask", "Error mask", errorMask);
   1081 		}
   1082 
   1083 		m_context.getTestContext().getLog() << TestLog::EndImageSet;
   1084 
   1085 		{
   1086 			const bool isOk = numFailedPixels == 0;
   1087 			return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
   1088 		}
   1089 	}
   1090 }
   1091 
   1092 class Texture2DMinLodTestInstance : public Texture2DLodControlTestInstance
   1093 {
   1094 public:
   1095 	Texture2DMinLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
   1096 		: Texture2DLodControlTestInstance(context, testParameters)
   1097 	{
   1098 	}
   1099 
   1100 protected:
   1101 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1102 	{
   1103 		params.minLod = getMinLodForCell(cellNdx);
   1104 	}
   1105 };
   1106 
   1107 class Texture2DMaxLodTestInstance : public Texture2DLodControlTestInstance
   1108 {
   1109 public:
   1110 	Texture2DMaxLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
   1111 		: Texture2DLodControlTestInstance(context, testParameters)
   1112 	{
   1113 	}
   1114 
   1115 protected:
   1116 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1117 	{
   1118 		params.maxLod = getMaxLodForCell(cellNdx);
   1119 	}
   1120 };
   1121 
   1122 class Texture2DBaseLevelTestInstance : public Texture2DLodControlTestInstance
   1123 {
   1124 public:
   1125 	Texture2DBaseLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
   1126 		: Texture2DLodControlTestInstance(context, testParameters)
   1127 		, m_testParam (testParameters)
   1128 	{
   1129 	}
   1130 
   1131 protected:
   1132 	const Texture2DMipmapTestCaseParameters m_testParam;
   1133 
   1134 	int getBaseLevel (int cellNdx) const
   1135 	{
   1136 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
   1137 		const int	baseLevel	= (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0xac2f274a) % numLevels;
   1138 
   1139 		return baseLevel;
   1140 	}
   1141 
   1142 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1143 	{
   1144 		params.baseLevel = getBaseLevel(cellNdx);
   1145 	}
   1146 };
   1147 
   1148 class Texture2DMaxLevelTestInstance : public Texture2DLodControlTestInstance
   1149 {
   1150 public:
   1151 	Texture2DMaxLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
   1152 		: Texture2DLodControlTestInstance(context, testParameters)
   1153 		, m_testParam (testParameters)
   1154 	{
   1155 	}
   1156 
   1157 protected:
   1158 	const Texture2DMipmapTestCaseParameters m_testParam;
   1159 
   1160 	int getMaxLevel (int cellNdx) const
   1161 	{
   1162 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
   1163 		const int	maxLevel	= (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x82cfa4e) % numLevels;
   1164 
   1165 		return maxLevel;
   1166 	}
   1167 
   1168 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1169 	{
   1170 		params.maxLevel = getMaxLevel(cellNdx);
   1171 	}
   1172 };
   1173 
   1174 // TextureCubeLodControlTestInstance
   1175 class TextureCubeLodControlTestInstance : public TestInstance
   1176 {
   1177 public:
   1178 	typedef TextureCubeMipmapTestCaseParameters	ParameterType;
   1179 
   1180 										TextureCubeLodControlTestInstance	(Context& context, const ParameterType& testParameters);
   1181 										~TextureCubeLodControlTestInstance	(void);
   1182 
   1183 	virtual tcu::TestStatus				iterate								(void);
   1184 
   1185 protected:
   1186 	virtual void						getReferenceParams					(ReferenceParams& params, int cellNdx)	= DE_NULL;
   1187 
   1188 	const int							m_texSize;
   1189 
   1190 private:
   1191 										TextureCubeLodControlTestInstance	(const TextureCubeLodControlTestInstance& other);
   1192 	TextureCubeLodControlTestInstance&	operator=							(const TextureCubeLodControlTestInstance& other);
   1193 
   1194 	const ParameterType					m_testParameters;
   1195 	tcu::Sampler::FilterMode			m_minFilter;
   1196 	TestTextureCubeSp					m_texture;
   1197 	TextureRenderer						m_renderer;
   1198 };
   1199 
   1200 TextureCubeLodControlTestInstance::TextureCubeLodControlTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
   1201 	: TestInstance		(context)
   1202 	, m_texSize			(64)
   1203 	, m_testParameters	(testParameters)
   1204 	, m_minFilter		(testParameters.minFilter)
   1205 	, m_texture			(DE_NULL)
   1206 	, m_renderer		(context, testParameters.sampleCount, m_texSize*2, m_texSize*2)
   1207 {
   1208 	const VkFormat	format		= VK_FORMAT_R8G8B8A8_UNORM;
   1209 	const int		numLevels	= deLog2Floor32(m_texSize)+1;
   1210 
   1211 	m_texture = TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(format), m_texSize));
   1212 
   1213 	// Fill texture with colored grid.
   1214 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
   1215 	{
   1216 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
   1217 		{
   1218 			const deUint32	step	= 0xff / (numLevels-1);
   1219 			const deUint32	inc		= deClamp32(step*levelNdx, 0x00, 0xff);
   1220 			const deUint32	dec		= 0xff - inc;
   1221 			deUint32		rgb		= 0;
   1222 
   1223 			switch (faceNdx)
   1224 			{
   1225 				case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
   1226 				case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
   1227 				case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
   1228 				case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
   1229 				case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
   1230 				case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
   1231 			}
   1232 
   1233 			const deUint32	color	= 0xff000000 | rgb;
   1234 
   1235 			tcu::clear(m_texture->getLevel(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
   1236 		}
   1237 	}
   1238 
   1239 	m_renderer.addCubeTexture(m_texture);
   1240 }
   1241 
   1242 TextureCubeLodControlTestInstance::~TextureCubeLodControlTestInstance (void)
   1243 {
   1244 }
   1245 
   1246 tcu::TestStatus TextureCubeLodControlTestInstance::iterate (void)
   1247 {
   1248 	const tcu::Sampler::WrapMode	wrapS			= Sampler::CLAMP_TO_EDGE;
   1249 	const tcu::Sampler::WrapMode	wrapT			= Sampler::CLAMP_TO_EDGE;
   1250 	const tcu::Sampler::FilterMode	magFilter		= Sampler::NEAREST;
   1251 
   1252 	const tcu::TextureCube&			refTexture		= m_texture->getTexture();
   1253 	const int						viewportWidth	= m_renderer.getRenderWidth();
   1254 	const int						viewportHeight	= m_renderer.getRenderHeight();
   1255 
   1256 	tcu::Sampler					sampler			= util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
   1257 	ReferenceParams					refParams		(TEXTURETYPE_CUBE, sampler);
   1258 	vector<float>					texCoord;
   1259 	tcu::Surface					renderedFrame	(viewportWidth, viewportHeight);
   1260 
   1261 	refParams.maxLevel = deLog2Floor32(m_texSize);
   1262 
   1263 	// Compute grid.
   1264 	vector<tcu::IVec4> gridLayout;
   1265 	computeGridLayout(gridLayout, viewportWidth, viewportHeight);
   1266 
   1267 	for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
   1268 	{
   1269 		const int			curX		= gridLayout[cellNdx].x();
   1270 		const int			curY		= gridLayout[cellNdx].y();
   1271 		const int			curW		= gridLayout[cellNdx].z();
   1272 		const int			curH		= gridLayout[cellNdx].w();
   1273 		const tcu::CubeFace	cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
   1274 
   1275 		computeQuadTexCoordCube(texCoord, cubeFace);
   1276 		getReferenceParams(refParams, cellNdx);
   1277 
   1278 		// Render with GL.
   1279 		m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
   1280 		m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel);
   1281 		m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
   1282 	}
   1283 
   1284 	// Render reference and compare
   1285 	{
   1286 		const tcu::IVec4		formatBitDepth		= getTextureFormatBitDepth(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
   1287 		const tcu::PixelFormat	pixelFormat			(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
   1288 		tcu::Surface			referenceFrame		(viewportWidth, viewportHeight);
   1289 		tcu::Surface			errorMask			(viewportWidth, viewportHeight);
   1290 		int						numFailedPixels		= 0;
   1291 		tcu::LookupPrecision	lookupPrec;
   1292 		tcu::LodPrecision		lodPrec;
   1293 
   1294 		// Params for rendering reference
   1295 		refParams.sampler					= util::createSampler(wrapS, wrapT, m_testParameters.minFilter, magFilter);
   1296 		refParams.sampler.seamlessCubeMap	= true;
   1297 		refParams.lodMode					= LODMODE_EXACT;
   1298 
   1299 		// Comparison parameters
   1300 		lookupPrec.colorMask				= getCompareMask(pixelFormat);
   1301 		lookupPrec.colorThreshold			= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat)-2, IVec4(0)));
   1302 		lookupPrec.coordBits				= tcu::IVec3(10);
   1303 		lookupPrec.uvwBits					= tcu::IVec3(5,5,0);
   1304 		lodPrec.derivateBits				= 10;
   1305 		lodPrec.lodBits						= 6;
   1306 
   1307 		for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
   1308 		{
   1309 			const int				curX		= gridLayout[cellNdx].x();
   1310 			const int				curY		= gridLayout[cellNdx].y();
   1311 			const int				curW		= gridLayout[cellNdx].z();
   1312 			const int				curH		= gridLayout[cellNdx].w();
   1313 			const tcu::CubeFace		cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
   1314 
   1315 			computeQuadTexCoordCube(texCoord, cubeFace);
   1316 			getReferenceParams(refParams, cellNdx);
   1317 
   1318 			// Render ideal reference.
   1319 			{
   1320 				tcu::SurfaceAccess idealDst(referenceFrame, pixelFormat, curX, curY, curW, curH);
   1321 				sampleTexture(idealDst, refTexture, &texCoord[0], refParams);
   1322 			}
   1323 
   1324 			// Compare this cell
   1325 			numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
   1326 														tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
   1327 														tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
   1328 														m_texture->getTexture(), &texCoord[0], refParams,
   1329 														lookupPrec, lodPrec,  m_context.getTestContext().getWatchDog());
   1330 		}
   1331 
   1332 		if (numFailedPixels > 0)
   1333 			 m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
   1334 
   1335 		 m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
   1336 											 << TestLog::Image("Rendered", "Rendered image", renderedFrame);
   1337 
   1338 		if (numFailedPixels > 0)
   1339 		{
   1340 			 m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
   1341 												 << TestLog::Image("ErrorMask", "Error mask", errorMask);
   1342 		}
   1343 
   1344 		 m_context.getTestContext().getLog() << TestLog::EndImageSet;
   1345 
   1346 		{
   1347 			const bool isOk = numFailedPixels == 0;
   1348 			return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
   1349 		}
   1350 	}
   1351 }
   1352 
   1353 class TextureCubeMinLodTestInstance : public TextureCubeLodControlTestInstance
   1354 {
   1355 public:
   1356 	TextureCubeMinLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
   1357 		: TextureCubeLodControlTestInstance(context, testParameters)
   1358 	{
   1359 	}
   1360 
   1361 protected:
   1362 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1363 	{
   1364 		params.minLod = getMinLodForCell(cellNdx);
   1365 	}
   1366 };
   1367 
   1368 class TextureCubeMaxLodTestInstance : public TextureCubeLodControlTestInstance
   1369 {
   1370 public:
   1371 	TextureCubeMaxLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
   1372 		: TextureCubeLodControlTestInstance(context, testParameters)
   1373 	{
   1374 	}
   1375 
   1376 protected:
   1377 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1378 	{
   1379 		params.maxLod = getMaxLodForCell(cellNdx);
   1380 	}
   1381 };
   1382 
   1383 class TextureCubeBaseLevelTestInstance : public TextureCubeLodControlTestInstance
   1384 {
   1385 public:
   1386 	TextureCubeBaseLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
   1387 		: TextureCubeLodControlTestInstance(context, testParameters)
   1388 		, m_testParam (testParameters)
   1389 	{
   1390 	}
   1391 
   1392 protected:
   1393 	const TextureCubeMipmapTestCaseParameters m_testParam;
   1394 
   1395 	int getBaseLevel (int cellNdx) const
   1396 	{
   1397 		const int	numLevels	= deLog2Floor32(m_texSize)+1;
   1398 		const int	baseLevel	= (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x23fae13) % numLevels;
   1399 
   1400 		return baseLevel;
   1401 	}
   1402 
   1403 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1404 	{
   1405 		params.baseLevel = getBaseLevel(cellNdx);
   1406 	}
   1407 };
   1408 
   1409 class TextureCubeMaxLevelTestInstance : public TextureCubeLodControlTestInstance
   1410 {
   1411 public:
   1412 	TextureCubeMaxLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
   1413 		: TextureCubeLodControlTestInstance(context, testParameters)
   1414 		, m_testParam (testParameters)
   1415 	{
   1416 	}
   1417 
   1418 protected:
   1419 	const TextureCubeMipmapTestCaseParameters m_testParam;
   1420 	int getMaxLevel (int cellNdx) const
   1421 	{
   1422 		const int	numLevels	= deLog2Floor32(m_texSize)+1;
   1423 		const int	maxLevel	= (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x974e21) % numLevels;
   1424 
   1425 		return maxLevel;
   1426 	}
   1427 
   1428 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1429 	{
   1430 		params.maxLevel = getMaxLevel(cellNdx);
   1431 	}
   1432 };
   1433 
   1434 // Texture3DLodControlTestInstance
   1435 class Texture3DLodControlTestInstance : public TestInstance
   1436 {
   1437 public:
   1438 	typedef Texture3DMipmapTestCaseParameters	ParameterType;
   1439 
   1440 										Texture3DLodControlTestInstance		(Context& context, const ParameterType& testParameters);
   1441 										~Texture3DLodControlTestInstance	(void);
   1442 
   1443 	virtual tcu::TestStatus				iterate								(void);
   1444 
   1445 protected:
   1446 	virtual void						getReferenceParams					(ReferenceParams& params, int cellNdx)	= DE_NULL;
   1447 
   1448 	const int							m_texWidth;
   1449 	const int							m_texHeight;
   1450 	const int							m_texDepth;
   1451 
   1452 private:
   1453 										Texture3DLodControlTestInstance		(const Texture3DLodControlTestInstance& other);
   1454 	Texture3DLodControlTestInstance&	operator=							(const Texture3DLodControlTestInstance& other);
   1455 
   1456 	const ParameterType					m_testParameters;
   1457 	tcu::Sampler::FilterMode			m_minFilter;
   1458 	TestTexture3DSp						m_texture;
   1459 	TextureRenderer						m_renderer;
   1460 };
   1461 
   1462 Texture3DLodControlTestInstance::Texture3DLodControlTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
   1463 	: TestInstance		(context)
   1464 	, m_texWidth		(32)
   1465 	, m_texHeight		(32)
   1466 	, m_texDepth		(32)
   1467 	, m_testParameters	(testParameters)
   1468 	, m_minFilter		(testParameters.minFilter)
   1469 	, m_texture			(DE_NULL)
   1470 	, m_renderer		(context, testParameters.sampleCount, m_texWidth*4, m_texHeight*4)
   1471 {
   1472 	const VkFormat			format		= VK_FORMAT_R8G8B8A8_UNORM;
   1473 	tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(mapVkFormat(format));
   1474 	const tcu::Vec4&		cScale		= fmtInfo.lookupScale;
   1475 	const tcu::Vec4&		cBias		= fmtInfo.lookupBias;
   1476 	const int				numLevels	= deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth))+1;
   1477 
   1478 	m_texture = TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(format), m_texWidth, m_texHeight, m_texDepth));
   1479 
   1480 	// Fill texture with colored grid.
   1481 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
   1482 	{
   1483 		const deUint32	step	= 0xff / (numLevels-1);
   1484 		const deUint32	inc		= deClamp32(step*levelNdx, 0x00, 0xff);
   1485 		const deUint32	dec		= 0xff - inc;
   1486 		const deUint32	rgb		= (inc << 16) | (dec << 8) | 0xff;
   1487 		const deUint32	color	= 0xff000000 | rgb;
   1488 
   1489 		tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec()*cScale + cBias);
   1490 	}
   1491 
   1492 	m_renderer.add3DTexture(m_texture);
   1493 }
   1494 
   1495 Texture3DLodControlTestInstance::~Texture3DLodControlTestInstance (void)
   1496 {
   1497 }
   1498 
   1499 tcu::TestStatus Texture3DLodControlTestInstance::iterate (void)
   1500 {
   1501 	const tcu::Sampler::WrapMode	wrapS			= Sampler::CLAMP_TO_EDGE;
   1502 	const tcu::Sampler::WrapMode	wrapT			= Sampler::CLAMP_TO_EDGE;
   1503 	const tcu::Sampler::WrapMode	wrapR			= Sampler::CLAMP_TO_EDGE;
   1504 	const tcu::Sampler::FilterMode	magFilter		= Sampler::NEAREST;
   1505 
   1506 	const tcu::Texture3D&			refTexture		= m_texture->getTexture();
   1507 	const tcu::TextureFormat&		texFmt			= refTexture.getFormat();
   1508 	const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(texFmt);
   1509 	const int						viewportWidth	= m_renderer.getRenderWidth();
   1510 	const int						viewportHeight	= m_renderer.getRenderHeight();
   1511 
   1512 	tcu::Sampler					sampler			= util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
   1513 	ReferenceParams					refParams		(TEXTURETYPE_3D, sampler);
   1514 	vector<float>					texCoord;
   1515 	tcu::Surface					renderedFrame	(viewportWidth, viewportHeight);
   1516 
   1517 	// Viewport is divided into 4x4 grid.
   1518 	const int						gridWidth		= 4;
   1519 	const int						gridHeight		= 4;
   1520 	const int						cellWidth		= viewportWidth / gridWidth;
   1521 	const int						cellHeight		= viewportHeight / gridHeight;
   1522 
   1523 	// Sampling parameters.
   1524 	refParams.sampler		= util::createSampler(wrapS, wrapT, wrapR, m_testParameters.minFilter, magFilter);
   1525 	refParams.samplerType	= getSamplerType(texFmt);
   1526 	refParams.colorBias		= fmtInfo.lookupBias;
   1527 	refParams.colorScale	= fmtInfo.lookupScale;
   1528 	refParams.maxLevel		= deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth));
   1529 
   1530 	// Render cells.
   1531 	for (int gridY = 0; gridY < gridHeight; gridY++)
   1532 	{
   1533 		for (int gridX = 0; gridX < gridWidth; gridX++)
   1534 		{
   1535 			const int	curX		= cellWidth*gridX;
   1536 			const int	curY		= cellHeight*gridY;
   1537 			const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
   1538 			const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
   1539 			const int	cellNdx		= gridY*gridWidth + gridX;
   1540 
   1541 			// Compute texcoord.
   1542 			getBasicTexCoord3D(texCoord, cellNdx);
   1543 
   1544 			getReferenceParams(refParams,cellNdx);
   1545 			//Render
   1546 			m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
   1547 			m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel);
   1548 			m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
   1549 		}
   1550 	}
   1551 
   1552 	// Compare and log
   1553 	{
   1554 		const tcu::IVec4		formatBitDepth	= getTextureFormatBitDepth(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
   1555 		const tcu::PixelFormat	pixelFormat		(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
   1556 		const bool				isTrilinear		= m_minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
   1557 		tcu::Surface			referenceFrame	(viewportWidth, viewportHeight);
   1558 		tcu::Surface			errorMask		(viewportWidth, viewportHeight);
   1559 		tcu::LookupPrecision	lookupPrec;
   1560 		tcu::LodPrecision		lodPrec;
   1561 		int						numFailedPixels	= 0;
   1562 
   1563 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 20);
   1564 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
   1565 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
   1566 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
   1567 		lodPrec.derivateBits		= 10;
   1568 		lodPrec.lodBits				= 8;
   1569 
   1570 		for (int gridY = 0; gridY < gridHeight; gridY++)
   1571 		{
   1572 			for (int gridX = 0; gridX < gridWidth; gridX++)
   1573 			{
   1574 				const int	curX		= cellWidth*gridX;
   1575 				const int	curY		= cellHeight*gridY;
   1576 				const int	curW		= gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
   1577 				const int	curH		= gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
   1578 				const int	cellNdx		= gridY*gridWidth + gridX;
   1579 
   1580 				getBasicTexCoord3D(texCoord, cellNdx);
   1581 				getReferenceParams(refParams, cellNdx);
   1582 
   1583 				// Render ideal result
   1584 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
   1585 							  refTexture, &texCoord[0], refParams);
   1586 
   1587 				// Compare this cell
   1588 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
   1589 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
   1590 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
   1591 															m_texture->getTexture(), &texCoord[0], refParams,
   1592 															lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
   1593 			}
   1594 		}
   1595 
   1596 		if (numFailedPixels > 0)
   1597 		{
   1598 			m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
   1599 		}
   1600 
   1601 		m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
   1602 											<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
   1603 
   1604 		if (numFailedPixels > 0)
   1605 		{
   1606 			m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
   1607 												<< TestLog::Image("ErrorMask", "Error mask", errorMask);
   1608 		}
   1609 
   1610 		m_context.getTestContext().getLog() << TestLog::EndImageSet;
   1611 
   1612 		{
   1613 			const bool isOk = numFailedPixels == 0;
   1614 			return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
   1615 		}
   1616 	}
   1617 }
   1618 
   1619 class Texture3DMinLodTestInstance : public Texture3DLodControlTestInstance
   1620 {
   1621 public:
   1622 	Texture3DMinLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
   1623 		: Texture3DLodControlTestInstance(context, testParameters)
   1624 	{
   1625 	}
   1626 
   1627 protected:
   1628 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1629 	{
   1630 		params.minLod = getMinLodForCell(cellNdx);
   1631 	}
   1632 };
   1633 
   1634 class Texture3DMaxLodTestInstance : public Texture3DLodControlTestInstance
   1635 {
   1636 public:
   1637 	Texture3DMaxLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
   1638 		: Texture3DLodControlTestInstance(context, testParameters)
   1639 	{
   1640 	}
   1641 
   1642 protected:
   1643 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1644 	{
   1645 		params.maxLod = getMaxLodForCell(cellNdx);
   1646 	}
   1647 };
   1648 
   1649 class Texture3DBaseLevelTestInstance : public Texture3DLodControlTestInstance
   1650 {
   1651 public:
   1652 	Texture3DBaseLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
   1653 		: Texture3DLodControlTestInstance(context, testParameters)
   1654 		,m_testParam (testParameters)
   1655 	{
   1656 	}
   1657 
   1658 protected:
   1659 	const Texture3DMipmapTestCaseParameters m_testParam;
   1660 
   1661 	int getBaseLevel (int cellNdx) const
   1662 	{
   1663 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
   1664 		const int	baseLevel	= (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x7347e9) % numLevels;
   1665 
   1666 		return baseLevel;
   1667 	}
   1668 
   1669 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1670 	{
   1671 		params.baseLevel = getBaseLevel(cellNdx);
   1672 	}
   1673 };
   1674 
   1675 class Texture3DMaxLevelTestInstance : public Texture3DLodControlTestInstance
   1676 {
   1677 public:
   1678 	Texture3DMaxLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
   1679 		: Texture3DLodControlTestInstance(context, testParameters)
   1680 		,m_testParam (testParameters)
   1681 	{
   1682 	}
   1683 
   1684 protected:
   1685 	const Texture3DMipmapTestCaseParameters m_testParam;
   1686 
   1687 	int getMaxLevel (int cellNdx) const
   1688 	{
   1689 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
   1690 		const int	maxLevel	= (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x9111e7) % numLevels;
   1691 
   1692 		return maxLevel;
   1693 	}
   1694 
   1695 	void getReferenceParams (ReferenceParams& params, int cellNdx)
   1696 	{
   1697 		params.maxLevel = getMaxLevel(cellNdx);
   1698 	}
   1699 };
   1700 
   1701 void populateTextureMipmappingTests (tcu::TestCaseGroup* textureMipmappingTests)
   1702 {
   1703 	tcu::TestContext&	testCtx		= textureMipmappingTests->getTestContext();
   1704 
   1705 	static const struct
   1706 	{
   1707 		const char*				name;
   1708 		const Sampler::WrapMode	mode;
   1709 	} wrapModes[] =
   1710 	{
   1711 		{ "clamp",		Sampler::CLAMP_TO_EDGE		},
   1712 		{ "repeat",		Sampler::REPEAT_GL			},
   1713 		{ "mirror",		Sampler::MIRRORED_REPEAT_GL	}
   1714 	};
   1715 
   1716 	static const struct
   1717 	{
   1718 		const char*					name;
   1719 		const Sampler::FilterMode	mode;
   1720 	} minFilterModes[] =
   1721 	{
   1722 		{ "nearest_nearest",	Sampler::NEAREST_MIPMAP_NEAREST	},
   1723 		{ "linear_nearest",		Sampler::LINEAR_MIPMAP_NEAREST	},
   1724 		{ "nearest_linear",		Sampler::NEAREST_MIPMAP_LINEAR	},
   1725 		{ "linear_linear",		Sampler::LINEAR_MIPMAP_LINEAR	}
   1726 	};
   1727 
   1728 	static const struct
   1729 	{
   1730 		const char*					name;
   1731 		const Sampler::FilterMode	mode;
   1732 	} magFilterModes[] =
   1733 	{
   1734 		{ "nearest",	Sampler::NEAREST},
   1735 		{ "linear",		Sampler::LINEAR}
   1736 	};
   1737 
   1738 
   1739 	static const struct
   1740 	{
   1741 		const CoordType		type;
   1742 		const char*			name;
   1743 		const char*			desc;
   1744 	} coordTypes[] =
   1745 	{
   1746 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
   1747 		{ COORDTYPE_AFFINE,		"affine",		"Mipmapping with affine coordinate transform"		},
   1748 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			}
   1749 	};
   1750 
   1751 	static const struct
   1752 	{
   1753 		const char*		name;
   1754 		const int		width;
   1755 		const int		height;
   1756 	} tex2DSizes[] =
   1757 	{
   1758 		{ DE_NULL,		64, 64 }, // Default.
   1759 		{ "npot",		63, 57 },
   1760 		{ "non_square",	32, 64 }
   1761 	};
   1762 
   1763 	static const struct
   1764 	{
   1765 		const char*		name;
   1766 		const int		width;
   1767 		const int		height;
   1768 		const int		depth;
   1769 	} tex3DSizes[] =
   1770 	{
   1771 		{ DE_NULL,		32, 32, 32 }, // Default.
   1772 		{ "npot",		33, 29, 27 }
   1773 	};
   1774 
   1775 	const int cubeMapSize = 64;
   1776 
   1777 	static const struct
   1778 	{
   1779 		const CoordType		type;
   1780 		const char*			name;
   1781 		const char*			desc;
   1782 	} cubeCoordTypes[] =
   1783 	{
   1784 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
   1785 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			},
   1786 		{ COORDTYPE_BASIC_BIAS,	"bias",			"User-supplied bias value"							}
   1787 	};
   1788 
   1789 	// 2D cases.
   1790 	{
   1791 		de::MovePtr<tcu::TestCaseGroup>	group2D				(new tcu::TestCaseGroup(testCtx, "2d", "2D Mipmap Filtering"));
   1792 
   1793 		de::MovePtr<tcu::TestCaseGroup>	biasGroup2D			(new tcu::TestCaseGroup(testCtx, "bias", "User-supplied bias value"));
   1794 		de::MovePtr<tcu::TestCaseGroup>	minLodGroup2D		(new tcu::TestCaseGroup(testCtx, "min_lod", "Lod control: min lod"));
   1795 		de::MovePtr<tcu::TestCaseGroup>	maxLodGroup2D		(new tcu::TestCaseGroup(testCtx, "max_lod", "Lod control: max lod"));
   1796 		de::MovePtr<tcu::TestCaseGroup>	baseLevelGroup2D	(new tcu::TestCaseGroup(testCtx, "base_level", "Base level"));
   1797 		de::MovePtr<tcu::TestCaseGroup>	maxLevelGroup2D		(new tcu::TestCaseGroup(testCtx, "max_level", "Max level"));
   1798 
   1799 		for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
   1800 		{
   1801 			de::MovePtr<tcu::TestCaseGroup>	coordTypeGroup		(new tcu::TestCaseGroup(testCtx, coordTypes[coordType].name, coordTypes[coordType].desc));
   1802 
   1803 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1804 			{
   1805 				for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
   1806 				{
   1807 					// Add non_square variants to basic cases only.
   1808 					int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
   1809 
   1810 					for (int size = 0; size < sizeEnd; size++)
   1811 					{
   1812 						Texture2DMipmapTestCaseParameters	testParameters;
   1813 
   1814 						testParameters.coordType	= coordTypes[coordType].type;
   1815 						testParameters.minFilter	= minFilterModes[minFilter].mode;
   1816 						testParameters.wrapS		= wrapModes[wrapMode].mode;
   1817 						testParameters.wrapT		= wrapModes[wrapMode].mode;
   1818 						testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM; //not sure (GL_RGBA)
   1819 						testParameters.width		= tex2DSizes[size].width;
   1820 						testParameters.height		= tex2DSizes[size].height;
   1821 						testParameters.programs.push_back(PROGRAM_2D_FLOAT);
   1822 
   1823 						std::ostringstream name;
   1824 						name << minFilterModes[minFilter].name
   1825 							 << "_" << wrapModes[wrapMode].name;
   1826 
   1827 						if (tex2DSizes[size].name)
   1828 							name << "_" << tex2DSizes[size].name;
   1829 
   1830 						coordTypeGroup->addChild(new TextureTestCase<Texture2DMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
   1831 					}
   1832 				}
   1833 			}
   1834 
   1835 			group2D->addChild(coordTypeGroup.release());
   1836 		}
   1837 
   1838 		// 2D bias variants.
   1839 		{
   1840 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1841 			{
   1842 				Texture2DMipmapTestCaseParameters	testParameters;
   1843 
   1844 				testParameters.coordType	= COORDTYPE_BASIC_BIAS;
   1845 				testParameters.minFilter	= minFilterModes[minFilter].mode;
   1846 				testParameters.magFilter	= minFilterModes[minFilter].mode;
   1847 				testParameters.wrapS		= Sampler::REPEAT_GL;
   1848 				testParameters.wrapT		= Sampler::REPEAT_GL;
   1849 				testParameters.format		= VK_FORMAT_R8G8B8A8_UNORM; //not sure (GL_RGBA)
   1850 				testParameters.width		= tex2DSizes[0].width;
   1851 				testParameters.height		= tex2DSizes[0].height;
   1852 				testParameters.programs.push_back(PROGRAM_2D_FLOAT_BIAS);
   1853 
   1854 				std::ostringstream name;
   1855 				name << minFilterModes[minFilter].name;
   1856 
   1857 				biasGroup2D->addChild(new TextureTestCase<Texture2DMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
   1858 			}
   1859 		}
   1860 
   1861 		// 2D LOD controls.
   1862 		{
   1863 			// MIN_LOD
   1864 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1865 			{
   1866 				Texture2DMipmapTestCaseParameters	testParameters;
   1867 				testParameters.minFilter	= minFilterModes[minFilter].mode;
   1868 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
   1869 
   1870 				minLodGroup2D->addChild(new TextureTestCase<Texture2DMinLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1871 			}
   1872 
   1873 			// MAX_LOD
   1874 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1875 			{
   1876 				Texture2DMipmapTestCaseParameters	testParameters;
   1877 				testParameters.minFilter = minFilterModes[minFilter].mode;
   1878 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
   1879 
   1880 				maxLodGroup2D->addChild(new TextureTestCase<Texture2DMaxLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1881 			}
   1882 		}
   1883 
   1884 		{
   1885 			// BASE_LEVEL
   1886 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1887 			{
   1888 				Texture2DMipmapTestCaseParameters	testParameters;
   1889 				testParameters.minFilter = minFilterModes[minFilter].mode;
   1890 				testParameters.minFilterName = minFilterModes[minFilter].name;
   1891 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
   1892 
   1893 				baseLevelGroup2D->addChild(new TextureTestCase<Texture2DBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1894 			}
   1895 
   1896 			// MAX_LEVEL
   1897 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1898 			{
   1899 				Texture2DMipmapTestCaseParameters	testParameters;
   1900 				testParameters.minFilter = minFilterModes[minFilter].mode;
   1901 				testParameters.minFilterName = minFilterModes[minFilter].name;
   1902 				testParameters.programs.push_back(PROGRAM_2D_FLOAT);
   1903 
   1904 				maxLevelGroup2D->addChild(new TextureTestCase<Texture2DMaxLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1905 			}
   1906 		}
   1907 
   1908 		group2D->addChild(biasGroup2D.release());
   1909 		group2D->addChild(minLodGroup2D.release());
   1910 		group2D->addChild(maxLodGroup2D.release());
   1911 		group2D->addChild(baseLevelGroup2D.release());
   1912 		group2D->addChild(maxLevelGroup2D.release());
   1913 
   1914 		textureMipmappingTests->addChild(group2D.release());
   1915 	}
   1916 
   1917 	// Cubemap cases.
   1918 	{
   1919 		de::MovePtr<tcu::TestCaseGroup>	groupCube			(new tcu::TestCaseGroup(testCtx, "cubemap", "Cube Mipmap Filtering"));
   1920 
   1921 		de::MovePtr<tcu::TestCaseGroup>	minLodGroupCube		(new tcu::TestCaseGroup(testCtx, "min_lod", "Lod control: min lod"));
   1922 		de::MovePtr<tcu::TestCaseGroup>	maxLodGroupCube		(new tcu::TestCaseGroup(testCtx, "max_lod", "Lod control: max lod"));
   1923 		de::MovePtr<tcu::TestCaseGroup>	baseLevelGroupCube	(new tcu::TestCaseGroup(testCtx, "base_level", "Base level"));
   1924 		de::MovePtr<tcu::TestCaseGroup>	maxLevelGroupCube	(new tcu::TestCaseGroup(testCtx, "max_level", "Max level"));
   1925 
   1926 		for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
   1927 		{
   1928 			de::MovePtr<tcu::TestCaseGroup>	coordTypeGroup	(new tcu::TestCaseGroup(testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc));
   1929 
   1930 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1931 			{
   1932 				for (int magFilter = 0; magFilter < DE_LENGTH_OF_ARRAY(magFilterModes); magFilter++)
   1933 				{
   1934 					for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
   1935 					{
   1936 						TextureCubeMipmapTestCaseParameters	testParameters;
   1937 
   1938 						testParameters.coordType		= cubeCoordTypes[coordType].type;
   1939 						testParameters.minFilter		= minFilterModes[minFilter].mode;
   1940 						testParameters.magFilter		= magFilterModes[magFilter].mode;
   1941 						testParameters.minFilterName	= minFilterModes[minFilter].name;
   1942 						testParameters.wrapS			= wrapModes[wrapMode].mode;
   1943 						testParameters.wrapT			= wrapModes[wrapMode].mode;
   1944 						testParameters.format			= VK_FORMAT_R8G8B8A8_UNORM;
   1945 						testParameters.size				= cubeMapSize;
   1946 						testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
   1947 						testParameters.programs.push_back(PROGRAM_CUBE_FLOAT_BIAS);
   1948 
   1949 						std::ostringstream name;
   1950 						name << minFilterModes[minFilter].name
   1951 							 << "_" << magFilterModes[magFilter].name
   1952 							 << "_" << wrapModes[wrapMode].name;
   1953 
   1954 						coordTypeGroup->addChild(new TextureTestCase<TextureCubeMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
   1955 					}
   1956 				}
   1957 			}
   1958 
   1959 			groupCube->addChild(coordTypeGroup.release());
   1960 		}
   1961 
   1962 		// Cubemap LOD controls.
   1963 		{
   1964 			// MIN_LOD
   1965 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1966 			{
   1967 				TextureCubeMipmapTestCaseParameters	testParameters;
   1968 				testParameters.minFilter	= minFilterModes[minFilter].mode;
   1969 				testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
   1970 
   1971 				minLodGroupCube->addChild(new TextureTestCase<TextureCubeMinLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1972 			}
   1973 
   1974 			// MAX_LOD
   1975 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1976 			{
   1977 				TextureCubeMipmapTestCaseParameters	testParameters;
   1978 				testParameters.minFilter	= minFilterModes[minFilter].mode;
   1979 				testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
   1980 
   1981 				maxLodGroupCube->addChild(new TextureTestCase<TextureCubeMaxLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1982 			}
   1983 		}
   1984 
   1985 		{
   1986 			// BASE_LEVEL
   1987 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1988 			{
   1989 				TextureCubeMipmapTestCaseParameters	testParameters;
   1990 				testParameters.minFilter = minFilterModes[minFilter].mode;
   1991 				testParameters.minFilterName = minFilterModes[minFilter].name;
   1992 				testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
   1993 
   1994 				baseLevelGroupCube->addChild(new TextureTestCase<TextureCubeBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   1995 			}
   1996 
   1997 			// MAX_LEVEL
   1998 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   1999 			{
   2000 				TextureCubeMipmapTestCaseParameters	testParameters;
   2001 				testParameters.minFilter = minFilterModes[minFilter].mode;
   2002 				testParameters.minFilterName = minFilterModes[minFilter].name;
   2003 				testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
   2004 
   2005 				maxLevelGroupCube->addChild(new TextureTestCase<TextureCubeMaxLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   2006 			}
   2007 		}
   2008 
   2009 		groupCube->addChild(minLodGroupCube.release());
   2010 		groupCube->addChild(maxLodGroupCube.release());
   2011 		groupCube->addChild(baseLevelGroupCube.release());
   2012 		groupCube->addChild(maxLevelGroupCube.release());
   2013 
   2014 		textureMipmappingTests->addChild(groupCube.release());
   2015 	}
   2016 
   2017 	// 3D cases.
   2018 	{
   2019 		de::MovePtr<tcu::TestCaseGroup>	group3D				(new tcu::TestCaseGroup(testCtx, "3d", "3D Mipmap Filtering"));
   2020 
   2021 		de::MovePtr<tcu::TestCaseGroup>	biasGroup3D			(new tcu::TestCaseGroup(testCtx, "bias", "User-supplied bias value"));
   2022 		de::MovePtr<tcu::TestCaseGroup>	minLodGroup3D		(new tcu::TestCaseGroup(testCtx, "min_lod", "Lod control: min lod"));
   2023 		de::MovePtr<tcu::TestCaseGroup>	maxLodGroup3D		(new tcu::TestCaseGroup(testCtx, "max_lod", "Lod control: max lod"));
   2024 		de::MovePtr<tcu::TestCaseGroup>	baseLevelGroup3D	(new tcu::TestCaseGroup(testCtx, "base_level", "Base level"));
   2025 		de::MovePtr<tcu::TestCaseGroup>	maxLevelGroup3D		(new tcu::TestCaseGroup(testCtx, "max_level", "Max level"));
   2026 
   2027 		for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
   2028 		{
   2029 			de::MovePtr<tcu::TestCaseGroup>	coordTypeGroup	(new tcu::TestCaseGroup(testCtx, coordTypes[coordType].name, coordTypes[coordType].desc));
   2030 
   2031 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   2032 			{
   2033 				for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
   2034 				{
   2035 					// Add other size variants to basic cases only.
   2036 					int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex3DSizes) : 1;
   2037 
   2038 					Texture3DMipmapTestCaseParameters	testParameters;
   2039 
   2040 					testParameters.coordType		= coordTypes[coordType].type;
   2041 					testParameters.minFilter		= minFilterModes[minFilter].mode;
   2042 					testParameters.minFilterName	= minFilterModes[minFilter].name;
   2043 					testParameters.wrapR			= wrapModes[wrapMode].mode;
   2044 					testParameters.wrapS			= wrapModes[wrapMode].mode;
   2045 					testParameters.wrapT			= wrapModes[wrapMode].mode;
   2046 					testParameters.format			= VK_FORMAT_R8G8B8A8_UNORM;
   2047 					testParameters.programs.push_back(PROGRAM_3D_FLOAT);
   2048 
   2049 					for (int size = 0; size < sizeEnd; size++)
   2050 					{
   2051 						testParameters.width			= tex3DSizes[size].width;
   2052 						testParameters.height			= tex3DSizes[size].height;
   2053 						testParameters.depth			= tex3DSizes[size].depth;
   2054 
   2055 						std::ostringstream name;
   2056 						name << minFilterModes[minFilter].name
   2057 							 << "_" << wrapModes[wrapMode].name;
   2058 
   2059 						if (tex3DSizes[size].name)
   2060 							name << "_" << tex3DSizes[size].name;
   2061 
   2062 						coordTypeGroup->addChild(new TextureTestCase<Texture3DMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
   2063 					}
   2064 				}
   2065 			}
   2066 
   2067 			group3D->addChild(coordTypeGroup.release());
   2068 		}
   2069 
   2070 		// 3D bias variants.
   2071 		{
   2072 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   2073 			{
   2074 				Texture3DMipmapTestCaseParameters	testParameters;
   2075 				testParameters.coordType			= COORDTYPE_BASIC_BIAS;
   2076 				testParameters.minFilter			= minFilterModes[minFilter].mode;
   2077 				testParameters.wrapR				= Sampler::REPEAT_GL;
   2078 				testParameters.wrapS				= Sampler::REPEAT_GL;
   2079 				testParameters.wrapT				= Sampler::REPEAT_GL;
   2080 				testParameters.format				= VK_FORMAT_R8G8B8A8_UNORM;
   2081 				testParameters.width				= tex3DSizes[0].width;
   2082 				testParameters.height				= tex3DSizes[0].height;
   2083 				testParameters.depth				= tex3DSizes[0].depth;
   2084 
   2085 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
   2086 				testParameters.programs.push_back(PROGRAM_3D_FLOAT_BIAS);
   2087 
   2088 				biasGroup3D->addChild(new TextureTestCase<Texture3DMipmapTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   2089 			}
   2090 		}
   2091 
   2092 		// 3D LOD controls.
   2093 		{
   2094 			// MIN_LOD
   2095 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   2096 			{
   2097 				Texture3DMipmapTestCaseParameters	testParameters;
   2098 				testParameters.minFilter			= minFilterModes[minFilter].mode;
   2099 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
   2100 
   2101 				minLodGroup3D->addChild(new TextureTestCase<Texture3DMinLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   2102 			}
   2103 
   2104 			// MAX_LOD
   2105 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   2106 			{
   2107 				Texture3DMipmapTestCaseParameters	testParameters;
   2108 				testParameters.minFilter			= minFilterModes[minFilter].mode;
   2109 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
   2110 
   2111 				maxLodGroup3D->addChild(new TextureTestCase<Texture3DMaxLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   2112 			}
   2113 		}
   2114 
   2115 		{
   2116 			// BASE_LEVEL
   2117 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   2118 			{
   2119 				Texture3DMipmapTestCaseParameters	testParameters;
   2120 				testParameters.minFilter			= minFilterModes[minFilter].mode;
   2121 				testParameters.minFilterName		= minFilterModes[minFilter].name;
   2122 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
   2123 
   2124 				baseLevelGroup3D->addChild(new TextureTestCase<Texture3DBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   2125 			}
   2126 
   2127 			// MAX_LEVEL
   2128 			for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
   2129 			{
   2130 				Texture3DMipmapTestCaseParameters	testParameters;
   2131 				testParameters.minFilter			= minFilterModes[minFilter].mode;
   2132 				testParameters.minFilterName		= minFilterModes[minFilter].name;
   2133 				testParameters.programs.push_back(PROGRAM_3D_FLOAT);
   2134 
   2135 				maxLevelGroup3D->addChild(new TextureTestCase<Texture3DMaxLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
   2136 			}
   2137 		}
   2138 
   2139 		group3D->addChild(biasGroup3D.release());
   2140 		group3D->addChild(minLodGroup3D.release());
   2141 		group3D->addChild(maxLodGroup3D.release());
   2142 		group3D->addChild(baseLevelGroup3D.release());
   2143 		group3D->addChild(maxLevelGroup3D.release());
   2144 
   2145 		textureMipmappingTests->addChild(group3D.release());
   2146 	}
   2147 }
   2148 
   2149 } // anonymous
   2150 
   2151 tcu::TestCaseGroup* createTextureMipmappingTests (tcu::TestContext& testCtx)
   2152 {
   2153 	return createTestGroup(testCtx, "mipmap", "Texture mipmapping tests.", populateTextureMipmappingTests);
   2154 }
   2155 
   2156 } // texture
   2157 } // vkt
   2158