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 
61 enum 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 
73 class Texture2DMipmapCase : public tcu::TestCase
74 {
75 public:
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 
96 private:
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 
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)116 Texture2DMipmapCase::Texture2DMipmapCase (tcu::TestContext&			testCtx,
117 										  glu::RenderContext&		renderCtx,
118 										  const glu::ContextInfo&	renderCtxInfo,
119 										  const char*				name,
120 										  const char*				desc,
121 										  CoordType					coordType,
122 										  deUint32					minFilter,
123 										  deUint32					wrapS,
124 										  deUint32					wrapT,
125 										  deUint32					format,
126 										  deUint32					dataType,
127 										  int						width,
128 										  int						height)
129 	: TestCase			(testCtx, name, desc)
130 	, m_renderCtx		(renderCtx)
131 	, m_renderCtxInfo	(renderCtxInfo)
132 	, m_coordType		(coordType)
133 	, m_minFilter		(minFilter)
134 	, m_wrapS			(wrapS)
135 	, m_wrapT			(wrapT)
136 	, m_format			(format)
137 	, m_dataType		(dataType)
138 	, m_width			(width)
139 	, m_height			(height)
140 	, m_texture			(DE_NULL)
141 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES,
142 						 renderCtxInfo.isFragmentHighPrecisionSupported() ? glu::PRECISION_HIGHP // Use highp if available.
143 																		  : glu::PRECISION_MEDIUMP)
144 {
145 }
146 
~Texture2DMipmapCase(void)147 Texture2DMipmapCase::~Texture2DMipmapCase (void)
148 {
149 	deinit();
150 }
151 
init(void)152 void 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 
deinit(void)178 void Texture2DMipmapCase::deinit (void)
179 {
180 	delete m_texture;
181 	m_texture = DE_NULL;
182 
183 	m_renderer.clear();
184 }
185 
getBasicTexCoord2D(std::vector<float> & dst,int cellNdx)186 static 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 
getAffineTexCoord2D(std::vector<float> & dst,int cellNdx)223 static 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 
iterate(void)248 Texture2DMipmapCase::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 
427 class TextureCubeMipmapCase : public tcu::TestCase
428 {
429 public:
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 
449 private:
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 
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)468 TextureCubeMipmapCase::TextureCubeMipmapCase (tcu::TestContext&			testCtx,
469 											  glu::RenderContext&		renderCtx,
470 											  const glu::ContextInfo&	renderCtxInfo,
471 											  const char*				name,
472 											  const char*				desc,
473 											  CoordType					coordType,
474 											  deUint32					minFilter,
475 											  deUint32					wrapS,
476 											  deUint32					wrapT,
477 											  deUint32					format,
478 											  deUint32					dataType,
479 											  int						size)
480 	: TestCase			(testCtx, name, desc)
481 	, m_renderCtx		(renderCtx)
482 	, m_renderCtxInfo	(renderCtxInfo)
483 	, m_coordType		(coordType)
484 	, m_minFilter		(minFilter)
485 	, m_wrapS			(wrapS)
486 	, m_wrapT			(wrapT)
487 	, m_format			(format)
488 	, m_dataType		(dataType)
489 	, m_size			(size)
490 	, m_texture			(DE_NULL)
491 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES,
492 						 renderCtxInfo.isFragmentHighPrecisionSupported() ? glu::PRECISION_HIGHP // Use highp if available.
493 																		  : glu::PRECISION_MEDIUMP)
494 {
495 }
496 
~TextureCubeMipmapCase(void)497 TextureCubeMipmapCase::~TextureCubeMipmapCase (void)
498 {
499 	deinit();
500 }
501 
init(void)502 void 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 
deinit(void)542 void TextureCubeMipmapCase::deinit (void)
543 {
544 	delete m_texture;
545 	m_texture = DE_NULL;
546 
547 	m_renderer.clear();
548 }
549 
randomPartition(vector<IVec4> & dst,de::Random & rnd,int x,int y,int width,int height)550 static 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 
computeGridLayout(vector<IVec4> & dst,int width,int height)575 static 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 
iterate(void)581 TextureCubeMipmapCase::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 
750 class Texture2DGenMipmapCase : public tcu::TestCase
751 {
752 public:
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 
761 private:
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 
Texture2DGenMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,deUint32 format,deUint32 dataType,deUint32 hint,int width,int height)777 Texture2DGenMipmapCase::Texture2DGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height)
778 	: TestCase			(testCtx, name, desc)
779 	, m_renderCtx		(renderCtx)
780 	, m_format			(format)
781 	, m_dataType		(dataType)
782 	, m_hint			(hint)
783 	, m_width			(width)
784 	, m_height			(height)
785 	, m_texture			(DE_NULL)
786 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
787 {
788 }
789 
~Texture2DGenMipmapCase(void)790 Texture2DGenMipmapCase::~Texture2DGenMipmapCase (void)
791 {
792 	deinit();
793 }
794 
init(void)795 void 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 
deinit(void)801 void Texture2DGenMipmapCase::deinit (void)
802 {
803 	delete m_texture;
804 	m_texture = DE_NULL;
805 
806 	m_renderer.clear();
807 }
808 
iterate(void)809 Texture2DGenMipmapCase::IterateResult Texture2DGenMipmapCase::iterate (void)
810 {
811 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
812 
813 	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
814 	const deUint32			magFilter			= GL_NEAREST;
815 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
816 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
817 
818 	const int				numLevels			= deLog2Floor32(de::max(m_width, m_height))+1;
819 
820 	tcu::Texture2D			resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight());
821 
822 	vector<float>			texCoord;
823 
824 	// Initialize texture level 0 with colored grid.
825 	m_texture->getRefTexture().allocLevel(0);
826 	tcu::fillWithGrid(m_texture->getRefTexture().getLevel(0), 8, tcu::Vec4(1.0f, 0.5f, 0.0f, 0.5f), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
827 
828 	// Upload data and setup params.
829 	m_texture->upload();
830 
831 	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
832 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		wrapS);
833 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		wrapT);
834 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	minFilter);
835 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
836 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
837 
838 	// Generate mipmap.
839 	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
840 	gl.generateMipmap(GL_TEXTURE_2D);
841 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
842 
843 	// Use (0, 0) -> (1, 1) texture coordinates.
844 	computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
845 
846 	// Fetch resulting texture by rendering.
847 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
848 	{
849 		const int				levelWidth		= de::max(1, m_width >> levelNdx);
850 		const int				levelHeight		= de::max(1, m_height >> levelNdx);
851 		const RandomViewport	viewport		(m_renderCtx.getRenderTarget(), levelWidth, levelHeight, deStringHash(getName()) + levelNdx);
852 
853 		gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
854 		m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
855 
856 		resultTexture.allocLevel(levelNdx);
857 		glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevel(levelNdx));
858 	}
859 
860 	// Compare results
861 	{
862 
863 		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
864 		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
865 		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
866 		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
867 		GenMipmapPrecision	comparePrec;
868 
869 		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
870 		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
871 		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
872 
873 		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
874 
875 		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
876 											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
877 											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
878 	}
879 
880 	return STOP;
881 }
882 
883 // TextureCubeGenMipmapCase
884 
885 class TextureCubeGenMipmapCase : public tcu::TestCase
886 {
887 public:
888 
889 								TextureCubeGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size);
890 								~TextureCubeGenMipmapCase		(void);
891 
892 	void						init							(void);
893 	void						deinit							(void);
894 	IterateResult				iterate							(void);
895 
896 private:
897 								TextureCubeGenMipmapCase		(const TextureCubeGenMipmapCase& other);
898 	TextureCubeGenMipmapCase&	operator=						(const TextureCubeGenMipmapCase& other);
899 
900 	glu::RenderContext&			m_renderCtx;
901 
902 	deUint32					m_format;
903 	deUint32					m_dataType;
904 	deUint32					m_hint;
905 	int							m_size;
906 
907 	glu::TextureCube*			m_texture;
908 	TextureRenderer				m_renderer;
909 };
910 
TextureCubeGenMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,deUint32 format,deUint32 dataType,deUint32 hint,int size)911 TextureCubeGenMipmapCase::TextureCubeGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size)
912 	: TestCase			(testCtx, name, desc)
913 	, m_renderCtx		(renderCtx)
914 	, m_format			(format)
915 	, m_dataType		(dataType)
916 	, m_hint			(hint)
917 	, m_size			(size)
918 	, m_texture			(DE_NULL)
919 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
920 {
921 }
922 
~TextureCubeGenMipmapCase(void)923 TextureCubeGenMipmapCase::~TextureCubeGenMipmapCase (void)
924 {
925 	deinit();
926 }
927 
init(void)928 void TextureCubeGenMipmapCase::init (void)
929 {
930 	if (m_renderCtx.getRenderTarget().getWidth() < 3*m_size || m_renderCtx.getRenderTarget().getHeight() < 2*m_size)
931 		throw tcu::NotSupportedError("Render target size must be at least (" + de::toString(3*m_size) + ", " + de::toString(2*m_size) + ")");
932 
933 	DE_ASSERT(!m_texture);
934 	m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_size);
935 }
936 
deinit(void)937 void TextureCubeGenMipmapCase::deinit (void)
938 {
939 	delete m_texture;
940 	m_texture = DE_NULL;
941 
942 	m_renderer.clear();
943 }
944 
iterate(void)945 TextureCubeGenMipmapCase::IterateResult TextureCubeGenMipmapCase::iterate (void)
946 {
947 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
948 
949 	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
950 	const deUint32			magFilter			= GL_NEAREST;
951 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
952 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
953 
954 	tcu::TextureCube		resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_size);
955 
956 	const int				numLevels			= deLog2Floor32(m_size)+1;
957 	vector<float>			texCoord;
958 
959 	// Initialize texture level 0 with colored grid.
960 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
961 	{
962 		Vec4 ca, cb; // Grid colors.
963 
964 		switch (face)
965 		{
966 			case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
967 			case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
968 			case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
969 			case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
970 			case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
971 			case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
972 		}
973 
974 		m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
975 		fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
976 	}
977 
978 	// Upload data and setup params.
979 	m_texture->upload();
980 
981 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
982 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		wrapS);
983 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		wrapT);
984 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	minFilter);
985 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
986 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
987 
988 	// Generate mipmap.
989 	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
990 	gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
991 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
992 
993 	// Render all levels.
994 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
995 	{
996 		const int	levelWidth	= de::max(1, m_size >> levelNdx);
997 		const int	levelHeight	= de::max(1, m_size >> levelNdx);
998 
999 		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1000 		{
1001 			const RandomViewport	viewport	(m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1002 			const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
1003 
1004 			computeQuadTexCoordCube(texCoord, face);
1005 
1006 			gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1007 			m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1008 
1009 			resultTexture.allocLevel(face, levelNdx);
1010 			glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1011 		}
1012 	}
1013 
1014 	// Compare results
1015 	{
1016 		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1017 		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1018 		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
1019 		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1020 		GenMipmapPrecision	comparePrec;
1021 
1022 		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1023 		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
1024 		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
1025 
1026 		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1027 
1028 		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
1029 											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
1030 											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
1031 	}
1032 
1033 	return STOP;
1034 }
1035 
TextureMipmapTests(Context & context)1036 TextureMipmapTests::TextureMipmapTests (Context& context)
1037 	: TestCaseGroup(context, "mipmap", "Mipmapping tests")
1038 {
1039 }
1040 
~TextureMipmapTests(void)1041 TextureMipmapTests::~TextureMipmapTests (void)
1042 {
1043 }
1044 
init(void)1045 void TextureMipmapTests::init (void)
1046 {
1047 	tcu::TestCaseGroup* group2D		= new tcu::TestCaseGroup(m_testCtx, "2d",	"2D Texture Mipmapping");
1048 	tcu::TestCaseGroup*	groupCube	= new tcu::TestCaseGroup(m_testCtx, "cube",	"Cube Map Filtering");
1049 	addChild(group2D);
1050 	addChild(groupCube);
1051 
1052 	static const struct
1053 	{
1054 		const char*		name;
1055 		deUint32		mode;
1056 	} wrapModes[] =
1057 	{
1058 		{ "clamp",		GL_CLAMP_TO_EDGE },
1059 		{ "repeat",		GL_REPEAT },
1060 		{ "mirror",		GL_MIRRORED_REPEAT }
1061 	};
1062 
1063 	static const struct
1064 	{
1065 		const char*		name;
1066 		deUint32		mode;
1067 	} minFilterModes[] =
1068 	{
1069 		{ "nearest_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1070 		{ "linear_nearest",		GL_LINEAR_MIPMAP_NEAREST	},
1071 		{ "nearest_linear",		GL_NEAREST_MIPMAP_LINEAR	},
1072 		{ "linear_linear",		GL_LINEAR_MIPMAP_LINEAR		}
1073 	};
1074 
1075 	static const struct
1076 	{
1077 		CoordType		type;
1078 		const char*		name;
1079 		const char*		desc;
1080 	} coordTypes[] =
1081 	{
1082 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1083 		{ COORDTYPE_AFFINE,		"affine",		"Mipmapping with affine coordinate transform"		},
1084 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			}
1085 	};
1086 
1087 	static const struct
1088 	{
1089 		const char*		name;
1090 		deUint32		format;
1091 		deUint32		dataType;
1092 	} formats[] =
1093 	{
1094 		{ "a8",			GL_ALPHA,			GL_UNSIGNED_BYTE },
1095 		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
1096 		{ "la88",		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
1097 		{ "rgb565",		GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
1098 		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
1099 		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
1100 		{ "rgba5551",	GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
1101 		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
1102 	};
1103 
1104 	static const struct
1105 	{
1106 		const char*		name;
1107 		deUint32		hint;
1108 	} genHints[] =
1109 	{
1110 		{ "fastest",	GL_FASTEST },
1111 		{ "nicest",		GL_NICEST }
1112 	};
1113 
1114 	static const struct
1115 	{
1116 		const char*		name;
1117 		int				width;
1118 		int				height;
1119 	} tex2DSizes[] =
1120 	{
1121 		{ DE_NULL,		64, 64 }, // Default.
1122 		{ "non_square",	32, 64 }
1123 	};
1124 
1125 	// 2D cases.
1126 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
1127 	{
1128 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
1129 		group2D->addChild(coordTypeGroup);
1130 
1131 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1132 		{
1133 			for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
1134 			{
1135 				// Add non_square variants to basic cases only.
1136 				int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
1137 
1138 				for (int size = 0; size < sizeEnd; size++)
1139 				{
1140 					std::ostringstream name;
1141 					name << minFilterModes[minFilter].name
1142 						 << "_" << wrapModes[wrapMode].name;
1143 
1144 					if (tex2DSizes[size].name)
1145 						name << "_" << tex2DSizes[size].name;
1146 
1147 					coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1148 																	 name.str().c_str(), "",
1149 																	 coordTypes[coordType].type,
1150 																	 minFilterModes[minFilter].mode,
1151 																	 wrapModes[wrapMode].mode,
1152 																	 wrapModes[wrapMode].mode,
1153 																	 GL_RGBA, GL_UNSIGNED_BYTE,
1154 																	 tex2DSizes[size].width, tex2DSizes[size].height));
1155 				}
1156 			}
1157 		}
1158 	}
1159 
1160 	// 2D bias variants.
1161 	{
1162 		tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
1163 		group2D->addChild(biasGroup);
1164 
1165 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1166 			biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1167 														minFilterModes[minFilter].name, "",
1168 														COORDTYPE_BASIC_BIAS,
1169 														minFilterModes[minFilter].mode,
1170 														GL_REPEAT, GL_REPEAT,
1171 														GL_RGBA, GL_UNSIGNED_BYTE,
1172 														tex2DSizes[0].width, tex2DSizes[0].height));
1173 	}
1174 
1175 	// 2D mipmap generation variants.
1176 	{
1177 		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1178 		group2D->addChild(genMipmapGroup);
1179 
1180 		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1181 		{
1182 			for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
1183 			{
1184 				for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1185 				{
1186 					std::ostringstream name;
1187 					name << formats[format].name;
1188 
1189 					if (tex2DSizes[size].name)
1190 						name << "_" << tex2DSizes[size].name;
1191 
1192 					name << "_" << genHints[hint].name;
1193 
1194 					genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
1195 																		formats[format].format, formats[format].dataType, genHints[hint].hint,
1196 																		tex2DSizes[size].width, tex2DSizes[size].height));
1197 				}
1198 			}
1199 		}
1200 	}
1201 
1202 	const int cubeMapSize = 64;
1203 
1204 	static const struct
1205 	{
1206 		CoordType		type;
1207 		const char*		name;
1208 		const char*		desc;
1209 	} cubeCoordTypes[] =
1210 	{
1211 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
1212 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			},
1213 		{ COORDTYPE_BASIC_BIAS,	"bias",			"User-supplied bias value"							}
1214 	};
1215 
1216 	// Cubemap cases.
1217 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
1218 	{
1219 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
1220 		groupCube->addChild(coordTypeGroup);
1221 
1222 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1223 		{
1224 			coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1225 															   minFilterModes[minFilter].name, "",
1226 															   cubeCoordTypes[coordType].type,
1227 															   minFilterModes[minFilter].mode,
1228 															   GL_CLAMP_TO_EDGE,
1229 															   GL_CLAMP_TO_EDGE,
1230 															   GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
1231 		}
1232 	}
1233 
1234 	// Cubemap mipmap generation variants.
1235 	{
1236 		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1237 		groupCube->addChild(genMipmapGroup);
1238 
1239 		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1240 		{
1241 			for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1242 			{
1243 				std::ostringstream name;
1244 				name << formats[format].name
1245 					 << "_" << genHints[hint].name;
1246 
1247 				genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
1248 			}
1249 		}
1250 	}
1251 }
1252 
1253 } // Functional
1254 } // gles2
1255 } // deqp
1256