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, 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, 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, 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	const tcu::Sampler		sampler				= glu::mapGLSampler(wrapS, wrapT, minFilter, magFilter);
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, 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	tcu::Sampler			sampler				= glu::mapGLSampler(wrapS, wrapT, minFilter, magFilter);
959	vector<float>			texCoord;
960
961	// Initialize texture level 0 with colored grid.
962	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
963	{
964		Vec4 ca, cb; // Grid colors.
965
966		switch (face)
967		{
968			case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
969			case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
970			case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
971			case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
972			case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
973			case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
974		}
975
976		m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
977		fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
978	}
979
980	// Upload data and setup params.
981	m_texture->upload();
982
983	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
984	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		wrapS);
985	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		wrapT);
986	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	minFilter);
987	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
988	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
989
990	// Generate mipmap.
991	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
992	gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
993	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
994
995	// Render all levels.
996	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
997	{
998		const int	levelWidth	= de::max(1, m_size >> levelNdx);
999		const int	levelHeight	= de::max(1, m_size >> levelNdx);
1000
1001		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1002		{
1003			const RandomViewport	viewport	(m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1004			const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
1005
1006			computeQuadTexCoordCube(texCoord, face);
1007
1008			gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1009			m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1010
1011			resultTexture.allocLevel(face, levelNdx);
1012			glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1013		}
1014	}
1015
1016	// Compare results
1017	{
1018		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1019		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1020		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
1021		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1022		GenMipmapPrecision	comparePrec;
1023
1024		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1025		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
1026		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
1027
1028		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1029
1030		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
1031											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
1032											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
1033	}
1034
1035	return STOP;
1036}
1037
1038TextureMipmapTests::TextureMipmapTests (Context& context)
1039	: TestCaseGroup(context, "mipmap", "Mipmapping tests")
1040{
1041}
1042
1043TextureMipmapTests::~TextureMipmapTests (void)
1044{
1045}
1046
1047void TextureMipmapTests::init (void)
1048{
1049	tcu::TestCaseGroup* group2D		= new tcu::TestCaseGroup(m_testCtx, "2d",	"2D Texture Mipmapping");
1050	tcu::TestCaseGroup*	groupCube	= new tcu::TestCaseGroup(m_testCtx, "cube",	"Cube Map Filtering");
1051	addChild(group2D);
1052	addChild(groupCube);
1053
1054	static const struct
1055	{
1056		const char*		name;
1057		deUint32		mode;
1058	} wrapModes[] =
1059	{
1060		{ "clamp",		GL_CLAMP_TO_EDGE },
1061		{ "repeat",		GL_REPEAT },
1062		{ "mirror",		GL_MIRRORED_REPEAT }
1063	};
1064
1065	static const struct
1066	{
1067		const char*		name;
1068		deUint32		mode;
1069	} minFilterModes[] =
1070	{
1071		{ "nearest_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1072		{ "linear_nearest",		GL_LINEAR_MIPMAP_NEAREST	},
1073		{ "nearest_linear",		GL_NEAREST_MIPMAP_LINEAR	},
1074		{ "linear_linear",		GL_LINEAR_MIPMAP_LINEAR		}
1075	};
1076
1077	static const struct
1078	{
1079		CoordType		type;
1080		const char*		name;
1081		const char*		desc;
1082	} coordTypes[] =
1083	{
1084		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1085		{ COORDTYPE_AFFINE,		"affine",		"Mipmapping with affine coordinate transform"		},
1086		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			}
1087	};
1088
1089	static const struct
1090	{
1091		const char*		name;
1092		deUint32		format;
1093		deUint32		dataType;
1094	} formats[] =
1095	{
1096		{ "a8",			GL_ALPHA,			GL_UNSIGNED_BYTE },
1097		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
1098		{ "la88",		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
1099		{ "rgb565",		GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
1100		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
1101		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
1102		{ "rgba5551",	GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
1103		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
1104	};
1105
1106	static const struct
1107	{
1108		const char*		name;
1109		deUint32		hint;
1110	} genHints[] =
1111	{
1112		{ "fastest",	GL_FASTEST },
1113		{ "nicest",		GL_NICEST }
1114	};
1115
1116	static const struct
1117	{
1118		const char*		name;
1119		int				width;
1120		int				height;
1121	} tex2DSizes[] =
1122	{
1123		{ DE_NULL,		64, 64 }, // Default.
1124		{ "non_square",	32, 64 }
1125	};
1126
1127	// 2D cases.
1128	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
1129	{
1130		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
1131		group2D->addChild(coordTypeGroup);
1132
1133		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1134		{
1135			for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
1136			{
1137				// Add non_square variants to basic cases only.
1138				int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
1139
1140				for (int size = 0; size < sizeEnd; size++)
1141				{
1142					std::ostringstream name;
1143					name << minFilterModes[minFilter].name
1144						 << "_" << wrapModes[wrapMode].name;
1145
1146					if (tex2DSizes[size].name)
1147						name << "_" << tex2DSizes[size].name;
1148
1149					coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1150																	 name.str().c_str(), "",
1151																	 coordTypes[coordType].type,
1152																	 minFilterModes[minFilter].mode,
1153																	 wrapModes[wrapMode].mode,
1154																	 wrapModes[wrapMode].mode,
1155																	 GL_RGBA, GL_UNSIGNED_BYTE,
1156																	 tex2DSizes[size].width, tex2DSizes[size].height));
1157				}
1158			}
1159		}
1160	}
1161
1162	// 2D bias variants.
1163	{
1164		tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
1165		group2D->addChild(biasGroup);
1166
1167		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1168			biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1169														minFilterModes[minFilter].name, "",
1170														COORDTYPE_BASIC_BIAS,
1171														minFilterModes[minFilter].mode,
1172														GL_REPEAT, GL_REPEAT,
1173														GL_RGBA, GL_UNSIGNED_BYTE,
1174														tex2DSizes[0].width, tex2DSizes[0].height));
1175	}
1176
1177	// 2D mipmap generation variants.
1178	{
1179		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1180		group2D->addChild(genMipmapGroup);
1181
1182		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1183		{
1184			for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
1185			{
1186				for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1187				{
1188					std::ostringstream name;
1189					name << formats[format].name;
1190
1191					if (tex2DSizes[size].name)
1192						name << "_" << tex2DSizes[size].name;
1193
1194					name << "_" << genHints[hint].name;
1195
1196					genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
1197																		formats[format].format, formats[format].dataType, genHints[hint].hint,
1198																		tex2DSizes[size].width, tex2DSizes[size].height));
1199				}
1200			}
1201		}
1202	}
1203
1204	const int cubeMapSize = 64;
1205
1206	static const struct
1207	{
1208		CoordType		type;
1209		const char*		name;
1210		const char*		desc;
1211	} cubeCoordTypes[] =
1212	{
1213		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1214		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			},
1215		{ COORDTYPE_BASIC_BIAS,	"bias",			"User-supplied bias value"							}
1216	};
1217
1218	// Cubemap cases.
1219	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
1220	{
1221		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
1222		groupCube->addChild(coordTypeGroup);
1223
1224		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1225		{
1226			coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1227															   minFilterModes[minFilter].name, "",
1228															   cubeCoordTypes[coordType].type,
1229															   minFilterModes[minFilter].mode,
1230															   GL_CLAMP_TO_EDGE,
1231															   GL_CLAMP_TO_EDGE,
1232															   GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
1233		}
1234	}
1235
1236	// Cubemap mipmap generation variants.
1237	{
1238		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1239		groupCube->addChild(genMipmapGroup);
1240
1241		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1242		{
1243			for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1244			{
1245				std::ostringstream name;
1246				name << formats[format].name
1247					 << "_" << genHints[hint].name;
1248
1249				genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
1250			}
1251		}
1252	}
1253}
1254
1255} // Functional
1256} // gles2
1257} // deqp
1258