1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Mipmapping tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2fTextureMipmapTests.hpp"
25#include "glsTextureTestUtil.hpp"
26#include "gluTexture.hpp"
27#include "gluStrUtil.hpp"
28#include "gluTextureUtil.hpp"
29#include "gluPixelTransfer.hpp"
30#include "tcuTestLog.hpp"
31#include "tcuTextureUtil.hpp"
32#include "tcuVector.hpp"
33#include "tcuMatrix.hpp"
34#include "tcuMatrixUtil.hpp"
35#include "tcuTexLookupVerifier.hpp"
36#include "tcuVectorUtil.hpp"
37#include "deStringUtil.hpp"
38#include "deRandom.hpp"
39#include "glwFunctions.hpp"
40#include "glwEnums.hpp"
41
42namespace deqp
43{
44namespace gles2
45{
46namespace Functional
47{
48
49using tcu::TestLog;
50using std::vector;
51using std::string;
52using tcu::Sampler;
53using tcu::Vec2;
54using tcu::Mat2;
55using tcu::Vec4;
56using tcu::IVec2;
57using tcu::IVec4;
58using namespace glu;
59using namespace gls::TextureTestUtil;
60
61enum CoordType
62{
63	COORDTYPE_BASIC,		//!< texCoord = translateScale(position).
64	COORDTYPE_BASIC_BIAS,	//!< Like basic, but with bias values.
65	COORDTYPE_AFFINE,		//!< texCoord = translateScaleRotateShear(position).
66	COORDTYPE_PROJECTED,	//!< Projected coordinates, w != 1
67
68	COORDTYPE_LAST
69};
70
71// Texture2DMipmapCase
72
73class Texture2DMipmapCase : public tcu::TestCase
74{
75public:
76
77								Texture2DMipmapCase			(tcu::TestContext&			testCtx,
78															 glu::RenderContext&		renderCtx,
79															 const glu::ContextInfo&	renderCtxInfo,
80															 const char*				name,
81															 const char*				desc,
82															 CoordType					coordType,
83															 deUint32					minFilter,
84															 deUint32					wrapS,
85															 deUint32					wrapT,
86															 deUint32					format,
87															 deUint32					dataType,
88															 int						width,
89															 int						height);
90								~Texture2DMipmapCase		(void);
91
92	void						init						(void);
93	void						deinit						(void);
94	IterateResult				iterate						(void);
95
96private:
97								Texture2DMipmapCase			(const Texture2DMipmapCase& other);
98	Texture2DMipmapCase&		operator=					(const Texture2DMipmapCase& other);
99
100	glu::RenderContext&			m_renderCtx;
101	const glu::ContextInfo&		m_renderCtxInfo;
102
103	CoordType					m_coordType;
104	deUint32					m_minFilter;
105	deUint32					m_wrapS;
106	deUint32					m_wrapT;
107	deUint32					m_format;
108	deUint32					m_dataType;
109	int							m_width;
110	int							m_height;
111
112	glu::Texture2D*				m_texture;
113	TextureRenderer				m_renderer;
114};
115
116Texture2DMipmapCase::Texture2DMipmapCase (tcu::TestContext&			testCtx,
117										  glu::RenderContext&		renderCtx,
118										  const glu::ContextInfo&	renderCtxInfo,
119										  const char*				name,
120										  const char*				desc,
121										  CoordType					coordType,
122										  deUint32					minFilter,
123										  deUint32					wrapS,
124										  deUint32					wrapT,
125										  deUint32					format,
126										  deUint32					dataType,
127										  int						width,
128										  int						height)
129	: TestCase			(testCtx, name, desc)
130	, m_renderCtx		(renderCtx)
131	, m_renderCtxInfo	(renderCtxInfo)
132	, m_coordType		(coordType)
133	, m_minFilter		(minFilter)
134	, m_wrapS			(wrapS)
135	, m_wrapT			(wrapT)
136	, m_format			(format)
137	, m_dataType		(dataType)
138	, m_width			(width)
139	, m_height			(height)
140	, m_texture			(DE_NULL)
141	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES,
142						 renderCtxInfo.isFragmentHighPrecisionSupported() ? glu::PRECISION_HIGHP // Use highp if available.
143																		  : glu::PRECISION_MEDIUMP)
144{
145}
146
147Texture2DMipmapCase::~Texture2DMipmapCase (void)
148{
149	deinit();
150}
151
152void Texture2DMipmapCase::init (void)
153{
154	if (!m_renderCtxInfo.isFragmentHighPrecisionSupported())
155		m_testCtx.getLog() << TestLog::Message << "Warning: High precision not supported in fragment shaders." << TestLog::EndMessage;
156
157	if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
158		throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
159
160	m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
161
162	int numLevels = deLog2Floor32(de::max(m_width, m_height))+1;
163
164	// Fill texture with colored grid.
165	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
166	{
167		deUint32	step		= 0xff / (numLevels-1);
168		deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
169		deUint32	dec			= 0xff - inc;
170		deUint32	rgb			= (inc << 16) | (dec << 8) | 0xff;
171		deUint32	color		= 0xff000000 | rgb;
172
173		m_texture->getRefTexture().allocLevel(levelNdx);
174		tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), toVec4(tcu::RGBA(color)));
175	}
176}
177
178void Texture2DMipmapCase::deinit (void)
179{
180	delete m_texture;
181	m_texture = DE_NULL;
182
183	m_renderer.clear();
184}
185
186static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
187{
188	static const struct
189	{
190		Vec2 bottomLeft;
191		Vec2 topRight;
192	} s_basicCoords[] =
193	{
194		{ Vec2(-0.1f,  0.1f), Vec2( 0.8f,  1.0f) },
195		{ Vec2(-0.3f, -0.6f), Vec2( 0.7f,  0.4f) },
196		{ Vec2(-0.3f,  0.6f), Vec2( 0.7f, -0.9f) },
197		{ Vec2(-0.8f,  0.6f), Vec2( 0.7f, -0.9f) },
198
199		{ Vec2(-0.5f, -0.5f), Vec2( 1.5f,  1.5f) },
200		{ Vec2( 1.0f, -1.0f), Vec2(-1.3f,  1.0f) },
201		{ Vec2( 1.2f, -1.0f), Vec2(-1.3f,  1.6f) },
202		{ Vec2( 2.2f, -1.1f), Vec2(-1.3f,  0.8f) },
203
204		{ Vec2(-1.5f,  1.6f), Vec2( 1.7f, -1.4f) },
205		{ Vec2( 2.0f,  1.6f), Vec2( 2.3f, -1.4f) },
206		{ Vec2( 1.3f, -2.6f), Vec2(-2.7f,  2.9f) },
207		{ Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
208
209		{ Vec2( -8.0f,   9.0f), Vec2(  8.3f,  -7.0f) },
210		{ Vec2(-16.0f,  10.0f), Vec2( 18.3f,  24.0f) },
211		{ Vec2( 30.2f,  55.0f), Vec2(-24.3f,  -1.6f) },
212		{ Vec2(-33.2f,  64.1f), Vec2( 32.1f, -64.1f) },
213	};
214
215	DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
216
217	const Vec2& bottomLeft	= s_basicCoords[cellNdx].bottomLeft;
218	const Vec2& topRight	= s_basicCoords[cellNdx].topRight;
219
220	computeQuadTexCoord2D(dst, bottomLeft, topRight);
221}
222
223static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
224{
225	// Use basic coords as base.
226	getBasicTexCoord2D(dst, cellNdx);
227
228	// Rotate based on cell index.
229	float		angle		= 2.0f*DE_PI * ((float)cellNdx / 16.0f);
230	tcu::Mat2	rotMatrix	= tcu::rotationMatrix(angle);
231
232	// Second and third row are sheared.
233	float		shearX		= de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
234	tcu::Mat2	shearMatrix	= tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
235
236	tcu::Mat2	transform	= rotMatrix * shearMatrix;
237	Vec2		p0			= transform * Vec2(dst[0], dst[1]);
238	Vec2		p1			= transform * Vec2(dst[2], dst[3]);
239	Vec2		p2			= transform * Vec2(dst[4], dst[5]);
240	Vec2		p3			= transform * Vec2(dst[6], dst[7]);
241
242	dst[0] = p0.x();	dst[1] = p0.y();
243	dst[2] = p1.x();	dst[3] = p1.y();
244	dst[4] = p2.x();	dst[5] = p2.y();
245	dst[6] = p3.x();	dst[7] = p3.y();
246}
247
248Texture2DMipmapCase::IterateResult Texture2DMipmapCase::iterate (void)
249{
250	const glw::Functions&		gl					= m_renderCtx.getFunctions();
251
252	const tcu::Texture2D&		refTexture			= m_texture->getRefTexture();
253
254	const deUint32				magFilter			= GL_NEAREST;
255	const int					texWidth			= refTexture.getWidth();
256	const int					texHeight			= refTexture.getHeight();
257	const int					defViewportWidth	= texWidth*4;
258	const int					defViewportHeight	= texHeight*4;
259
260	const RandomViewport		viewport			(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
261	ReferenceParams				sampleParams		(TEXTURETYPE_2D);
262	vector<float>				texCoord;
263
264	const bool					isProjected			= m_coordType == COORDTYPE_PROJECTED;
265	const bool					useLodBias			= m_coordType == COORDTYPE_BASIC_BIAS;
266
267	tcu::Surface				renderedFrame		(viewport.width, viewport.height);
268
269	// Viewport is divided into 4x4 grid.
270	int							gridWidth			= 4;
271	int							gridHeight			= 4;
272	int							cellWidth			= viewport.width / gridWidth;
273	int							cellHeight			= viewport.height / gridHeight;
274
275	// Bail out if rendertarget is too small.
276	if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
277		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
278
279	// Sampling parameters.
280	sampleParams.sampler		= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
281	sampleParams.samplerType	= gls::TextureTestUtil::getSamplerType(m_texture->getRefTexture().getFormat());
282	sampleParams.flags			= (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
283	sampleParams.lodMode		= LODMODE_EXACT; // Use ideal lod.
284
285	// Upload texture data.
286	m_texture->upload();
287
288	// Bind gradient texture and setup sampler parameters.
289	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
290	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
291	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
292	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
293	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
294
295	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
296
297	// Bias values.
298	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
299
300	// Projection values.
301	static const Vec4 s_projections[] =
302	{
303		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
304		Vec4(1.3f, 0.8f, 0.6f, 2.0f),
305		Vec4(0.8f, 1.0f, 1.7f, 0.6f),
306		Vec4(1.2f, 1.0f, 1.7f, 1.5f)
307	};
308
309	// Render cells.
310	for (int gridY = 0; gridY < gridHeight; gridY++)
311	{
312		for (int gridX = 0; gridX < gridWidth; gridX++)
313		{
314			const int		curX		= cellWidth*gridX;
315			const int		curY		= cellHeight*gridY;
316			const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
317			const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
318			const int		cellNdx		= gridY*gridWidth + gridX;
319
320			// Compute texcoord.
321			switch (m_coordType)
322			{
323				case COORDTYPE_BASIC_BIAS:	// Fall-through.
324				case COORDTYPE_PROJECTED:
325				case COORDTYPE_BASIC:		getBasicTexCoord2D	(texCoord, cellNdx);	break;
326				case COORDTYPE_AFFINE:		getAffineTexCoord2D	(texCoord, cellNdx);	break;
327				default:					DE_ASSERT(DE_FALSE);
328			}
329
330			if (isProjected)
331				sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
332
333			if (useLodBias)
334				sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
335
336			// Render with GL.
337			gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
338			m_renderer.renderQuad(0, &texCoord[0], sampleParams);
339		}
340	}
341
342	// Read result.
343	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
344
345	// Compare and log.
346	{
347		const tcu::PixelFormat&	pixelFormat		= m_renderCtx.getRenderTarget().getPixelFormat();
348		const bool				isTrilinear		= m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
349		tcu::Surface			referenceFrame	(viewport.width, viewport.height);
350		tcu::Surface			errorMask		(viewport.width, viewport.height);
351		tcu::LookupPrecision	lookupPrec;
352		tcu::LodPrecision		lodPrec;
353		int						numFailedPixels	= 0;
354
355		lookupPrec.coordBits		= tcu::IVec3(20, 20, 0);
356		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
357		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
358		lookupPrec.colorMask		= getCompareMask(pixelFormat);
359		lodPrec.derivateBits		= 10;
360		lodPrec.lodBits				= isProjected ? 6 : 8;
361
362		for (int gridY = 0; gridY < gridHeight; gridY++)
363		{
364			for (int gridX = 0; gridX < gridWidth; gridX++)
365			{
366				const int		curX		= cellWidth*gridX;
367				const int		curY		= cellHeight*gridY;
368				const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
369				const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
370				const int		cellNdx		= gridY*gridWidth + gridX;
371
372				// Compute texcoord.
373				switch (m_coordType)
374				{
375					case COORDTYPE_BASIC_BIAS:	// Fall-through.
376					case COORDTYPE_PROJECTED:
377					case COORDTYPE_BASIC:		getBasicTexCoord2D	(texCoord, cellNdx);	break;
378					case COORDTYPE_AFFINE:		getAffineTexCoord2D	(texCoord, cellNdx);	break;
379					default:					DE_ASSERT(DE_FALSE);
380				}
381
382				if (isProjected)
383					sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
384
385				if (useLodBias)
386					sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
387
388				// Render ideal result
389				sampleTexture(SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
390							  refTexture, &texCoord[0], sampleParams);
391
392				// Compare this cell
393				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
394															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
395															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
396															m_texture->getRefTexture(), &texCoord[0], sampleParams,
397															lookupPrec, lodPrec, m_testCtx.getWatchDog());
398			}
399		}
400
401		if (numFailedPixels > 0)
402			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
403
404		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
405							<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
406
407		if (numFailedPixels > 0)
408		{
409			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
410								<< TestLog::Image("ErrorMask", "Error mask", errorMask);
411		}
412
413		m_testCtx.getLog() << TestLog::EndImageSet;
414
415		{
416			const bool isOk = numFailedPixels == 0;
417			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
418									isOk ? "Pass"				: "Image verification failed");
419		}
420	}
421
422	return STOP;
423}
424
425// TextureCubeMipmapCase
426
427class TextureCubeMipmapCase : public tcu::TestCase
428{
429public:
430
431								TextureCubeMipmapCase		(tcu::TestContext&			testCtx,
432															 glu::RenderContext&		renderCtx,
433															 const glu::ContextInfo&	renderCtxInfo,
434															 const char*				name,
435															 const char*				desc,
436															 CoordType					coordType,
437															 deUint32					minFilter,
438															 deUint32					wrapS,
439															 deUint32					wrapT,
440															 deUint32					format,
441															 deUint32					dataType,
442															 int						size);
443								~TextureCubeMipmapCase		(void);
444
445	void						init						(void);
446	void						deinit						(void);
447	IterateResult				iterate						(void);
448
449private:
450								TextureCubeMipmapCase		(const TextureCubeMipmapCase& other);
451	TextureCubeMipmapCase&		operator=					(const TextureCubeMipmapCase& other);
452
453	glu::RenderContext&			m_renderCtx;
454	const glu::ContextInfo&		m_renderCtxInfo;
455
456	CoordType					m_coordType;
457	deUint32					m_minFilter;
458	deUint32					m_wrapS;
459	deUint32					m_wrapT;
460	deUint32					m_format;
461	deUint32					m_dataType;
462	int							m_size;
463
464	glu::TextureCube*			m_texture;
465	TextureRenderer				m_renderer;
466};
467
468TextureCubeMipmapCase::TextureCubeMipmapCase (tcu::TestContext&			testCtx,
469											  glu::RenderContext&		renderCtx,
470											  const glu::ContextInfo&	renderCtxInfo,
471											  const char*				name,
472											  const char*				desc,
473											  CoordType					coordType,
474											  deUint32					minFilter,
475											  deUint32					wrapS,
476											  deUint32					wrapT,
477											  deUint32					format,
478											  deUint32					dataType,
479											  int						size)
480	: TestCase			(testCtx, name, desc)
481	, m_renderCtx		(renderCtx)
482	, m_renderCtxInfo	(renderCtxInfo)
483	, m_coordType		(coordType)
484	, m_minFilter		(minFilter)
485	, m_wrapS			(wrapS)
486	, m_wrapT			(wrapT)
487	, m_format			(format)
488	, m_dataType		(dataType)
489	, m_size			(size)
490	, m_texture			(DE_NULL)
491	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES,
492						 renderCtxInfo.isFragmentHighPrecisionSupported() ? glu::PRECISION_HIGHP // Use highp if available.
493																		  : glu::PRECISION_MEDIUMP)
494{
495}
496
497TextureCubeMipmapCase::~TextureCubeMipmapCase (void)
498{
499	deinit();
500}
501
502void TextureCubeMipmapCase::init (void)
503{
504	if (!m_renderCtxInfo.isFragmentHighPrecisionSupported())
505		m_testCtx.getLog() << TestLog::Message << "Warning: High precision not supported in fragment shaders." << TestLog::EndMessage;
506
507	if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
508		throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
509
510	m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_size);
511
512	int numLevels = deLog2Floor32(m_size)+1;
513
514	// Fill texture with colored grid.
515	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
516	{
517		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
518		{
519			deUint32	step		= 0xff / (numLevels-1);
520			deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
521			deUint32	dec			= 0xff - inc;
522			deUint32	rgb			= 0;
523
524			switch (faceNdx)
525			{
526				case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
527				case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
528				case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
529				case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
530				case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
531				case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
532			}
533
534			deUint32	color		= 0xff000000 | rgb;
535
536			m_texture->getRefTexture().allocLevel((tcu::CubeFace)faceNdx, levelNdx);
537			tcu::clear(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), toVec4(tcu::RGBA(color)));
538		}
539	}
540}
541
542void TextureCubeMipmapCase::deinit (void)
543{
544	delete m_texture;
545	m_texture = DE_NULL;
546
547	m_renderer.clear();
548}
549
550static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
551{
552	const int minWidth	= 8;
553	const int minHeight	= 8;
554
555	bool	partition		= rnd.getFloat() > 0.4f;
556	bool	partitionX		= partition && width > minWidth && rnd.getBool();
557	bool	partitionY		= partition && height > minHeight && !partitionX;
558
559	if (partitionX)
560	{
561		int split = width/2 + rnd.getInt(-width/4, +width/4);
562		randomPartition(dst, rnd, x, y, split, height);
563		randomPartition(dst, rnd, x+split, y, width-split, height);
564	}
565	else if (partitionY)
566	{
567		int split = height/2 + rnd.getInt(-height/4, +height/4);
568		randomPartition(dst, rnd, x, y, width, split);
569		randomPartition(dst, rnd, x, y+split, width, height-split);
570	}
571	else
572		dst.push_back(IVec4(x, y, width, height));
573}
574
575static void computeGridLayout (vector<IVec4>& dst, int width, int height)
576{
577	de::Random rnd(7);
578	randomPartition(dst, rnd, 0, 0, width, height);
579}
580
581TextureCubeMipmapCase::IterateResult TextureCubeMipmapCase::iterate (void)
582{
583	const deUint32			magFilter			= GL_NEAREST;
584	const int				texWidth			= m_texture->getRefTexture().getSize();
585	const int				texHeight			= m_texture->getRefTexture().getSize();
586	const int				defViewportWidth	= texWidth*2;
587	const int				defViewportHeight	= texHeight*2;
588
589	const glw::Functions&	gl					= m_renderCtx.getFunctions();
590	const RandomViewport	viewport			(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
591
592	const bool				isProjected			= m_coordType == COORDTYPE_PROJECTED;
593	const bool				useLodBias			= m_coordType == COORDTYPE_BASIC_BIAS;
594
595	vector<float>			texCoord;
596	tcu::Surface			renderedFrame		(viewport.width, viewport.height);
597
598	// Bail out if rendertarget is too small.
599	if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
600		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
601
602	// Upload texture data.
603	m_texture->upload();
604
605	// Bind gradient texture and setup sampler parameters.
606	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
607	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
608	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
609	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
610	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
611
612	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
613
614	// Compute grid.
615	vector<IVec4> gridLayout;
616	computeGridLayout(gridLayout, viewport.width, viewport.height);
617
618	// Bias values.
619	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
620
621	// Projection values \note Less agressive than in 2D case due to smaller quads.
622	static const Vec4 s_projections[] =
623	{
624		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
625		Vec4(1.3f, 0.8f, 0.6f, 1.1f),
626		Vec4(0.8f, 1.0f, 1.2f, 0.8f),
627		Vec4(1.2f, 1.0f, 1.3f, 0.9f)
628	};
629
630	// Render with GL
631	for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
632	{
633		const int			curX		= gridLayout[cellNdx].x();
634		const int			curY		= gridLayout[cellNdx].y();
635		const int			curW		= gridLayout[cellNdx].z();
636		const int			curH		= gridLayout[cellNdx].w();
637		const tcu::CubeFace	cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
638		RenderParams		params		(TEXTURETYPE_CUBE);
639
640		DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
641		computeQuadTexCoordCube(texCoord, cubeFace);
642
643		if (isProjected)
644		{
645			params.flags	|= ReferenceParams::PROJECTED;
646			params.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
647		}
648
649		if (useLodBias)
650		{
651			params.flags	|= ReferenceParams::USE_BIAS;
652			params.bias		 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
653		}
654
655		// Render with GL.
656		gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
657		m_renderer.renderQuad(0, &texCoord[0], params);
658	}
659	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
660
661	// Read result.
662	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
663	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
664
665	// Render reference and compare
666	{
667		tcu::Surface			referenceFrame		(viewport.width, viewport.height);
668		tcu::Surface			errorMask			(viewport.width, viewport.height);
669		int						numFailedPixels		= 0;
670		ReferenceParams			params				(TEXTURETYPE_CUBE);
671		tcu::LookupPrecision	lookupPrec;
672		tcu::LodPrecision		lodPrec;
673
674		// Params for rendering reference
675		params.sampler					= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
676		params.sampler.seamlessCubeMap	= false;
677		params.lodMode					= LODMODE_EXACT;
678
679		// Comparison parameters
680		lookupPrec.colorMask			= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
681		lookupPrec.colorThreshold		= tcu::computeFixedPointThreshold(max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0)));
682		lookupPrec.coordBits			= isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
683		lookupPrec.uvwBits				= tcu::IVec3(5,5,0);
684		lodPrec.derivateBits			= 10;
685		lodPrec.lodBits					= isProjected ? 4 : 6;
686
687		for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
688		{
689			const int				curX		= gridLayout[cellNdx].x();
690			const int				curY		= gridLayout[cellNdx].y();
691			const int				curW		= gridLayout[cellNdx].z();
692			const int				curH		= gridLayout[cellNdx].w();
693			const tcu::CubeFace		cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
694
695			DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
696			computeQuadTexCoordCube(texCoord, cubeFace);
697
698			if (isProjected)
699			{
700				params.flags	|= ReferenceParams::PROJECTED;
701				params.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
702			}
703
704			if (useLodBias)
705			{
706				params.flags	|= ReferenceParams::USE_BIAS;
707				params.bias		 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
708			}
709
710			// Render ideal reference.
711			{
712				SurfaceAccess idealDst(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
713				sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
714			}
715
716			// Compare this cell
717			numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
718														tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
719														tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
720														m_texture->getRefTexture(), &texCoord[0], params,
721														lookupPrec, lodPrec, m_testCtx.getWatchDog());
722		}
723
724		if (numFailedPixels > 0)
725			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
726
727		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
728						   << TestLog::Image("Rendered", "Rendered image", renderedFrame);
729
730		if (numFailedPixels > 0)
731		{
732			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
733							   << TestLog::Image("ErrorMask", "Error mask", errorMask);
734		}
735
736		m_testCtx.getLog() << TestLog::EndImageSet;
737
738		{
739			const bool isOk = numFailedPixels == 0;
740			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
741									isOk ? "Pass"				: "Image verification failed");
742		}
743	}
744
745	return STOP;
746}
747
748// Texture2DGenMipmapCase
749
750class Texture2DGenMipmapCase : public tcu::TestCase
751{
752public:
753
754								Texture2DGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height);
755								~Texture2DGenMipmapCase		(void);
756
757	void						init						(void);
758	void						deinit						(void);
759	IterateResult				iterate						(void);
760
761private:
762								Texture2DGenMipmapCase		(const Texture2DGenMipmapCase& other);
763	Texture2DGenMipmapCase&		operator=					(const Texture2DGenMipmapCase& other);
764
765	glu::RenderContext&			m_renderCtx;
766
767	deUint32					m_format;
768	deUint32					m_dataType;
769	deUint32					m_hint;
770	int							m_width;
771	int							m_height;
772
773	glu::Texture2D*				m_texture;
774	TextureRenderer				m_renderer;
775};
776
777Texture2DGenMipmapCase::Texture2DGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height)
778	: TestCase			(testCtx, name, desc)
779	, m_renderCtx		(renderCtx)
780	, m_format			(format)
781	, m_dataType		(dataType)
782	, m_hint			(hint)
783	, m_width			(width)
784	, m_height			(height)
785	, m_texture			(DE_NULL)
786	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
787{
788}
789
790Texture2DGenMipmapCase::~Texture2DGenMipmapCase (void)
791{
792	deinit();
793}
794
795void Texture2DGenMipmapCase::init (void)
796{
797	DE_ASSERT(!m_texture);
798	m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
799}
800
801void Texture2DGenMipmapCase::deinit (void)
802{
803	delete m_texture;
804	m_texture = DE_NULL;
805
806	m_renderer.clear();
807}
808
809Texture2DGenMipmapCase::IterateResult Texture2DGenMipmapCase::iterate (void)
810{
811	const glw::Functions&	gl					= m_renderCtx.getFunctions();
812
813	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
814	const deUint32			magFilter			= GL_NEAREST;
815	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
816	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
817
818	const int				numLevels			= deLog2Floor32(de::max(m_width, m_height))+1;
819
820	tcu::Texture2D			resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight());
821
822	vector<float>			texCoord;
823
824	// Initialize texture level 0 with colored grid.
825	m_texture->getRefTexture().allocLevel(0);
826	tcu::fillWithGrid(m_texture->getRefTexture().getLevel(0), 8, tcu::Vec4(1.0f, 0.5f, 0.0f, 0.5f), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
827
828	// Upload data and setup params.
829	m_texture->upload();
830
831	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
832	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		wrapS);
833	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		wrapT);
834	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	minFilter);
835	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
836	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
837
838	// Generate mipmap.
839	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
840	gl.generateMipmap(GL_TEXTURE_2D);
841	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
842
843	// Use (0, 0) -> (1, 1) texture coordinates.
844	computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
845
846	// Fetch resulting texture by rendering.
847	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
848	{
849		const int				levelWidth		= de::max(1, m_width >> levelNdx);
850		const int				levelHeight		= de::max(1, m_height >> levelNdx);
851		const RandomViewport	viewport		(m_renderCtx.getRenderTarget(), levelWidth, levelHeight, deStringHash(getName()) + levelNdx);
852
853		gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
854		m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
855
856		resultTexture.allocLevel(levelNdx);
857		glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevel(levelNdx));
858	}
859
860	// Compare results
861	{
862
863		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
864		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
865		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
866		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
867		GenMipmapPrecision	comparePrec;
868
869		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
870		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
871		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
872
873		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
874
875		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
876											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
877											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
878	}
879
880	return STOP;
881}
882
883// TextureCubeGenMipmapCase
884
885class TextureCubeGenMipmapCase : public tcu::TestCase
886{
887public:
888
889								TextureCubeGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size);
890								~TextureCubeGenMipmapCase		(void);
891
892	void						init							(void);
893	void						deinit							(void);
894	IterateResult				iterate							(void);
895
896private:
897								TextureCubeGenMipmapCase		(const TextureCubeGenMipmapCase& other);
898	TextureCubeGenMipmapCase&	operator=						(const TextureCubeGenMipmapCase& other);
899
900	glu::RenderContext&			m_renderCtx;
901
902	deUint32					m_format;
903	deUint32					m_dataType;
904	deUint32					m_hint;
905	int							m_size;
906
907	glu::TextureCube*			m_texture;
908	TextureRenderer				m_renderer;
909};
910
911TextureCubeGenMipmapCase::TextureCubeGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size)
912	: TestCase			(testCtx, name, desc)
913	, m_renderCtx		(renderCtx)
914	, m_format			(format)
915	, m_dataType		(dataType)
916	, m_hint			(hint)
917	, m_size			(size)
918	, m_texture			(DE_NULL)
919	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
920{
921}
922
923TextureCubeGenMipmapCase::~TextureCubeGenMipmapCase (void)
924{
925	deinit();
926}
927
928void TextureCubeGenMipmapCase::init (void)
929{
930	if (m_renderCtx.getRenderTarget().getWidth() < 3*m_size || m_renderCtx.getRenderTarget().getHeight() < 2*m_size)
931		throw tcu::NotSupportedError("Render target size must be at least (" + de::toString(3*m_size) + ", " + de::toString(2*m_size) + ")");
932
933	DE_ASSERT(!m_texture);
934	m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_size);
935}
936
937void TextureCubeGenMipmapCase::deinit (void)
938{
939	delete m_texture;
940	m_texture = DE_NULL;
941
942	m_renderer.clear();
943}
944
945TextureCubeGenMipmapCase::IterateResult TextureCubeGenMipmapCase::iterate (void)
946{
947	const glw::Functions&	gl					= m_renderCtx.getFunctions();
948
949	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
950	const deUint32			magFilter			= GL_NEAREST;
951	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
952	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
953
954	tcu::TextureCube		resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_size);
955
956	const int				numLevels			= deLog2Floor32(m_size)+1;
957	vector<float>			texCoord;
958
959	// Initialize texture level 0 with colored grid.
960	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
961	{
962		Vec4 ca, cb; // Grid colors.
963
964		switch (face)
965		{
966			case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
967			case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
968			case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
969			case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
970			case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
971			case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
972		}
973
974		m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
975		fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
976	}
977
978	// Upload data and setup params.
979	m_texture->upload();
980
981	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
982	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		wrapS);
983	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		wrapT);
984	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	minFilter);
985	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
986	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
987
988	// Generate mipmap.
989	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
990	gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
991	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
992
993	// Render all levels.
994	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
995	{
996		const int	levelWidth	= de::max(1, m_size >> levelNdx);
997		const int	levelHeight	= de::max(1, m_size >> levelNdx);
998
999		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1000		{
1001			const RandomViewport	viewport	(m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1002			const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
1003
1004			computeQuadTexCoordCube(texCoord, face);
1005
1006			gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1007			m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1008
1009			resultTexture.allocLevel(face, levelNdx);
1010			glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1011		}
1012	}
1013
1014	// Compare results
1015	{
1016		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1017		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1018		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
1019		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1020		GenMipmapPrecision	comparePrec;
1021
1022		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1023		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
1024		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
1025
1026		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1027
1028		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
1029											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
1030											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
1031	}
1032
1033	return STOP;
1034}
1035
1036TextureMipmapTests::TextureMipmapTests (Context& context)
1037	: TestCaseGroup(context, "mipmap", "Mipmapping tests")
1038{
1039}
1040
1041TextureMipmapTests::~TextureMipmapTests (void)
1042{
1043}
1044
1045void TextureMipmapTests::init (void)
1046{
1047	tcu::TestCaseGroup* group2D		= new tcu::TestCaseGroup(m_testCtx, "2d",	"2D Texture Mipmapping");
1048	tcu::TestCaseGroup*	groupCube	= new tcu::TestCaseGroup(m_testCtx, "cube",	"Cube Map Filtering");
1049	addChild(group2D);
1050	addChild(groupCube);
1051
1052	static const struct
1053	{
1054		const char*		name;
1055		deUint32		mode;
1056	} wrapModes[] =
1057	{
1058		{ "clamp",		GL_CLAMP_TO_EDGE },
1059		{ "repeat",		GL_REPEAT },
1060		{ "mirror",		GL_MIRRORED_REPEAT }
1061	};
1062
1063	static const struct
1064	{
1065		const char*		name;
1066		deUint32		mode;
1067	} minFilterModes[] =
1068	{
1069		{ "nearest_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1070		{ "linear_nearest",		GL_LINEAR_MIPMAP_NEAREST	},
1071		{ "nearest_linear",		GL_NEAREST_MIPMAP_LINEAR	},
1072		{ "linear_linear",		GL_LINEAR_MIPMAP_LINEAR		}
1073	};
1074
1075	static const struct
1076	{
1077		CoordType		type;
1078		const char*		name;
1079		const char*		desc;
1080	} coordTypes[] =
1081	{
1082		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1083		{ COORDTYPE_AFFINE,		"affine",		"Mipmapping with affine coordinate transform"		},
1084		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			}
1085	};
1086
1087	static const struct
1088	{
1089		const char*		name;
1090		deUint32		format;
1091		deUint32		dataType;
1092	} formats[] =
1093	{
1094		{ "a8",			GL_ALPHA,			GL_UNSIGNED_BYTE },
1095		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
1096		{ "la88",		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
1097		{ "rgb565",		GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
1098		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
1099		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
1100		{ "rgba5551",	GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
1101		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
1102	};
1103
1104	static const struct
1105	{
1106		const char*		name;
1107		deUint32		hint;
1108	} genHints[] =
1109	{
1110		{ "fastest",	GL_FASTEST },
1111		{ "nicest",		GL_NICEST }
1112	};
1113
1114	static const struct
1115	{
1116		const char*		name;
1117		int				width;
1118		int				height;
1119	} tex2DSizes[] =
1120	{
1121		{ DE_NULL,		64, 64 }, // Default.
1122		{ "non_square",	32, 64 }
1123	};
1124
1125	// 2D cases.
1126	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
1127	{
1128		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
1129		group2D->addChild(coordTypeGroup);
1130
1131		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1132		{
1133			for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
1134			{
1135				// Add non_square variants to basic cases only.
1136				int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
1137
1138				for (int size = 0; size < sizeEnd; size++)
1139				{
1140					std::ostringstream name;
1141					name << minFilterModes[minFilter].name
1142						 << "_" << wrapModes[wrapMode].name;
1143
1144					if (tex2DSizes[size].name)
1145						name << "_" << tex2DSizes[size].name;
1146
1147					coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1148																	 name.str().c_str(), "",
1149																	 coordTypes[coordType].type,
1150																	 minFilterModes[minFilter].mode,
1151																	 wrapModes[wrapMode].mode,
1152																	 wrapModes[wrapMode].mode,
1153																	 GL_RGBA, GL_UNSIGNED_BYTE,
1154																	 tex2DSizes[size].width, tex2DSizes[size].height));
1155				}
1156			}
1157		}
1158	}
1159
1160	// 2D bias variants.
1161	{
1162		tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
1163		group2D->addChild(biasGroup);
1164
1165		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1166			biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1167														minFilterModes[minFilter].name, "",
1168														COORDTYPE_BASIC_BIAS,
1169														minFilterModes[minFilter].mode,
1170														GL_REPEAT, GL_REPEAT,
1171														GL_RGBA, GL_UNSIGNED_BYTE,
1172														tex2DSizes[0].width, tex2DSizes[0].height));
1173	}
1174
1175	// 2D mipmap generation variants.
1176	{
1177		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1178		group2D->addChild(genMipmapGroup);
1179
1180		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1181		{
1182			for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
1183			{
1184				for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1185				{
1186					std::ostringstream name;
1187					name << formats[format].name;
1188
1189					if (tex2DSizes[size].name)
1190						name << "_" << tex2DSizes[size].name;
1191
1192					name << "_" << genHints[hint].name;
1193
1194					genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
1195																		formats[format].format, formats[format].dataType, genHints[hint].hint,
1196																		tex2DSizes[size].width, tex2DSizes[size].height));
1197				}
1198			}
1199		}
1200	}
1201
1202	const int cubeMapSize = 64;
1203
1204	static const struct
1205	{
1206		CoordType		type;
1207		const char*		name;
1208		const char*		desc;
1209	} cubeCoordTypes[] =
1210	{
1211		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1212		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			},
1213		{ COORDTYPE_BASIC_BIAS,	"bias",			"User-supplied bias value"							}
1214	};
1215
1216	// Cubemap cases.
1217	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
1218	{
1219		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
1220		groupCube->addChild(coordTypeGroup);
1221
1222		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1223		{
1224			coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1225															   minFilterModes[minFilter].name, "",
1226															   cubeCoordTypes[coordType].type,
1227															   minFilterModes[minFilter].mode,
1228															   GL_CLAMP_TO_EDGE,
1229															   GL_CLAMP_TO_EDGE,
1230															   GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
1231		}
1232	}
1233
1234	// Cubemap mipmap generation variants.
1235	{
1236		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1237		groupCube->addChild(genMipmapGroup);
1238
1239		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1240		{
1241			for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1242			{
1243				std::ostringstream name;
1244				name << formats[format].name
1245					 << "_" << genHints[hint].name;
1246
1247				genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
1248			}
1249		}
1250	}
1251}
1252
1253} // Functional
1254} // gles2
1255} // deqp
1256