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