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
42using namespace vk;
43
44namespace vkt
45{
46namespace texture
47{
48namespace
49{
50
51using std::string;
52using std::vector;
53using tcu::TestLog;
54using tcu::Vec2;
55using tcu::Vec3;
56using tcu::Vec4;
57using tcu::IVec4;
58using tcu::Sampler;
59using tcu::TextureFormat;
60using namespace texture::util;
61using namespace glu::TextureTestUtil;
62
63float 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
87float 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
112enum 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
122struct TextureMipmapCommonTestCaseParameters
123{
124							TextureMipmapCommonTestCaseParameters		(void);
125	CoordType				coordType;
126	const char*				minFilterName;
127};
128
129TextureMipmapCommonTestCaseParameters::TextureMipmapCommonTestCaseParameters (void)
130	: coordType				(COORDTYPE_BASIC)
131	, minFilterName			(NULL)
132{
133}
134
135struct Texture2DMipmapTestCaseParameters : public Texture2DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
136{
137};
138
139struct TextureCubeMipmapTestCaseParameters : public TextureCubeTestCaseParameters, public TextureMipmapCommonTestCaseParameters
140{
141};
142
143struct Texture3DMipmapTestCaseParameters : public Texture3DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
144{
145};
146
147// Texture2DMipmapTestInstance
148class Texture2DMipmapTestInstance : public TestInstance
149{
150public:
151	typedef Texture2DMipmapTestCaseParameters	ParameterType;
152
153									Texture2DMipmapTestInstance		(Context& context, const ParameterType& testParameters);
154									~Texture2DMipmapTestInstance	(void);
155
156	virtual tcu::TestStatus			iterate							(void);
157
158private:
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
167Texture2DMipmapTestInstance::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
194Texture2DMipmapTestInstance::~Texture2DMipmapTestInstance (void)
195{
196}
197
198static 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
235static 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
260tcu::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
409class TextureCubeMipmapTestInstance : public TestInstance
410{
411public:
412	typedef	TextureCubeMipmapTestCaseParameters	ParameterType;
413
414									TextureCubeMipmapTestInstance	(Context& context, const ParameterType& testParameters);
415									~TextureCubeMipmapTestInstance	(void);
416
417	virtual tcu::TestStatus			iterate							(void);
418
419private:
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
428TextureCubeMipmapTestInstance::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
467TextureCubeMipmapTestInstance::~TextureCubeMipmapTestInstance (void)
468{
469}
470
471static 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
496static 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
502tcu::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
648class Texture3DMipmapTestInstance : public TestInstance
649{
650public:
651	typedef Texture3DMipmapTestCaseParameters	ParameterType;
652
653									Texture3DMipmapTestInstance		(Context& context, const ParameterType& testParameters);
654									~Texture3DMipmapTestInstance	(void);
655
656	virtual tcu::TestStatus			iterate							(void);
657
658private:
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
667Texture3DMipmapTestInstance::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
697Texture3DMipmapTestInstance::~Texture3DMipmapTestInstance (void)
698{
699}
700
701static 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
747static 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
768tcu::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
922class Texture2DLodControlTestInstance : public TestInstance
923{
924public:
925	typedef Texture2DMipmapTestCaseParameters	ParameterType;
926
927										Texture2DLodControlTestInstance		(Context& context, const ParameterType& testParameters);
928										~Texture2DLodControlTestInstance	(void);
929
930	virtual tcu::TestStatus				iterate								(void);
931
932protected:
933	virtual void						getReferenceParams					(ReferenceParams& params, int cellNdx) = 0;
934
935	const int							m_texWidth;
936	const int							m_texHeight;
937
938private:
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
948Texture2DLodControlTestInstance::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
977Texture2DLodControlTestInstance::~Texture2DLodControlTestInstance (void)
978{
979}
980
981tcu::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
1092class Texture2DMinLodTestInstance : public Texture2DLodControlTestInstance
1093{
1094public:
1095	Texture2DMinLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
1096		: Texture2DLodControlTestInstance(context, testParameters)
1097	{
1098	}
1099
1100protected:
1101	void getReferenceParams (ReferenceParams& params, int cellNdx)
1102	{
1103		params.minLod = getMinLodForCell(cellNdx);
1104	}
1105};
1106
1107class Texture2DMaxLodTestInstance : public Texture2DLodControlTestInstance
1108{
1109public:
1110	Texture2DMaxLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
1111		: Texture2DLodControlTestInstance(context, testParameters)
1112	{
1113	}
1114
1115protected:
1116	void getReferenceParams (ReferenceParams& params, int cellNdx)
1117	{
1118		params.maxLod = getMaxLodForCell(cellNdx);
1119	}
1120};
1121
1122class Texture2DBaseLevelTestInstance : public Texture2DLodControlTestInstance
1123{
1124public:
1125	Texture2DBaseLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
1126		: Texture2DLodControlTestInstance(context, testParameters)
1127		, m_testParam (testParameters)
1128	{
1129	}
1130
1131protected:
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
1148class Texture2DMaxLevelTestInstance : public Texture2DLodControlTestInstance
1149{
1150public:
1151	Texture2DMaxLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
1152		: Texture2DLodControlTestInstance(context, testParameters)
1153		, m_testParam (testParameters)
1154	{
1155	}
1156
1157protected:
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
1175class TextureCubeLodControlTestInstance : public TestInstance
1176{
1177public:
1178	typedef TextureCubeMipmapTestCaseParameters	ParameterType;
1179
1180										TextureCubeLodControlTestInstance	(Context& context, const ParameterType& testParameters);
1181										~TextureCubeLodControlTestInstance	(void);
1182
1183	virtual tcu::TestStatus				iterate								(void);
1184
1185protected:
1186	virtual void						getReferenceParams					(ReferenceParams& params, int cellNdx)	= DE_NULL;
1187
1188	const int							m_texSize;
1189
1190private:
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
1200TextureCubeLodControlTestInstance::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
1242TextureCubeLodControlTestInstance::~TextureCubeLodControlTestInstance (void)
1243{
1244}
1245
1246tcu::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
1353class TextureCubeMinLodTestInstance : public TextureCubeLodControlTestInstance
1354{
1355public:
1356	TextureCubeMinLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
1357		: TextureCubeLodControlTestInstance(context, testParameters)
1358	{
1359	}
1360
1361protected:
1362	void getReferenceParams (ReferenceParams& params, int cellNdx)
1363	{
1364		params.minLod = getMinLodForCell(cellNdx);
1365	}
1366};
1367
1368class TextureCubeMaxLodTestInstance : public TextureCubeLodControlTestInstance
1369{
1370public:
1371	TextureCubeMaxLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
1372		: TextureCubeLodControlTestInstance(context, testParameters)
1373	{
1374	}
1375
1376protected:
1377	void getReferenceParams (ReferenceParams& params, int cellNdx)
1378	{
1379		params.maxLod = getMaxLodForCell(cellNdx);
1380	}
1381};
1382
1383class TextureCubeBaseLevelTestInstance : public TextureCubeLodControlTestInstance
1384{
1385public:
1386	TextureCubeBaseLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
1387		: TextureCubeLodControlTestInstance(context, testParameters)
1388		, m_testParam (testParameters)
1389	{
1390	}
1391
1392protected:
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
1409class TextureCubeMaxLevelTestInstance : public TextureCubeLodControlTestInstance
1410{
1411public:
1412	TextureCubeMaxLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
1413		: TextureCubeLodControlTestInstance(context, testParameters)
1414		, m_testParam (testParameters)
1415	{
1416	}
1417
1418protected:
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
1435class Texture3DLodControlTestInstance : public TestInstance
1436{
1437public:
1438	typedef Texture3DMipmapTestCaseParameters	ParameterType;
1439
1440										Texture3DLodControlTestInstance		(Context& context, const ParameterType& testParameters);
1441										~Texture3DLodControlTestInstance	(void);
1442
1443	virtual tcu::TestStatus				iterate								(void);
1444
1445protected:
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
1452private:
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
1462Texture3DLodControlTestInstance::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
1495Texture3DLodControlTestInstance::~Texture3DLodControlTestInstance (void)
1496{
1497}
1498
1499tcu::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
1619class Texture3DMinLodTestInstance : public Texture3DLodControlTestInstance
1620{
1621public:
1622	Texture3DMinLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
1623		: Texture3DLodControlTestInstance(context, testParameters)
1624	{
1625	}
1626
1627protected:
1628	void getReferenceParams (ReferenceParams& params, int cellNdx)
1629	{
1630		params.minLod = getMinLodForCell(cellNdx);
1631	}
1632};
1633
1634class Texture3DMaxLodTestInstance : public Texture3DLodControlTestInstance
1635{
1636public:
1637	Texture3DMaxLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
1638		: Texture3DLodControlTestInstance(context, testParameters)
1639	{
1640	}
1641
1642protected:
1643	void getReferenceParams (ReferenceParams& params, int cellNdx)
1644	{
1645		params.maxLod = getMaxLodForCell(cellNdx);
1646	}
1647};
1648
1649class Texture3DBaseLevelTestInstance : public Texture3DLodControlTestInstance
1650{
1651public:
1652	Texture3DBaseLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
1653		: Texture3DLodControlTestInstance(context, testParameters)
1654		,m_testParam (testParameters)
1655	{
1656	}
1657
1658protected:
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
1675class Texture3DMaxLevelTestInstance : public Texture3DLodControlTestInstance
1676{
1677public:
1678	Texture3DMaxLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
1679		: Texture3DLodControlTestInstance(context, testParameters)
1680		,m_testParam (testParameters)
1681	{
1682	}
1683
1684protected:
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
1701void 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
2151tcu::TestCaseGroup* createTextureMipmappingTests (tcu::TestContext& testCtx)
2152{
2153	return createTestGroup(testCtx, "mipmap", "Texture mipmapping tests.", populateTextureMipmappingTests);
2154}
2155
2156} // texture
2157} // vkt
2158