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 
42 namespace deqp
43 {
44 namespace gles2
45 {
46 namespace Functional
47 {
48 
49 using tcu::TestLog;
50 using std::vector;
51 using std::string;
52 using tcu::Sampler;
53 using tcu::Vec2;
54 using tcu::Mat2;
55 using tcu::Vec4;
56 using tcu::IVec2;
57 using tcu::IVec4;
58 using namespace glu;
59 using namespace gls::TextureTestUtil;
60 using namespace glu::TextureTestUtil;
61 
62 enum 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 
74 class Texture2DMipmapCase : public tcu::TestCase
75 {
76 public:
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 
97 private:
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 
Texture2DMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & renderCtxInfo,const char * name,const char * desc,CoordType coordType,deUint32 minFilter,deUint32 wrapS,deUint32 wrapT,deUint32 format,deUint32 dataType,int width,int height)117 Texture2DMipmapCase::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 
~Texture2DMipmapCase(void)148 Texture2DMipmapCase::~Texture2DMipmapCase (void)
149 {
150 	deinit();
151 }
152 
init(void)153 void 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 
deinit(void)179 void Texture2DMipmapCase::deinit (void)
180 {
181 	delete m_texture;
182 	m_texture = DE_NULL;
183 
184 	m_renderer.clear();
185 }
186 
getBasicTexCoord2D(std::vector<float> & dst,int cellNdx)187 static 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 
getAffineTexCoord2D(std::vector<float> & dst,int cellNdx)224 static 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 
iterate(void)249 Texture2DMipmapCase::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 
428 class TextureCubeMipmapCase : public tcu::TestCase
429 {
430 public:
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 
450 private:
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 
TextureCubeMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & renderCtxInfo,const char * name,const char * desc,CoordType coordType,deUint32 minFilter,deUint32 wrapS,deUint32 wrapT,deUint32 format,deUint32 dataType,int size)469 TextureCubeMipmapCase::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 
~TextureCubeMipmapCase(void)498 TextureCubeMipmapCase::~TextureCubeMipmapCase (void)
499 {
500 	deinit();
501 }
502 
init(void)503 void 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 
deinit(void)543 void TextureCubeMipmapCase::deinit (void)
544 {
545 	delete m_texture;
546 	m_texture = DE_NULL;
547 
548 	m_renderer.clear();
549 }
550 
randomPartition(vector<IVec4> & dst,de::Random & rnd,int x,int y,int width,int height)551 static 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 
computeGridLayout(vector<IVec4> & dst,int width,int height)576 static 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 
iterate(void)582 TextureCubeMipmapCase::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 	// Detect compatible GLES context by querying GL_MAJOR_VERSION.
604 	// This query does not exist on GLES2 so succeeding query implies GLES3+ context.
605 	bool isES3Compatible = false;
606 	glw::GLint majorVersion = 0;
607 	gl.getIntegerv(GL_MAJOR_VERSION, &majorVersion);
608 	if (gl.getError() == GL_NO_ERROR)
609 		isES3Compatible = true;
610 
611 	// Upload texture data.
612 	m_texture->upload();
613 
614 	// Bind gradient texture and setup sampler parameters.
615 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
616 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
617 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
618 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
619 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
620 
621 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
622 
623 	// Compute grid.
624 	vector<IVec4> gridLayout;
625 	computeGridLayout(gridLayout, viewport.width, viewport.height);
626 
627 	// Bias values.
628 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
629 
630 	// Projection values \note Less agressive than in 2D case due to smaller quads.
631 	static const Vec4 s_projections[] =
632 	{
633 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
634 		Vec4(1.3f, 0.8f, 0.6f, 1.1f),
635 		Vec4(0.8f, 1.0f, 1.2f, 0.8f),
636 		Vec4(1.2f, 1.0f, 1.3f, 0.9f)
637 	};
638 
639 	// Render with GL
640 	for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
641 	{
642 		const int			curX		= gridLayout[cellNdx].x();
643 		const int			curY		= gridLayout[cellNdx].y();
644 		const int			curW		= gridLayout[cellNdx].z();
645 		const int			curH		= gridLayout[cellNdx].w();
646 		const tcu::CubeFace	cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
647 		RenderParams		params		(TEXTURETYPE_CUBE);
648 
649 		DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
650 		computeQuadTexCoordCube(texCoord, cubeFace);
651 
652 		if (isProjected)
653 		{
654 			params.flags	|= ReferenceParams::PROJECTED;
655 			params.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
656 		}
657 
658 		if (useLodBias)
659 		{
660 			params.flags	|= ReferenceParams::USE_BIAS;
661 			params.bias		 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
662 		}
663 
664 		// Render with GL.
665 		gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
666 		m_renderer.renderQuad(0, &texCoord[0], params);
667 	}
668 	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
669 
670 	// Read result.
671 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
672 	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
673 
674 	// Render reference and compare
675 	{
676 		tcu::Surface			referenceFrame		(viewport.width, viewport.height);
677 		tcu::Surface			errorMask			(viewport.width, viewport.height);
678 		int						numFailedPixels		= 0;
679 		ReferenceParams			params				(TEXTURETYPE_CUBE);
680 		tcu::LookupPrecision	lookupPrec;
681 		tcu::LodPrecision		lodPrec;
682 
683 		// Params for rendering reference
684 		params.sampler					= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
685 		params.sampler.seamlessCubeMap	= isES3Compatible;
686 		params.lodMode					= LODMODE_EXACT;
687 
688 		// Comparison parameters
689 		lookupPrec.colorMask			= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
690 		lookupPrec.colorThreshold		= tcu::computeFixedPointThreshold(max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0)));
691 		lookupPrec.coordBits			= isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
692 		lookupPrec.uvwBits				= tcu::IVec3(5,5,0);
693 		lodPrec.derivateBits			= 10;
694 		lodPrec.lodBits					= isES3Compatible ? 3 : 4;
695 		lodPrec.lodBits					= isProjected ? lodPrec.lodBits : 6;
696 
697 		for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
698 		{
699 			const int				curX		= gridLayout[cellNdx].x();
700 			const int				curY		= gridLayout[cellNdx].y();
701 			const int				curW		= gridLayout[cellNdx].z();
702 			const int				curH		= gridLayout[cellNdx].w();
703 			const tcu::CubeFace		cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
704 
705 			DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
706 			computeQuadTexCoordCube(texCoord, cubeFace);
707 
708 			if (isProjected)
709 			{
710 				params.flags	|= ReferenceParams::PROJECTED;
711 				params.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
712 			}
713 
714 			if (useLodBias)
715 			{
716 				params.flags	|= ReferenceParams::USE_BIAS;
717 				params.bias		 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
718 			}
719 
720 			// Render ideal reference.
721 			{
722 				tcu::SurfaceAccess idealDst(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
723 				sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
724 			}
725 
726 			// Compare this cell
727 			numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
728 														tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
729 														tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
730 														m_texture->getRefTexture(), &texCoord[0], params,
731 														lookupPrec, lodPrec, m_testCtx.getWatchDog());
732 		}
733 
734 		if (numFailedPixels > 0)
735 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
736 
737 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
738 						   << TestLog::Image("Rendered", "Rendered image", renderedFrame);
739 
740 		if (numFailedPixels > 0)
741 		{
742 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
743 							   << TestLog::Image("ErrorMask", "Error mask", errorMask);
744 		}
745 
746 		m_testCtx.getLog() << TestLog::EndImageSet;
747 
748 		{
749 			const bool isOk = numFailedPixels == 0;
750 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
751 									isOk ? "Pass"				: "Image verification failed");
752 		}
753 	}
754 
755 	return STOP;
756 }
757 
758 // Texture2DGenMipmapCase
759 
760 class Texture2DGenMipmapCase : public tcu::TestCase
761 {
762 public:
763 
764 								Texture2DGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height);
765 								~Texture2DGenMipmapCase		(void);
766 
767 	void						init						(void);
768 	void						deinit						(void);
769 	IterateResult				iterate						(void);
770 
771 private:
772 								Texture2DGenMipmapCase		(const Texture2DGenMipmapCase& other);
773 	Texture2DGenMipmapCase&		operator=					(const Texture2DGenMipmapCase& other);
774 
775 	glu::RenderContext&			m_renderCtx;
776 
777 	deUint32					m_format;
778 	deUint32					m_dataType;
779 	deUint32					m_hint;
780 	int							m_width;
781 	int							m_height;
782 
783 	glu::Texture2D*				m_texture;
784 	TextureRenderer				m_renderer;
785 };
786 
Texture2DGenMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,deUint32 format,deUint32 dataType,deUint32 hint,int width,int height)787 Texture2DGenMipmapCase::Texture2DGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height)
788 	: TestCase			(testCtx, name, desc)
789 	, m_renderCtx		(renderCtx)
790 	, m_format			(format)
791 	, m_dataType		(dataType)
792 	, m_hint			(hint)
793 	, m_width			(width)
794 	, m_height			(height)
795 	, m_texture			(DE_NULL)
796 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
797 {
798 }
799 
~Texture2DGenMipmapCase(void)800 Texture2DGenMipmapCase::~Texture2DGenMipmapCase (void)
801 {
802 	deinit();
803 }
804 
init(void)805 void Texture2DGenMipmapCase::init (void)
806 {
807 	DE_ASSERT(!m_texture);
808 	m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
809 }
810 
deinit(void)811 void Texture2DGenMipmapCase::deinit (void)
812 {
813 	delete m_texture;
814 	m_texture = DE_NULL;
815 
816 	m_renderer.clear();
817 }
818 
iterate(void)819 Texture2DGenMipmapCase::IterateResult Texture2DGenMipmapCase::iterate (void)
820 {
821 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
822 
823 	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
824 	const deUint32			magFilter			= GL_NEAREST;
825 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
826 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
827 
828 	const int				numLevels			= deLog2Floor32(de::max(m_width, m_height))+1;
829 
830 	tcu::Texture2D			resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight());
831 
832 	vector<float>			texCoord;
833 
834 	// Initialize texture level 0 with colored grid.
835 	m_texture->getRefTexture().allocLevel(0);
836 	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));
837 
838 	// Upload data and setup params.
839 	m_texture->upload();
840 
841 	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
842 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		wrapS);
843 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		wrapT);
844 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	minFilter);
845 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
846 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
847 
848 	// Generate mipmap.
849 	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
850 	gl.generateMipmap(GL_TEXTURE_2D);
851 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
852 
853 	// Use (0, 0) -> (1, 1) texture coordinates.
854 	computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
855 
856 	// Fetch resulting texture by rendering.
857 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
858 	{
859 		const int				levelWidth		= de::max(1, m_width >> levelNdx);
860 		const int				levelHeight		= de::max(1, m_height >> levelNdx);
861 		const RandomViewport	viewport		(m_renderCtx.getRenderTarget(), levelWidth, levelHeight, deStringHash(getName()) + levelNdx);
862 
863 		gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
864 		m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
865 
866 		resultTexture.allocLevel(levelNdx);
867 		glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevel(levelNdx));
868 	}
869 
870 	// Compare results
871 	{
872 
873 		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
874 		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
875 		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
876 		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
877 		GenMipmapPrecision	comparePrec;
878 
879 		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
880 		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
881 		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
882 
883 		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
884 
885 		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
886 											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
887 											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
888 	}
889 
890 	return STOP;
891 }
892 
893 // TextureCubeGenMipmapCase
894 
895 class TextureCubeGenMipmapCase : public tcu::TestCase
896 {
897 public:
898 
899 								TextureCubeGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size);
900 								~TextureCubeGenMipmapCase		(void);
901 
902 	void						init							(void);
903 	void						deinit							(void);
904 	IterateResult				iterate							(void);
905 
906 private:
907 								TextureCubeGenMipmapCase		(const TextureCubeGenMipmapCase& other);
908 	TextureCubeGenMipmapCase&	operator=						(const TextureCubeGenMipmapCase& other);
909 
910 	glu::RenderContext&			m_renderCtx;
911 
912 	deUint32					m_format;
913 	deUint32					m_dataType;
914 	deUint32					m_hint;
915 	int							m_size;
916 
917 	glu::TextureCube*			m_texture;
918 	TextureRenderer				m_renderer;
919 };
920 
TextureCubeGenMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,deUint32 format,deUint32 dataType,deUint32 hint,int size)921 TextureCubeGenMipmapCase::TextureCubeGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size)
922 	: TestCase			(testCtx, name, desc)
923 	, m_renderCtx		(renderCtx)
924 	, m_format			(format)
925 	, m_dataType		(dataType)
926 	, m_hint			(hint)
927 	, m_size			(size)
928 	, m_texture			(DE_NULL)
929 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
930 {
931 }
932 
~TextureCubeGenMipmapCase(void)933 TextureCubeGenMipmapCase::~TextureCubeGenMipmapCase (void)
934 {
935 	deinit();
936 }
937 
init(void)938 void TextureCubeGenMipmapCase::init (void)
939 {
940 	if (m_renderCtx.getRenderTarget().getWidth() < 3*m_size || m_renderCtx.getRenderTarget().getHeight() < 2*m_size)
941 		throw tcu::NotSupportedError("Render target size must be at least (" + de::toString(3*m_size) + ", " + de::toString(2*m_size) + ")");
942 
943 	DE_ASSERT(!m_texture);
944 	m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_size);
945 }
946 
deinit(void)947 void TextureCubeGenMipmapCase::deinit (void)
948 {
949 	delete m_texture;
950 	m_texture = DE_NULL;
951 
952 	m_renderer.clear();
953 }
954 
iterate(void)955 TextureCubeGenMipmapCase::IterateResult TextureCubeGenMipmapCase::iterate (void)
956 {
957 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
958 
959 	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
960 	const deUint32			magFilter			= GL_NEAREST;
961 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
962 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
963 
964 	tcu::TextureCube		resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_size);
965 
966 	const int				numLevels			= deLog2Floor32(m_size)+1;
967 	vector<float>			texCoord;
968 
969 	// Initialize texture level 0 with colored grid.
970 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
971 	{
972 		Vec4 ca, cb; // Grid colors.
973 
974 		switch (face)
975 		{
976 			case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
977 			case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
978 			case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
979 			case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
980 			case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
981 			case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
982 		}
983 
984 		m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
985 		fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
986 	}
987 
988 	// Upload data and setup params.
989 	m_texture->upload();
990 
991 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
992 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		wrapS);
993 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		wrapT);
994 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	minFilter);
995 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
996 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
997 
998 	// Generate mipmap.
999 	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
1000 	gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
1001 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
1002 
1003 	// Render all levels.
1004 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1005 	{
1006 		const int	levelWidth	= de::max(1, m_size >> levelNdx);
1007 		const int	levelHeight	= de::max(1, m_size >> levelNdx);
1008 
1009 		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1010 		{
1011 			const RandomViewport	viewport	(m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1012 			const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
1013 
1014 			computeQuadTexCoordCube(texCoord, face);
1015 
1016 			gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1017 			m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1018 
1019 			resultTexture.allocLevel(face, levelNdx);
1020 			glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1021 		}
1022 	}
1023 
1024 	// Compare results
1025 	{
1026 		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1027 		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1028 		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
1029 		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1030 		GenMipmapPrecision	comparePrec;
1031 
1032 		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1033 		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
1034 		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
1035 
1036 		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1037 
1038 		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
1039 											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
1040 											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
1041 	}
1042 
1043 	return STOP;
1044 }
1045 
TextureMipmapTests(Context & context)1046 TextureMipmapTests::TextureMipmapTests (Context& context)
1047 	: TestCaseGroup(context, "mipmap", "Mipmapping tests")
1048 {
1049 }
1050 
~TextureMipmapTests(void)1051 TextureMipmapTests::~TextureMipmapTests (void)
1052 {
1053 }
1054 
init(void)1055 void TextureMipmapTests::init (void)
1056 {
1057 	tcu::TestCaseGroup* group2D		= new tcu::TestCaseGroup(m_testCtx, "2d",	"2D Texture Mipmapping");
1058 	tcu::TestCaseGroup*	groupCube	= new tcu::TestCaseGroup(m_testCtx, "cube",	"Cube Map Filtering");
1059 	addChild(group2D);
1060 	addChild(groupCube);
1061 
1062 	static const struct
1063 	{
1064 		const char*		name;
1065 		deUint32		mode;
1066 	} wrapModes[] =
1067 	{
1068 		{ "clamp",		GL_CLAMP_TO_EDGE },
1069 		{ "repeat",		GL_REPEAT },
1070 		{ "mirror",		GL_MIRRORED_REPEAT }
1071 	};
1072 
1073 	static const struct
1074 	{
1075 		const char*		name;
1076 		deUint32		mode;
1077 	} minFilterModes[] =
1078 	{
1079 		{ "nearest_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1080 		{ "linear_nearest",		GL_LINEAR_MIPMAP_NEAREST	},
1081 		{ "nearest_linear",		GL_NEAREST_MIPMAP_LINEAR	},
1082 		{ "linear_linear",		GL_LINEAR_MIPMAP_LINEAR		}
1083 	};
1084 
1085 	static const struct
1086 	{
1087 		CoordType		type;
1088 		const char*		name;
1089 		const char*		desc;
1090 	} coordTypes[] =
1091 	{
1092 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1093 		{ COORDTYPE_AFFINE,		"affine",		"Mipmapping with affine coordinate transform"		},
1094 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			}
1095 	};
1096 
1097 	static const struct
1098 	{
1099 		const char*		name;
1100 		deUint32		format;
1101 		deUint32		dataType;
1102 	} formats[] =
1103 	{
1104 		{ "a8",			GL_ALPHA,			GL_UNSIGNED_BYTE },
1105 		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
1106 		{ "la88",		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
1107 		{ "rgb565",		GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
1108 		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
1109 		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
1110 		{ "rgba5551",	GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
1111 		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
1112 	};
1113 
1114 	static const struct
1115 	{
1116 		const char*		name;
1117 		deUint32		hint;
1118 	} genHints[] =
1119 	{
1120 		{ "fastest",	GL_FASTEST },
1121 		{ "nicest",		GL_NICEST }
1122 	};
1123 
1124 	static const struct
1125 	{
1126 		const char*		name;
1127 		int				width;
1128 		int				height;
1129 	} tex2DSizes[] =
1130 	{
1131 		{ DE_NULL,		64, 64 }, // Default.
1132 		{ "non_square",	32, 64 }
1133 	};
1134 
1135 	// 2D cases.
1136 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
1137 	{
1138 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
1139 		group2D->addChild(coordTypeGroup);
1140 
1141 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1142 		{
1143 			for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
1144 			{
1145 				// Add non_square variants to basic cases only.
1146 				int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
1147 
1148 				for (int size = 0; size < sizeEnd; size++)
1149 				{
1150 					std::ostringstream name;
1151 					name << minFilterModes[minFilter].name
1152 						 << "_" << wrapModes[wrapMode].name;
1153 
1154 					if (tex2DSizes[size].name)
1155 						name << "_" << tex2DSizes[size].name;
1156 
1157 					coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1158 																	 name.str().c_str(), "",
1159 																	 coordTypes[coordType].type,
1160 																	 minFilterModes[minFilter].mode,
1161 																	 wrapModes[wrapMode].mode,
1162 																	 wrapModes[wrapMode].mode,
1163 																	 GL_RGBA, GL_UNSIGNED_BYTE,
1164 																	 tex2DSizes[size].width, tex2DSizes[size].height));
1165 				}
1166 			}
1167 		}
1168 	}
1169 
1170 	// 2D bias variants.
1171 	{
1172 		tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
1173 		group2D->addChild(biasGroup);
1174 
1175 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1176 			biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1177 														minFilterModes[minFilter].name, "",
1178 														COORDTYPE_BASIC_BIAS,
1179 														minFilterModes[minFilter].mode,
1180 														GL_REPEAT, GL_REPEAT,
1181 														GL_RGBA, GL_UNSIGNED_BYTE,
1182 														tex2DSizes[0].width, tex2DSizes[0].height));
1183 	}
1184 
1185 	// 2D mipmap generation variants.
1186 	{
1187 		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1188 		group2D->addChild(genMipmapGroup);
1189 
1190 		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1191 		{
1192 			for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
1193 			{
1194 				for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1195 				{
1196 					std::ostringstream name;
1197 					name << formats[format].name;
1198 
1199 					if (tex2DSizes[size].name)
1200 						name << "_" << tex2DSizes[size].name;
1201 
1202 					name << "_" << genHints[hint].name;
1203 
1204 					genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
1205 																		formats[format].format, formats[format].dataType, genHints[hint].hint,
1206 																		tex2DSizes[size].width, tex2DSizes[size].height));
1207 				}
1208 			}
1209 		}
1210 	}
1211 
1212 	const int cubeMapSize = 64;
1213 
1214 	static const struct
1215 	{
1216 		CoordType		type;
1217 		const char*		name;
1218 		const char*		desc;
1219 	} cubeCoordTypes[] =
1220 	{
1221 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1222 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			},
1223 		{ COORDTYPE_BASIC_BIAS,	"bias",			"User-supplied bias value"							}
1224 	};
1225 
1226 	// Cubemap cases.
1227 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
1228 	{
1229 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
1230 		groupCube->addChild(coordTypeGroup);
1231 
1232 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1233 		{
1234 			coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1235 															   minFilterModes[minFilter].name, "",
1236 															   cubeCoordTypes[coordType].type,
1237 															   minFilterModes[minFilter].mode,
1238 															   GL_CLAMP_TO_EDGE,
1239 															   GL_CLAMP_TO_EDGE,
1240 															   GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
1241 		}
1242 	}
1243 
1244 	// Cubemap mipmap generation variants.
1245 	{
1246 		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1247 		groupCube->addChild(genMipmapGroup);
1248 
1249 		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1250 		{
1251 			for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1252 			{
1253 				std::ostringstream name;
1254 				name << formats[format].name
1255 					 << "_" << genHints[hint].name;
1256 
1257 				genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
1258 			}
1259 		}
1260 	}
1261 }
1262 
1263 } // Functional
1264 } // gles2
1265 } // deqp
1266