• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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 "es3fTextureMipmapTests.hpp"
25 
26 #include "glsTextureTestUtil.hpp"
27 #include "gluTexture.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuMatrix.hpp"
32 #include "tcuMatrixUtil.hpp"
33 #include "tcuTexLookupVerifier.hpp"
34 #include "tcuVectorUtil.hpp"
35 #include "deStringUtil.hpp"
36 #include "deRandom.hpp"
37 #include "deString.h"
38 #include "glwFunctions.hpp"
39 #include "glwEnums.hpp"
40 
41 using std::vector;
42 using std::string;
43 using namespace deqp::gls;
44 
45 namespace deqp
46 {
47 namespace gles3
48 {
49 namespace Functional
50 {
51 
52 using std::string;
53 using std::vector;
54 using tcu::TestLog;
55 using tcu::Vec2;
56 using tcu::Vec3;
57 using tcu::Vec4;
58 using tcu::IVec4;
59 using namespace gls::TextureTestUtil;
60 using namespace glu::TextureTestUtil;
61 
getMinLodForCell(int cellNdx)62 static float getMinLodForCell (int cellNdx)
63 {
64 	static const float s_values[] =
65 	{
66 		1.0f,
67 		3.5f,
68 		2.0f,
69 		-2.0f,
70 		0.0f,
71 		3.0f,
72 		10.0f,
73 		4.8f,
74 		5.8f,
75 		5.7f,
76 		-1.9f,
77 		4.0f,
78 		6.5f,
79 		7.1f,
80 		-1e10,
81 		1000.f
82 	};
83 	return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
84 }
85 
getMaxLodForCell(int cellNdx)86 static float getMaxLodForCell (int cellNdx)
87 {
88 	static const float s_values[] =
89 	{
90 		0.0f,
91 		0.2f,
92 		0.7f,
93 		0.4f,
94 		1.3f,
95 		0.0f,
96 		0.5f,
97 		1.2f,
98 		-2.0f,
99 		1.0f,
100 		0.1f,
101 		0.3f,
102 		2.7f,
103 		1.2f,
104 		10.0f,
105 		-1000.f,
106 		1e10f
107 	};
108 	return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
109 }
110 
111 enum CoordType
112 {
113 	COORDTYPE_BASIC,		//!< texCoord = translateScale(position).
114 	COORDTYPE_BASIC_BIAS,	//!< Like basic, but with bias values.
115 	COORDTYPE_AFFINE,		//!< texCoord = translateScaleRotateShear(position).
116 	COORDTYPE_PROJECTED,	//!< Projected coordinates, w != 1
117 
118 	COORDTYPE_LAST
119 };
120 
121 // Texture2DMipmapCase
122 
123 class Texture2DMipmapCase : public tcu::TestCase
124 {
125 public:
126 
127 								Texture2DMipmapCase			(tcu::TestContext&			testCtx,
128 															 glu::RenderContext&		renderCtx,
129 															 const glu::ContextInfo&	renderCtxInfo,
130 															 const char*				name,
131 															 const char*				desc,
132 															 CoordType					coordType,
133 															 deUint32					minFilter,
134 															 deUint32					wrapS,
135 															 deUint32					wrapT,
136 															 deUint32					format,
137 															 deUint32					dataType,
138 															 int						width,
139 															 int						height);
140 								~Texture2DMipmapCase		(void);
141 
142 	void						init						(void);
143 	void						deinit						(void);
144 	IterateResult				iterate						(void);
145 
146 private:
147 								Texture2DMipmapCase			(const Texture2DMipmapCase& other);
148 	Texture2DMipmapCase&		operator=					(const Texture2DMipmapCase& other);
149 
150 	glu::RenderContext&			m_renderCtx;
151 	const glu::ContextInfo&		m_renderCtxInfo;
152 
153 	CoordType					m_coordType;
154 	deUint32					m_minFilter;
155 	deUint32					m_wrapS;
156 	deUint32					m_wrapT;
157 	deUint32					m_format;
158 	deUint32					m_dataType;
159 	int							m_width;
160 	int							m_height;
161 
162 	glu::Texture2D*				m_texture;
163 	TextureRenderer				m_renderer;
164 };
165 
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)166 Texture2DMipmapCase::Texture2DMipmapCase (tcu::TestContext&			testCtx,
167 										  glu::RenderContext&		renderCtx,
168 										  const glu::ContextInfo&	renderCtxInfo,
169 										  const char*				name,
170 										  const char*				desc,
171 										  CoordType					coordType,
172 										  deUint32					minFilter,
173 										  deUint32					wrapS,
174 										  deUint32					wrapT,
175 										  deUint32					format,
176 										  deUint32					dataType,
177 										  int						width,
178 										  int						height)
179 	: TestCase			(testCtx, name, desc)
180 	, m_renderCtx		(renderCtx)
181 	, m_renderCtxInfo	(renderCtxInfo)
182 	, m_coordType		(coordType)
183 	, m_minFilter		(minFilter)
184 	, m_wrapS			(wrapS)
185 	, m_wrapT			(wrapT)
186 	, m_format			(format)
187 	, m_dataType		(dataType)
188 	, m_width			(width)
189 	, m_height			(height)
190 	, m_texture			(DE_NULL)
191 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
192 {
193 }
194 
~Texture2DMipmapCase(void)195 Texture2DMipmapCase::~Texture2DMipmapCase (void)
196 {
197 	deinit();
198 }
199 
init(void)200 void Texture2DMipmapCase::init (void)
201 {
202 	if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
203 		throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
204 
205 	m_texture = new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
206 
207 	int numLevels = deLog2Floor32(de::max(m_width, m_height))+1;
208 
209 	// Fill texture with colored grid.
210 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
211 	{
212 		deUint32	step		= 0xff / (numLevels-1);
213 		deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
214 		deUint32	dec			= 0xff - inc;
215 		deUint32	rgb			= (inc << 16) | (dec << 8) | 0xff;
216 		deUint32	color		= 0xff000000 | rgb;
217 
218 		m_texture->getRefTexture().allocLevel(levelNdx);
219 		tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec());
220 	}
221 }
222 
deinit(void)223 void Texture2DMipmapCase::deinit (void)
224 {
225 	delete m_texture;
226 	m_texture = DE_NULL;
227 
228 	m_renderer.clear();
229 }
230 
getBasicTexCoord2D(std::vector<float> & dst,int cellNdx)231 static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
232 {
233 	static const struct
234 	{
235 		Vec2 bottomLeft;
236 		Vec2 topRight;
237 	} s_basicCoords[] =
238 	{
239 		{ Vec2(-0.1f,  0.1f), Vec2( 0.8f,  1.0f) },
240 		{ Vec2(-0.3f, -0.6f), Vec2( 0.7f,  0.4f) },
241 		{ Vec2(-0.3f,  0.6f), Vec2( 0.7f, -0.9f) },
242 		{ Vec2(-0.8f,  0.6f), Vec2( 0.7f, -0.9f) },
243 
244 		{ Vec2(-0.5f, -0.5f), Vec2( 1.5f,  1.5f) },
245 		{ Vec2( 1.0f, -1.0f), Vec2(-1.3f,  1.0f) },
246 		{ Vec2( 1.2f, -1.0f), Vec2(-1.3f,  1.6f) },
247 		{ Vec2( 2.2f, -1.1f), Vec2(-1.3f,  0.8f) },
248 
249 		{ Vec2(-1.5f,  1.6f), Vec2( 1.7f, -1.4f) },
250 		{ Vec2( 2.0f,  1.6f), Vec2( 2.3f, -1.4f) },
251 		{ Vec2( 1.3f, -2.6f), Vec2(-2.7f,  2.9f) },
252 		{ Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
253 
254 		{ Vec2( -8.0f,   9.0f), Vec2(  8.3f,  -7.0f) },
255 		{ Vec2(-16.0f,  10.0f), Vec2( 18.3f,  24.0f) },
256 		{ Vec2( 30.2f,  55.0f), Vec2(-24.3f,  -1.6f) },
257 		{ Vec2(-33.2f,  64.1f), Vec2( 32.1f, -64.1f) },
258 	};
259 
260 	DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
261 
262 	const Vec2& bottomLeft	= s_basicCoords[cellNdx].bottomLeft;
263 	const Vec2& topRight	= s_basicCoords[cellNdx].topRight;
264 
265 	computeQuadTexCoord2D(dst, bottomLeft, topRight);
266 }
267 
getAffineTexCoord2D(std::vector<float> & dst,int cellNdx)268 static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
269 {
270 	// Use basic coords as base.
271 	getBasicTexCoord2D(dst, cellNdx);
272 
273 	// Rotate based on cell index.
274 	float		angle		= 2.0f*DE_PI * ((float)cellNdx / 16.0f);
275 	tcu::Mat2	rotMatrix	= tcu::rotationMatrix(angle);
276 
277 	// Second and third row are sheared.
278 	float		shearX		= de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
279 	tcu::Mat2	shearMatrix	= tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
280 
281 	tcu::Mat2	transform	= rotMatrix * shearMatrix;
282 	Vec2		p0			= transform * Vec2(dst[0], dst[1]);
283 	Vec2		p1			= transform * Vec2(dst[2], dst[3]);
284 	Vec2		p2			= transform * Vec2(dst[4], dst[5]);
285 	Vec2		p3			= transform * Vec2(dst[6], dst[7]);
286 
287 	dst[0] = p0.x();	dst[1] = p0.y();
288 	dst[2] = p1.x();	dst[3] = p1.y();
289 	dst[4] = p2.x();	dst[5] = p2.y();
290 	dst[6] = p3.x();	dst[7] = p3.y();
291 }
292 
iterate(void)293 Texture2DMipmapCase::IterateResult Texture2DMipmapCase::iterate (void)
294 {
295 	const glw::Functions&		gl					= m_renderCtx.getFunctions();
296 
297 	const tcu::Texture2D&		refTexture			= m_texture->getRefTexture();
298 
299 	const deUint32				magFilter			= GL_NEAREST;
300 	const int					texWidth			= refTexture.getWidth();
301 	const int					texHeight			= refTexture.getHeight();
302 	const int					defViewportWidth	= texWidth*4;
303 	const int					defViewportHeight	= texHeight*4;
304 
305 	const RandomViewport		viewport			(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
306 	ReferenceParams				sampleParams		(TEXTURETYPE_2D);
307 	vector<float>				texCoord;
308 
309 	const bool					isProjected			= m_coordType == COORDTYPE_PROJECTED;
310 	const bool					useLodBias			= m_coordType == COORDTYPE_BASIC_BIAS;
311 
312 	tcu::Surface				renderedFrame		(viewport.width, viewport.height);
313 
314 	// Viewport is divided into 4x4 grid.
315 	int							gridWidth			= 4;
316 	int							gridHeight			= 4;
317 	int							cellWidth			= viewport.width / gridWidth;
318 	int							cellHeight			= viewport.height / gridHeight;
319 
320 	// Bail out if rendertarget is too small.
321 	if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
322 		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
323 
324 	// Sampling parameters.
325 	sampleParams.sampler		= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
326 	sampleParams.samplerType	= glu::TextureTestUtil::getSamplerType(m_texture->getRefTexture().getFormat());
327 	sampleParams.flags			= (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
328 	sampleParams.lodMode		= LODMODE_EXACT; // Use ideal lod.
329 
330 	// Upload texture data.
331 	m_texture->upload();
332 
333 	// Bind gradient texture and setup sampler parameters.
334 	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
335 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
336 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
337 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
338 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
339 
340 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
341 
342 	// Bias values.
343 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
344 
345 	// Projection values.
346 	static const Vec4 s_projections[] =
347 	{
348 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
349 		Vec4(1.3f, 0.8f, 0.6f, 2.0f),
350 		Vec4(0.8f, 1.0f, 1.7f, 0.6f),
351 		Vec4(1.2f, 1.0f, 1.7f, 1.5f)
352 	};
353 
354 	// Render cells.
355 	for (int gridY = 0; gridY < gridHeight; gridY++)
356 	{
357 		for (int gridX = 0; gridX < gridWidth; gridX++)
358 		{
359 			const int		curX		= cellWidth*gridX;
360 			const int		curY		= cellHeight*gridY;
361 			const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
362 			const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
363 			const int		cellNdx		= gridY*gridWidth + gridX;
364 
365 			// Compute texcoord.
366 			switch (m_coordType)
367 			{
368 				case COORDTYPE_BASIC_BIAS:	// Fall-through.
369 				case COORDTYPE_PROJECTED:
370 				case COORDTYPE_BASIC:		getBasicTexCoord2D	(texCoord, cellNdx);	break;
371 				case COORDTYPE_AFFINE:		getAffineTexCoord2D	(texCoord, cellNdx);	break;
372 				default:					DE_ASSERT(DE_FALSE);
373 			}
374 
375 			if (isProjected)
376 				sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
377 
378 			if (useLodBias)
379 				sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
380 
381 			// Render with GL.
382 			gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
383 			m_renderer.renderQuad(0, &texCoord[0], sampleParams);
384 		}
385 	}
386 
387 	// Read result.
388 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
389 
390 	// Compare and log.
391 	{
392 		const tcu::PixelFormat&	pixelFormat		= m_renderCtx.getRenderTarget().getPixelFormat();
393 		const bool				isTrilinear		= m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
394 		tcu::Surface			referenceFrame	(viewport.width, viewport.height);
395 		tcu::Surface			errorMask		(viewport.width, viewport.height);
396 		tcu::LookupPrecision	lookupPrec;
397 		tcu::LodPrecision		lodPrec;
398 		int						numFailedPixels	= 0;
399 
400 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 0);
401 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
402 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
403 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
404 		lodPrec.derivateBits		= 10;
405 		lodPrec.lodBits				= isProjected ? 6 : 8;
406 
407 		for (int gridY = 0; gridY < gridHeight; gridY++)
408 		{
409 			for (int gridX = 0; gridX < gridWidth; gridX++)
410 			{
411 				const int		curX		= cellWidth*gridX;
412 				const int		curY		= cellHeight*gridY;
413 				const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
414 				const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
415 				const int		cellNdx		= gridY*gridWidth + gridX;
416 
417 				// Compute texcoord.
418 				switch (m_coordType)
419 				{
420 					case COORDTYPE_BASIC_BIAS:	// Fall-through.
421 					case COORDTYPE_PROJECTED:
422 					case COORDTYPE_BASIC:		getBasicTexCoord2D	(texCoord, cellNdx);	break;
423 					case COORDTYPE_AFFINE:		getAffineTexCoord2D	(texCoord, cellNdx);	break;
424 					default:					DE_ASSERT(DE_FALSE);
425 				}
426 
427 				if (isProjected)
428 					sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
429 
430 				if (useLodBias)
431 					sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
432 
433 				// Render ideal result
434 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
435 							  refTexture, &texCoord[0], sampleParams);
436 
437 				// Compare this cell
438 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
439 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
440 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
441 															m_texture->getRefTexture(), &texCoord[0], sampleParams,
442 															lookupPrec, lodPrec, m_testCtx.getWatchDog());
443 			}
444 		}
445 
446 		if (numFailedPixels > 0)
447 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
448 
449 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
450 							<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
451 
452 		if (numFailedPixels > 0)
453 		{
454 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
455 								<< TestLog::Image("ErrorMask", "Error mask", errorMask);
456 		}
457 
458 		m_testCtx.getLog() << TestLog::EndImageSet;
459 
460 		{
461 			const bool isOk = numFailedPixels == 0;
462 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
463 									isOk ? "Pass"				: "Image verification failed");
464 		}
465 	}
466 
467 	return STOP;
468 }
469 
470 // TextureCubeMipmapCase
471 
472 class TextureCubeMipmapCase : public tcu::TestCase
473 {
474 public:
475 
476 								TextureCubeMipmapCase		(tcu::TestContext&			testCtx,
477 															 glu::RenderContext&		renderCtx,
478 															 const glu::ContextInfo&	renderCtxInfo,
479 															 const char*				name,
480 															 const char*				desc,
481 															 CoordType					coordType,
482 															 deUint32					minFilter,
483 															 deUint32					wrapS,
484 															 deUint32					wrapT,
485 															 deUint32					format,
486 															 deUint32					dataType,
487 															 int						size);
488 								~TextureCubeMipmapCase		(void);
489 
490 	void						init						(void);
491 	void						deinit						(void);
492 	IterateResult				iterate						(void);
493 
494 private:
495 								TextureCubeMipmapCase		(const TextureCubeMipmapCase& other);
496 	TextureCubeMipmapCase&		operator=					(const TextureCubeMipmapCase& other);
497 
498 	glu::RenderContext&			m_renderCtx;
499 	const glu::ContextInfo&		m_renderCtxInfo;
500 
501 	CoordType					m_coordType;
502 	deUint32					m_minFilter;
503 	deUint32					m_wrapS;
504 	deUint32					m_wrapT;
505 	deUint32					m_format;
506 	deUint32					m_dataType;
507 	int							m_size;
508 
509 	glu::TextureCube*			m_texture;
510 	TextureRenderer				m_renderer;
511 };
512 
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)513 TextureCubeMipmapCase::TextureCubeMipmapCase (tcu::TestContext&			testCtx,
514 											  glu::RenderContext&		renderCtx,
515 											  const glu::ContextInfo&	renderCtxInfo,
516 											  const char*				name,
517 											  const char*				desc,
518 											  CoordType					coordType,
519 											  deUint32					minFilter,
520 											  deUint32					wrapS,
521 											  deUint32					wrapT,
522 											  deUint32					format,
523 											  deUint32					dataType,
524 											  int						size)
525 	: TestCase			(testCtx, name, desc)
526 	, m_renderCtx		(renderCtx)
527 	, m_renderCtxInfo	(renderCtxInfo)
528 	, m_coordType		(coordType)
529 	, m_minFilter		(minFilter)
530 	, m_wrapS			(wrapS)
531 	, m_wrapT			(wrapT)
532 	, m_format			(format)
533 	, m_dataType		(dataType)
534 	, m_size			(size)
535 	, m_texture			(DE_NULL)
536 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
537 {
538 }
539 
~TextureCubeMipmapCase(void)540 TextureCubeMipmapCase::~TextureCubeMipmapCase (void)
541 {
542 	deinit();
543 }
544 
init(void)545 void TextureCubeMipmapCase::init (void)
546 {
547 	if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
548 		throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
549 
550 	m_texture = new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_size);
551 
552 	int numLevels = deLog2Floor32(m_size)+1;
553 
554 	// Fill texture with colored grid.
555 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
556 	{
557 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
558 		{
559 			deUint32	step		= 0xff / (numLevels-1);
560 			deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
561 			deUint32	dec			= 0xff - inc;
562 			deUint32	rgb			= 0;
563 
564 			switch (faceNdx)
565 			{
566 				case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
567 				case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
568 				case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
569 				case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
570 				case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
571 				case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
572 			}
573 
574 			deUint32	color		= 0xff000000 | rgb;
575 
576 			m_texture->getRefTexture().allocLevel((tcu::CubeFace)faceNdx, levelNdx);
577 			tcu::clear(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
578 		}
579 	}
580 }
581 
deinit(void)582 void TextureCubeMipmapCase::deinit (void)
583 {
584 	delete m_texture;
585 	m_texture = DE_NULL;
586 
587 	m_renderer.clear();
588 }
589 
randomPartition(vector<IVec4> & dst,de::Random & rnd,int x,int y,int width,int height)590 static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
591 {
592 	const int minWidth	= 8;
593 	const int minHeight	= 8;
594 
595 	bool	partition		= rnd.getFloat() > 0.4f;
596 	bool	partitionX		= partition && width > minWidth && rnd.getBool();
597 	bool	partitionY		= partition && height > minHeight && !partitionX;
598 
599 	if (partitionX)
600 	{
601 		int split = width/2 + rnd.getInt(-width/4, +width/4);
602 		randomPartition(dst, rnd, x, y, split, height);
603 		randomPartition(dst, rnd, x+split, y, width-split, height);
604 	}
605 	else if (partitionY)
606 	{
607 		int split = height/2 + rnd.getInt(-height/4, +height/4);
608 		randomPartition(dst, rnd, x, y, width, split);
609 		randomPartition(dst, rnd, x, y+split, width, height-split);
610 	}
611 	else
612 		dst.push_back(IVec4(x, y, width, height));
613 }
614 
computeGridLayout(vector<IVec4> & dst,int width,int height)615 static void computeGridLayout (vector<IVec4>& dst, int width, int height)
616 {
617 	de::Random rnd(7);
618 	randomPartition(dst, rnd, 0, 0, width, height);
619 }
620 
iterate(void)621 TextureCubeMipmapCase::IterateResult TextureCubeMipmapCase::iterate (void)
622 {
623 	const deUint32			magFilter			= GL_NEAREST;
624 	const int				texWidth			= m_texture->getRefTexture().getSize();
625 	const int				texHeight			= m_texture->getRefTexture().getSize();
626 	const int				defViewportWidth	= texWidth*2;
627 	const int				defViewportHeight	= texHeight*2;
628 
629 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
630 	const RandomViewport	viewport			(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
631 
632 	const bool				isProjected			= m_coordType == COORDTYPE_PROJECTED;
633 	const bool				useLodBias			= m_coordType == COORDTYPE_BASIC_BIAS;
634 
635 	vector<float>			texCoord;
636 	tcu::Surface			renderedFrame		(viewport.width, viewport.height);
637 
638 	// Bail out if rendertarget is too small.
639 	if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
640 		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
641 
642 	// Upload texture data.
643 	m_texture->upload();
644 
645 	// Bind gradient texture and setup sampler parameters.
646 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
647 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
648 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
649 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
650 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
651 
652 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
653 
654 	// Compute grid.
655 	vector<IVec4> gridLayout;
656 	computeGridLayout(gridLayout, viewport.width, viewport.height);
657 
658 	// Bias values.
659 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
660 
661 	// Projection values \note Less agressive than in 2D case due to smaller quads.
662 	static const Vec4 s_projections[] =
663 	{
664 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
665 		Vec4(1.3f, 0.8f, 0.6f, 1.1f),
666 		Vec4(0.8f, 1.0f, 1.2f, 0.8f),
667 		Vec4(1.2f, 1.0f, 1.3f, 0.9f)
668 	};
669 
670 	// Render with GL
671 	for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
672 	{
673 		const int			curX		= gridLayout[cellNdx].x();
674 		const int			curY		= gridLayout[cellNdx].y();
675 		const int			curW		= gridLayout[cellNdx].z();
676 		const int			curH		= gridLayout[cellNdx].w();
677 		const tcu::CubeFace	cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
678 		RenderParams		params		(TEXTURETYPE_CUBE);
679 
680 		DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
681 		computeQuadTexCoordCube(texCoord, cubeFace);
682 
683 		if (isProjected)
684 		{
685 			params.flags	|= ReferenceParams::PROJECTED;
686 			params.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
687 		}
688 
689 		if (useLodBias)
690 		{
691 			params.flags	|= ReferenceParams::USE_BIAS;
692 			params.bias		 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
693 		}
694 
695 		// Render with GL.
696 		gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
697 		m_renderer.renderQuad(0, &texCoord[0], params);
698 	}
699 	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
700 
701 	// Read result.
702 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
703 	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
704 
705 	// Render reference and compare
706 	{
707 		tcu::Surface			referenceFrame		(viewport.width, viewport.height);
708 		tcu::Surface			errorMask			(viewport.width, viewport.height);
709 		int						numFailedPixels		= 0;
710 		ReferenceParams			params				(TEXTURETYPE_CUBE);
711 		tcu::LookupPrecision	lookupPrec;
712 		tcu::LodPrecision		lodPrec;
713 
714 		// Params for rendering reference
715 		params.sampler					= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
716 		params.sampler.seamlessCubeMap	= true;
717 		params.lodMode					= LODMODE_EXACT;
718 
719 		// Comparison parameters
720 		lookupPrec.colorMask			= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
721 		lookupPrec.colorThreshold		= tcu::computeFixedPointThreshold(max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0)));
722 		lookupPrec.coordBits			= isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
723 		lookupPrec.uvwBits				= tcu::IVec3(5,5,0);
724 		lodPrec.derivateBits			= 10;
725 		lodPrec.lodBits					= isProjected ? 3 : 6;
726 
727 		for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
728 		{
729 			const int				curX		= gridLayout[cellNdx].x();
730 			const int				curY		= gridLayout[cellNdx].y();
731 			const int				curW		= gridLayout[cellNdx].z();
732 			const int				curH		= gridLayout[cellNdx].w();
733 			const tcu::CubeFace		cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
734 
735 			DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
736 			computeQuadTexCoordCube(texCoord, cubeFace);
737 
738 			if (isProjected)
739 			{
740 				params.flags	|= ReferenceParams::PROJECTED;
741 				params.w		 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
742 			}
743 
744 			if (useLodBias)
745 			{
746 				params.flags	|= ReferenceParams::USE_BIAS;
747 				params.bias		 = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
748 			}
749 
750 			// Render ideal reference.
751 			{
752 				tcu::SurfaceAccess idealDst(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
753 				sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
754 			}
755 
756 			// Compare this cell
757 			numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
758 														tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
759 														tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
760 														m_texture->getRefTexture(), &texCoord[0], params,
761 														lookupPrec, lodPrec, m_testCtx.getWatchDog());
762 		}
763 
764 		if (numFailedPixels > 0)
765 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
766 
767 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
768 						   << TestLog::Image("Rendered", "Rendered image", renderedFrame);
769 
770 		if (numFailedPixels > 0)
771 		{
772 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
773 							   << TestLog::Image("ErrorMask", "Error mask", errorMask);
774 		}
775 
776 		m_testCtx.getLog() << TestLog::EndImageSet;
777 
778 		{
779 			const bool isOk = numFailedPixels == 0;
780 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
781 									isOk ? "Pass"				: "Image verification failed");
782 		}
783 	}
784 
785 	return STOP;
786 }
787 
788 // Texture2DGenMipmapCase
789 
790 class Texture2DGenMipmapCase : public tcu::TestCase
791 {
792 public:
793 
794 								Texture2DGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height);
795 								~Texture2DGenMipmapCase		(void);
796 
797 	void						init						(void);
798 	void						deinit						(void);
799 	IterateResult				iterate						(void);
800 
801 private:
802 								Texture2DGenMipmapCase		(const Texture2DGenMipmapCase& other);
803 	Texture2DGenMipmapCase&		operator=					(const Texture2DGenMipmapCase& other);
804 
805 	glu::RenderContext&			m_renderCtx;
806 
807 	deUint32					m_format;
808 	deUint32					m_dataType;
809 	deUint32					m_hint;
810 	int							m_width;
811 	int							m_height;
812 
813 	glu::Texture2D*				m_texture;
814 	TextureRenderer				m_renderer;
815 };
816 
Texture2DGenMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,deUint32 format,deUint32 dataType,deUint32 hint,int width,int height)817 Texture2DGenMipmapCase::Texture2DGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height)
818 	: TestCase			(testCtx, name, desc)
819 	, m_renderCtx		(renderCtx)
820 	, m_format			(format)
821 	, m_dataType		(dataType)
822 	, m_hint			(hint)
823 	, m_width			(width)
824 	, m_height			(height)
825 	, m_texture			(DE_NULL)
826 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
827 {
828 }
829 
~Texture2DGenMipmapCase(void)830 Texture2DGenMipmapCase::~Texture2DGenMipmapCase (void)
831 {
832 	deinit();
833 }
834 
init(void)835 void Texture2DGenMipmapCase::init (void)
836 {
837 	DE_ASSERT(!m_texture);
838 	m_texture = new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
839 }
840 
deinit(void)841 void Texture2DGenMipmapCase::deinit (void)
842 {
843 	delete m_texture;
844 	m_texture = DE_NULL;
845 
846 	m_renderer.clear();
847 }
848 
iterate(void)849 Texture2DGenMipmapCase::IterateResult Texture2DGenMipmapCase::iterate (void)
850 {
851 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
852 
853 	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
854 	const deUint32			magFilter			= GL_NEAREST;
855 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
856 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
857 
858 	const int				numLevels			= deLog2Floor32(de::max(m_width, m_height))+1;
859 
860 	tcu::Texture2D			resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight());
861 
862 	vector<float>			texCoord;
863 
864 	// Initialize texture level 0 with colored grid.
865 	m_texture->getRefTexture().allocLevel(0);
866 	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));
867 
868 	// Upload data and setup params.
869 	m_texture->upload();
870 
871 	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
872 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		wrapS);
873 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		wrapT);
874 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	minFilter);
875 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
876 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
877 
878 	// Generate mipmap.
879 	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
880 	gl.generateMipmap(GL_TEXTURE_2D);
881 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
882 
883 	// Use (0, 0) -> (1, 1) texture coordinates.
884 	computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
885 
886 	// Fetch resulting texture by rendering.
887 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
888 	{
889 		const int				levelWidth		= de::max(1, m_width >> levelNdx);
890 		const int				levelHeight		= de::max(1, m_height >> levelNdx);
891 		const RandomViewport	viewport		(m_renderCtx.getRenderTarget(), levelWidth, levelHeight, deStringHash(getName()) + levelNdx);
892 
893 		gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
894 		m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
895 
896 		resultTexture.allocLevel(levelNdx);
897 		glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevel(levelNdx));
898 	}
899 
900 	// Compare results
901 	{
902 		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
903 		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
904 		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
905 		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
906 		GenMipmapPrecision	comparePrec;
907 
908 		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
909 		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
910 		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
911 
912 		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
913 
914 		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
915 											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
916 											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
917 	}
918 
919 	return STOP;
920 }
921 
922 // TextureCubeGenMipmapCase
923 
924 class TextureCubeGenMipmapCase : public tcu::TestCase
925 {
926 public:
927 
928 								TextureCubeGenMipmapCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size);
929 								~TextureCubeGenMipmapCase		(void);
930 
931 	void						init							(void);
932 	void						deinit							(void);
933 	IterateResult				iterate							(void);
934 
935 private:
936 								TextureCubeGenMipmapCase		(const TextureCubeGenMipmapCase& other);
937 	TextureCubeGenMipmapCase&	operator=						(const TextureCubeGenMipmapCase& other);
938 
939 	glu::RenderContext&			m_renderCtx;
940 
941 	deUint32					m_format;
942 	deUint32					m_dataType;
943 	deUint32					m_hint;
944 	int							m_size;
945 
946 	glu::TextureCube*			m_texture;
947 	TextureRenderer				m_renderer;
948 };
949 
TextureCubeGenMipmapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,deUint32 format,deUint32 dataType,deUint32 hint,int size)950 TextureCubeGenMipmapCase::TextureCubeGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size)
951 	: TestCase			(testCtx, name, desc)
952 	, m_renderCtx		(renderCtx)
953 	, m_format			(format)
954 	, m_dataType		(dataType)
955 	, m_hint			(hint)
956 	, m_size			(size)
957 	, m_texture			(DE_NULL)
958 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
959 {
960 }
961 
~TextureCubeGenMipmapCase(void)962 TextureCubeGenMipmapCase::~TextureCubeGenMipmapCase (void)
963 {
964 	deinit();
965 }
966 
init(void)967 void TextureCubeGenMipmapCase::init (void)
968 {
969 	if (m_renderCtx.getRenderTarget().getWidth() < 3*m_size || m_renderCtx.getRenderTarget().getHeight() < 2*m_size)
970 		throw tcu::NotSupportedError("Render target size must be at least (" + de::toString(3*m_size) + ", " + de::toString(2*m_size) + ")");
971 
972 	DE_ASSERT(!m_texture);
973 	m_texture = new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_size);
974 }
975 
deinit(void)976 void TextureCubeGenMipmapCase::deinit (void)
977 {
978 	delete m_texture;
979 	m_texture = DE_NULL;
980 
981 	m_renderer.clear();
982 }
983 
iterate(void)984 TextureCubeGenMipmapCase::IterateResult TextureCubeGenMipmapCase::iterate (void)
985 {
986 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
987 
988 	const deUint32			minFilter			= GL_NEAREST_MIPMAP_NEAREST;
989 	const deUint32			magFilter			= GL_NEAREST;
990 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
991 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
992 
993 	tcu::TextureCube		resultTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_size);
994 
995 	const int				numLevels			= deLog2Floor32(m_size)+1;
996 	vector<float>			texCoord;
997 
998 	// Initialize texture level 0 with colored grid.
999 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1000 	{
1001 		Vec4 ca, cb; // Grid colors.
1002 
1003 		switch (face)
1004 		{
1005 			case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
1006 			case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
1007 			case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
1008 			case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
1009 			case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
1010 			case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
1011 		}
1012 
1013 		m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
1014 		fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
1015 	}
1016 
1017 	// Upload data and setup params.
1018 	m_texture->upload();
1019 
1020 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
1021 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		wrapS);
1022 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		wrapT);
1023 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	minFilter);
1024 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
1025 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1026 
1027 	// Generate mipmap.
1028 	gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
1029 	gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
1030 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
1031 
1032 	// Render all levels.
1033 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1034 	{
1035 		const int	levelWidth	= de::max(1, m_size >> levelNdx);
1036 		const int	levelHeight	= de::max(1, m_size >> levelNdx);
1037 
1038 		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1039 		{
1040 			const RandomViewport	viewport	(m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1041 			const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
1042 
1043 			computeQuadTexCoordCube(texCoord, face);
1044 
1045 			gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1046 			m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1047 
1048 			resultTexture.allocLevel(face, levelNdx);
1049 			glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1050 		}
1051 	}
1052 
1053 	// Compare results
1054 	{
1055 		const IVec4			framebufferBits		= max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1056 		const IVec4			formatBits			= tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1057 		const tcu::BVec4	formatMask			= greaterThan(formatBits, IVec4(0));
1058 		const IVec4			cmpBits				= select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1059 		GenMipmapPrecision	comparePrec;
1060 
1061 		comparePrec.colorMask		= getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1062 		comparePrec.colorThreshold	= tcu::computeFixedPointThreshold(cmpBits);
1063 		comparePrec.filterBits		= tcu::IVec3(4, 4, 0);
1064 
1065 		const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1066 
1067 		m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS				? "Pass" :
1068 											   compareResult == QP_TEST_RESULT_QUALITY_WARNING	? "Low-quality method used"	:
1069 											   compareResult == QP_TEST_RESULT_FAIL				? "Image comparison failed"	: "");
1070 	}
1071 
1072 	return STOP;
1073 }
1074 
1075 // Texture3DMipmapCase
1076 
1077 class Texture3DMipmapCase : public TestCase
1078 {
1079 public:
1080 
1081 								Texture3DMipmapCase			(Context&					context,
1082 															 const char*				name,
1083 															 const char*				desc,
1084 															 CoordType					coordType,
1085 															 deUint32					minFilter,
1086 															 deUint32					wrapS,
1087 															 deUint32					wrapT,
1088 															 deUint32					wrapR,
1089 															 deUint32					format,
1090 															 int						width,
1091 															 int						height,
1092 															 int						depth);
1093 								~Texture3DMipmapCase		(void);
1094 
1095 	void						init						(void);
1096 	void						deinit						(void);
1097 	IterateResult				iterate						(void);
1098 
1099 private:
1100 								Texture3DMipmapCase			(const Texture3DMipmapCase& other);
1101 	Texture3DMipmapCase&		operator=					(const Texture3DMipmapCase& other);
1102 
1103 	CoordType					m_coordType;
1104 	deUint32					m_minFilter;
1105 	deUint32					m_wrapS;
1106 	deUint32					m_wrapT;
1107 	deUint32					m_wrapR;
1108 	deUint32					m_internalFormat;
1109 	int							m_width;
1110 	int							m_height;
1111 	int							m_depth;
1112 
1113 	glu::Texture3D*						m_texture;
1114 	TextureTestUtil::TextureRenderer	m_renderer;
1115 };
1116 
Texture3DMipmapCase(Context & context,const char * name,const char * desc,CoordType coordType,deUint32 minFilter,deUint32 wrapS,deUint32 wrapT,deUint32 wrapR,deUint32 format,int width,int height,int depth)1117 Texture3DMipmapCase::Texture3DMipmapCase (Context& context, const char* name, const char* desc, CoordType coordType, deUint32 minFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 format, int width, int height, int depth)
1118 	: TestCase			(context, name, desc)
1119 	, m_coordType		(coordType)
1120 	, m_minFilter		(minFilter)
1121 	, m_wrapS			(wrapS)
1122 	, m_wrapT			(wrapT)
1123 	, m_wrapR			(wrapR)
1124 	, m_internalFormat	(format)
1125 	, m_width			(width)
1126 	, m_height			(height)
1127 	, m_depth			(depth)
1128 	, m_texture			(DE_NULL)
1129 	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1130 {
1131 }
1132 
~Texture3DMipmapCase(void)1133 Texture3DMipmapCase::~Texture3DMipmapCase (void)
1134 {
1135 	Texture3DMipmapCase::deinit();
1136 }
1137 
init(void)1138 void Texture3DMipmapCase::init (void)
1139 {
1140 	const tcu::TextureFormat&		texFmt			= glu::mapGLInternalFormat(m_internalFormat);
1141 	tcu::TextureFormatInfo			fmtInfo			= tcu::getTextureFormatInfo(texFmt);
1142 	const tcu::Vec4&				cScale			= fmtInfo.lookupScale;
1143 	const tcu::Vec4&				cBias			= fmtInfo.lookupBias;
1144 	int								numLevels		= deLog2Floor32(de::max(de::max(m_width, m_height), m_depth))+1;
1145 
1146 	if (m_coordType == COORDTYPE_PROJECTED && m_context.getRenderTarget().getNumSamples() > 0)
1147 		throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
1148 
1149 	m_texture = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1150 
1151 	// Fill texture with colored grid.
1152 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1153 	{
1154 		deUint32	step		= 0xff / (numLevels-1);
1155 		deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
1156 		deUint32	dec			= 0xff - inc;
1157 		deUint32	rgb			= (0xff << 16) | (dec << 8) | inc;
1158 		deUint32	color		= 0xff000000 | rgb;
1159 
1160 		m_texture->getRefTexture().allocLevel(levelNdx);
1161 		tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec()*cScale + cBias);
1162 	}
1163 
1164 	m_texture->upload();
1165 }
1166 
deinit(void)1167 void Texture3DMipmapCase::deinit (void)
1168 {
1169 	delete m_texture;
1170 	m_texture = DE_NULL;
1171 
1172 	m_renderer.clear();
1173 }
1174 
getBasicTexCoord3D(std::vector<float> & dst,int cellNdx)1175 static void getBasicTexCoord3D (std::vector<float>& dst, int cellNdx)
1176 {
1177 	static const struct
1178 	{
1179 		float sScale;
1180 		float sBias;
1181 		float tScale;
1182 		float tBias;
1183 		float rScale;
1184 		float rBias;
1185 	} s_params[] =
1186 	{
1187 	//		sScale	sBias	tScale	tBias	rScale	rBias
1188 		{	 0.9f,	-0.1f,	 0.7f,	 0.3f,	 0.8f,	 0.9f	},
1189 		{	 1.2f,	-0.1f,	 1.1f,	 0.3f,	 1.0f,	 0.9f	},
1190 		{	 1.5f,	 0.7f,	 0.9f,	-0.3f,	 1.1f,	 0.1f	},
1191 		{	 1.2f,	 0.7f,	-2.3f,	-0.3f,	 1.1f,	 0.2f	},
1192 		{	 1.1f,	 0.8f,	-1.3f,	-0.3f,	 2.9f,	 0.9f	},
1193 		{	 3.4f,	 0.8f,	 4.0f,	 0.0f,	-3.3f,	-1.0f	},
1194 		{	-3.4f,	-0.1f,	-4.0f,	 0.0f,	-5.1f,	 1.0f	},
1195 		{	-4.0f,	-0.1f,	 3.4f,	 0.1f,	 5.7f,	 0.0f	},
1196 		{	-5.6f,	 0.0f,	 0.5f,	 1.2f,	 3.9f,	 4.0f	},
1197 		{	 5.0f,	-2.0f,	 3.1f,	 1.2f,	 5.1f,	 0.2f	},
1198 		{	 2.5f,	-2.0f,	 6.3f,	 3.0f,	 5.1f,	 0.2f	},
1199 		{	-8.3f,	 0.0f,	 7.1f,	 3.0f,	 2.0f,	 0.2f	},
1200 		{    3.8f,	 0.0f,	 9.7f,	 1.0f,	 7.0f,	 0.7f	},
1201 		{	13.3f,	 0.0f,	 7.1f,	 3.0f,	 2.0f,	 0.2f	},
1202 		{   16.0f,	 8.0f,	12.7f,	 1.0f,	17.1f,	 0.7f	},
1203 		{	15.3f,	 0.0f,	20.1f,	 3.0f,	33.0f,	 3.2f	}
1204 	};
1205 
1206 	float sScale	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sScale;
1207 	float sBias		= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sBias;
1208 	float tScale	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tScale;
1209 	float tBias		= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tBias;
1210 	float rScale	= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rScale;
1211 	float rBias		= s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rBias;
1212 
1213 	dst.resize(3*4);
1214 
1215 	dst[0] = sBias;			dst[ 1] = tBias;			dst[ 2] = rBias;
1216 	dst[3] = sBias;			dst[ 4] = tBias+tScale;		dst[ 5] = rBias+rScale*0.5f;
1217 	dst[6] = sBias+sScale;	dst[ 7] = tBias;			dst[ 8] = rBias+rScale*0.5f;
1218 	dst[9] = sBias+sScale;	dst[10] = tBias+tScale;		dst[11] = rBias+rScale;
1219 }
1220 
getAffineTexCoord3D(std::vector<float> & dst,int cellNdx)1221 static void getAffineTexCoord3D (std::vector<float>& dst, int cellNdx)
1222 {
1223 	// Use basic coords as base.
1224 	getBasicTexCoord3D(dst, cellNdx);
1225 
1226 	// Rotate based on cell index.
1227 	float		angleX		= 0.0f + 2.0f*DE_PI * ((float)cellNdx / 16.0f);
1228 	float		angleY		= 1.0f + 2.0f*DE_PI * ((float)cellNdx / 32.0f);
1229 	tcu::Mat3	rotMatrix	= tcu::rotationMatrixX(angleX) * tcu::rotationMatrixY(angleY);
1230 
1231 	Vec3		p0			= rotMatrix * Vec3(dst[0], dst[ 1], dst[ 2]);
1232 	Vec3		p1			= rotMatrix * Vec3(dst[3], dst[ 4], dst[ 5]);
1233 	Vec3		p2			= rotMatrix * Vec3(dst[6], dst[ 7], dst[ 8]);
1234 	Vec3		p3			= rotMatrix * Vec3(dst[9], dst[10], dst[11]);
1235 
1236 	dst[0] = p0.x();	dst[ 1] = p0.y();	dst[ 2] = p0.z();
1237 	dst[3] = p1.x();	dst[ 4] = p1.y();	dst[ 5] = p1.z();
1238 	dst[6] = p2.x();	dst[ 7] = p2.y();	dst[ 8] = p2.z();
1239 	dst[9] = p3.x();	dst[10] = p3.y();	dst[11] = p3.z();
1240 }
1241 
iterate(void)1242 Texture3DMipmapCase::IterateResult Texture3DMipmapCase::iterate (void)
1243 {
1244 	const glw::Functions&			gl					= m_context.getRenderContext().getFunctions();
1245 
1246 	const tcu::Texture3D&			refTexture			= m_texture->getRefTexture();
1247 	const tcu::TextureFormat&		texFmt				= refTexture.getFormat();
1248 	const tcu::TextureFormatInfo	fmtInfo				= tcu::getTextureFormatInfo(texFmt);
1249 	const int						texWidth			= refTexture.getWidth();
1250 	const int						texHeight			= refTexture.getHeight();
1251 	const deUint32					magFilter			= GL_NEAREST;
1252 
1253 	const tcu::RenderTarget&		renderTarget		= m_context.getRenderContext().getRenderTarget();
1254 	const RandomViewport			viewport			(renderTarget, texWidth*4, texHeight*4, deStringHash(getName()));
1255 
1256 	const bool						isProjected			= m_coordType == COORDTYPE_PROJECTED;
1257 	const bool						useLodBias			= m_coordType == COORDTYPE_BASIC_BIAS;
1258 
1259 	// Viewport is divided into 4x4 grid.
1260 	const int						gridWidth			= 4;
1261 	const int						gridHeight			= 4;
1262 	const int						cellWidth			= viewport.width / gridWidth;
1263 	const int						cellHeight			= viewport.height / gridHeight;
1264 
1265 	ReferenceParams					sampleParams		(TEXTURETYPE_3D);
1266 
1267 	tcu::Surface					renderedFrame		(viewport.width, viewport.height);
1268 	vector<float>					texCoord;
1269 
1270 	// Sampling parameters.
1271 	sampleParams.sampler		= glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, magFilter);
1272 	sampleParams.samplerType	= getSamplerType(texFmt);
1273 	sampleParams.colorBias		= fmtInfo.lookupBias;
1274 	sampleParams.colorScale		= fmtInfo.lookupScale;
1275 	sampleParams.flags			= (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
1276 
1277 	// Bind texture and setup sampler parameters.
1278 	gl.bindTexture	(GL_TEXTURE_3D, m_texture->getGLTexture());
1279 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,		m_wrapS);
1280 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,		m_wrapT);
1281 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,		m_wrapR);
1282 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1283 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,	magFilter);
1284 
1285 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1286 
1287 	// Bias values.
1288 	static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
1289 
1290 	// Projection values.
1291 	static const Vec4 s_projections[] =
1292 	{
1293 		Vec4(1.2f, 1.0f, 0.7f, 1.0f),
1294 		Vec4(1.3f, 0.8f, 0.6f, 2.0f),
1295 		Vec4(0.8f, 1.0f, 1.7f, 0.6f),
1296 		Vec4(1.2f, 1.0f, 1.7f, 1.5f)
1297 	};
1298 
1299 	// Render cells.
1300 	for (int gridY = 0; gridY < gridHeight; gridY++)
1301 	{
1302 		for (int gridX = 0; gridX < gridWidth; gridX++)
1303 		{
1304 			const int		curX		= cellWidth*gridX;
1305 			const int		curY		= cellHeight*gridY;
1306 			const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1307 			const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1308 			const int		cellNdx		= gridY*gridWidth + gridX;
1309 
1310 			// Compute texcoord.
1311 			switch (m_coordType)
1312 			{
1313 				case COORDTYPE_BASIC_BIAS:	// Fall-through.
1314 				case COORDTYPE_PROJECTED:
1315 				case COORDTYPE_BASIC:		getBasicTexCoord3D	(texCoord, cellNdx);	break;
1316 				case COORDTYPE_AFFINE:		getAffineTexCoord3D	(texCoord, cellNdx);	break;
1317 				default:					DE_ASSERT(DE_FALSE);
1318 			}
1319 
1320 			// Set projection.
1321 			if (isProjected)
1322 				sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
1323 
1324 			// Set LOD bias.
1325 			if (useLodBias)
1326 				sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
1327 
1328 			// Render with GL.
1329 			gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
1330 			m_renderer.renderQuad(0, &texCoord[0], sampleParams);
1331 		}
1332 	}
1333 
1334 	// Read result.
1335 	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
1336 
1337 	// Compare and log
1338 	{
1339 		const tcu::PixelFormat&	pixelFormat		= m_context.getRenderTarget().getPixelFormat();
1340 		const bool				isTrilinear		= m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
1341 		tcu::Surface			referenceFrame	(viewport.width, viewport.height);
1342 		tcu::Surface			errorMask		(viewport.width, viewport.height);
1343 		tcu::LookupPrecision	lookupPrec;
1344 		tcu::LodPrecision		lodPrec;
1345 		int						numFailedPixels	= 0;
1346 
1347 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 20);
1348 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
1349 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
1350 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
1351 		lodPrec.derivateBits		= 10;
1352 		lodPrec.lodBits				= isProjected ? 6 : 8;
1353 
1354 		for (int gridY = 0; gridY < gridHeight; gridY++)
1355 		{
1356 			for (int gridX = 0; gridX < gridWidth; gridX++)
1357 			{
1358 				const int		curX		= cellWidth*gridX;
1359 				const int		curY		= cellHeight*gridY;
1360 				const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1361 				const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1362 				const int		cellNdx		= gridY*gridWidth + gridX;
1363 
1364 				switch (m_coordType)
1365 				{
1366 					case COORDTYPE_BASIC_BIAS:	// Fall-through.
1367 					case COORDTYPE_PROJECTED:
1368 					case COORDTYPE_BASIC:		getBasicTexCoord3D	(texCoord, cellNdx);	break;
1369 					case COORDTYPE_AFFINE:		getAffineTexCoord3D	(texCoord, cellNdx);	break;
1370 					default:					DE_ASSERT(DE_FALSE);
1371 				}
1372 
1373 				if (isProjected)
1374 					sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
1375 
1376 				if (useLodBias)
1377 					sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
1378 
1379 				// Render ideal result
1380 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
1381 							  refTexture, &texCoord[0], sampleParams);
1382 
1383 				// Compare this cell
1384 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
1385 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
1386 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
1387 															m_texture->getRefTexture(), &texCoord[0], sampleParams,
1388 															lookupPrec, lodPrec, m_testCtx.getWatchDog());
1389 			}
1390 		}
1391 
1392 		if (numFailedPixels > 0)
1393 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1394 
1395 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
1396 							<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
1397 
1398 		if (numFailedPixels > 0)
1399 		{
1400 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
1401 								<< TestLog::Image("ErrorMask", "Error mask", errorMask);
1402 		}
1403 
1404 		m_testCtx.getLog() << TestLog::EndImageSet;
1405 
1406 		{
1407 			const bool isOk = numFailedPixels == 0;
1408 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1409 									isOk ? "Pass"				: "Image verification failed");
1410 		}
1411 	}
1412 
1413 	return STOP;
1414 }
1415 
1416 // Texture2DLodControlCase + test cases
1417 
1418 class Texture2DLodControlCase : public TestCase
1419 {
1420 public:
1421 
1422 										Texture2DLodControlCase		(Context& context, const char* name, const char* desc, deUint32 minFilter);
1423 										~Texture2DLodControlCase	(void);
1424 
1425 	void								init						(void);
1426 	void								deinit						(void);
1427 	IterateResult						iterate						(void);
1428 
1429 protected:
1430 	virtual void						setTextureParams			(int cellNdx)							= DE_NULL;
1431 	virtual void						getReferenceParams			(ReferenceParams& params, int cellNdx)	= DE_NULL;
1432 
1433 	const int							m_texWidth;
1434 	const int							m_texHeight;
1435 
1436 private:
1437 										Texture2DLodControlCase		(const Texture2DLodControlCase& other);
1438 	Texture2DLodControlCase&			operator=					(const Texture2DLodControlCase& other);
1439 
1440 	deUint32							m_minFilter;
1441 
1442 	glu::Texture2D*						m_texture;
1443 	TextureTestUtil::TextureRenderer	m_renderer;
1444 };
1445 
Texture2DLodControlCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1446 Texture2DLodControlCase::Texture2DLodControlCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1447 	: TestCase		(context, name, desc)
1448 	, m_texWidth	(64)
1449 	, m_texHeight	(64)
1450 	, m_minFilter	(minFilter)
1451 	, m_texture		(DE_NULL)
1452 	, m_renderer	(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1453 {
1454 }
1455 
~Texture2DLodControlCase(void)1456 Texture2DLodControlCase::~Texture2DLodControlCase (void)
1457 {
1458 	Texture2DLodControlCase::deinit();
1459 }
1460 
init(void)1461 void Texture2DLodControlCase::init (void)
1462 {
1463 	const deUint32	format		= GL_RGBA8;
1464 	int				numLevels	= deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
1465 
1466 	m_texture = new glu::Texture2D(m_context.getRenderContext(), format, m_texWidth, m_texHeight);
1467 
1468 	// Fill texture with colored grid.
1469 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1470 	{
1471 		deUint32	step		= 0xff / (numLevels-1);
1472 		deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
1473 		deUint32	dec			= 0xff - inc;
1474 		deUint32	rgb			= (inc << 16) | (dec << 8) | 0xff;
1475 		deUint32	color		= 0xff000000 | rgb;
1476 
1477 		m_texture->getRefTexture().allocLevel(levelNdx);
1478 		tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec());
1479 	}
1480 }
1481 
deinit(void)1482 void Texture2DLodControlCase::deinit (void)
1483 {
1484 	delete m_texture;
1485 	m_texture = DE_NULL;
1486 
1487 	m_renderer.clear();
1488 }
1489 
iterate(void)1490 Texture2DLodControlCase::IterateResult Texture2DLodControlCase::iterate (void)
1491 {
1492 	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
1493 
1494 	const deUint32				wrapS				= GL_REPEAT;
1495 	const deUint32				wrapT				= GL_REPEAT;
1496 	const deUint32				magFilter			= GL_NEAREST;
1497 
1498 	const tcu::Texture2D&		refTexture			= m_texture->getRefTexture();
1499 	const int					texWidth			= refTexture.getWidth();
1500 	const int					texHeight			= refTexture.getHeight();
1501 
1502 	const tcu::RenderTarget&	renderTarget		= m_context.getRenderContext().getRenderTarget();
1503 	const RandomViewport		viewport			(renderTarget, texWidth*4, texHeight*4, deStringHash(getName()));
1504 
1505 	ReferenceParams				sampleParams		(TEXTURETYPE_2D, glu::mapGLSampler(wrapS, wrapT, m_minFilter, magFilter));
1506 	vector<float>				texCoord;
1507 	tcu::Surface				renderedFrame		(viewport.width, viewport.height);
1508 
1509 	// Viewport is divided into 4x4 grid.
1510 	const int					gridWidth			= 4;
1511 	const int					gridHeight			= 4;
1512 	const int					cellWidth			= viewport.width / gridWidth;
1513 	const int					cellHeight			= viewport.height / gridHeight;
1514 
1515 	// Upload texture data.
1516 	m_texture->upload();
1517 
1518 	// Bind gradient texture and setup sampler parameters.
1519 	gl.bindTexture	(GL_TEXTURE_2D, m_texture->getGLTexture());
1520 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		wrapS);
1521 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		wrapT);
1522 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1523 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
1524 
1525 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1526 
1527 	// Render cells.
1528 	for (int gridY = 0; gridY < gridHeight; gridY++)
1529 	{
1530 		for (int gridX = 0; gridX < gridWidth; gridX++)
1531 		{
1532 			int				curX		= cellWidth*gridX;
1533 			int				curY		= cellHeight*gridY;
1534 			int				curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1535 			int				curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1536 			int				cellNdx		= gridY*gridWidth + gridX;
1537 
1538 			// Compute texcoord.
1539 			getBasicTexCoord2D(texCoord, cellNdx);
1540 
1541 			// Render with GL.
1542 			setTextureParams(cellNdx);
1543 			gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
1544 			m_renderer.renderQuad(0, &texCoord[0], sampleParams);
1545 		}
1546 	}
1547 
1548 	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
1549 	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
1550 
1551 	// Compare and log.
1552 	{
1553 		const tcu::PixelFormat&	pixelFormat		= m_context.getRenderTarget().getPixelFormat();
1554 		const bool				isTrilinear		= m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
1555 		tcu::Surface			referenceFrame	(viewport.width, viewport.height);
1556 		tcu::Surface			errorMask		(viewport.width, viewport.height);
1557 		tcu::LookupPrecision	lookupPrec;
1558 		tcu::LodPrecision		lodPrec;
1559 		int						numFailedPixels	= 0;
1560 
1561 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 0);
1562 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
1563 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
1564 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
1565 		lodPrec.derivateBits		= 10;
1566 		lodPrec.lodBits				= 8;
1567 
1568 		for (int gridY = 0; gridY < gridHeight; gridY++)
1569 		{
1570 			for (int gridX = 0; gridX < gridWidth; gridX++)
1571 			{
1572 				const int		curX		= cellWidth*gridX;
1573 				const int		curY		= cellHeight*gridY;
1574 				const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1575 				const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1576 				const int		cellNdx		= gridY*gridWidth + gridX;
1577 
1578 				getBasicTexCoord2D(texCoord, cellNdx);
1579 				getReferenceParams(sampleParams, cellNdx);
1580 
1581 				// Render ideal result
1582 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
1583 							  refTexture, &texCoord[0], sampleParams);
1584 
1585 				// Compare this cell
1586 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
1587 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
1588 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
1589 															m_texture->getRefTexture(), &texCoord[0], sampleParams,
1590 															lookupPrec, lodPrec, m_testCtx.getWatchDog());
1591 			}
1592 		}
1593 
1594 		if (numFailedPixels > 0)
1595 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1596 
1597 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
1598 							<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
1599 
1600 		if (numFailedPixels > 0)
1601 		{
1602 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
1603 								<< TestLog::Image("ErrorMask", "Error mask", errorMask);
1604 		}
1605 
1606 		m_testCtx.getLog() << TestLog::EndImageSet;
1607 
1608 		{
1609 			const bool isOk = numFailedPixels == 0;
1610 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1611 									isOk ? "Pass"				: "Image verification failed");
1612 		}
1613 	}
1614 
1615 	return STOP;
1616 }
1617 
1618 class Texture2DMinLodCase : public Texture2DLodControlCase
1619 {
1620 public:
Texture2DMinLodCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1621 	Texture2DMinLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1622 		: Texture2DLodControlCase(context, name, desc, minFilter)
1623 	{
1624 	}
1625 
1626 protected:
setTextureParams(int cellNdx)1627 	void setTextureParams (int cellNdx)
1628 	{
1629 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1630 		gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, getMinLodForCell(cellNdx));
1631 	}
1632 
getReferenceParams(ReferenceParams & params,int cellNdx)1633 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1634 	{
1635 		params.minLod = getMinLodForCell(cellNdx);
1636 	}
1637 };
1638 
1639 class Texture2DMaxLodCase : public Texture2DLodControlCase
1640 {
1641 public:
Texture2DMaxLodCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1642 	Texture2DMaxLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1643 		: Texture2DLodControlCase(context, name, desc, minFilter)
1644 	{
1645 	}
1646 
1647 protected:
setTextureParams(int cellNdx)1648 	void setTextureParams (int cellNdx)
1649 	{
1650 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1651 		gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, getMaxLodForCell(cellNdx));
1652 	}
1653 
getReferenceParams(ReferenceParams & params,int cellNdx)1654 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1655 	{
1656 		params.maxLod = getMaxLodForCell(cellNdx);
1657 	}
1658 };
1659 
1660 class Texture2DBaseLevelCase : public Texture2DLodControlCase
1661 {
1662 public:
Texture2DBaseLevelCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1663 	Texture2DBaseLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1664 		: Texture2DLodControlCase(context, name, desc, minFilter)
1665 	{
1666 	}
1667 
1668 protected:
getBaseLevel(int cellNdx) const1669 	int getBaseLevel (int cellNdx) const
1670 	{
1671 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
1672 		const int	baseLevel	= (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0xac2f274a) % numLevels;
1673 
1674 		return baseLevel;
1675 	}
1676 
setTextureParams(int cellNdx)1677 	void setTextureParams (int cellNdx)
1678 	{
1679 		const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
1680 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, getBaseLevel(cellNdx));
1681 	}
1682 
getReferenceParams(ReferenceParams & params,int cellNdx)1683 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1684 	{
1685 		params.baseLevel = getBaseLevel(cellNdx);
1686 	}
1687 };
1688 
1689 class Texture2DMaxLevelCase : public Texture2DLodControlCase
1690 {
1691 public:
Texture2DMaxLevelCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1692 	Texture2DMaxLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1693 		: Texture2DLodControlCase(context, name, desc, minFilter)
1694 	{
1695 	}
1696 
1697 protected:
getMaxLevel(int cellNdx) const1698 	int getMaxLevel (int cellNdx) const
1699 	{
1700 		const int		numLevels	= deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
1701 		const int		maxLevel	= (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x82cfa4e) % numLevels;
1702 
1703 		return maxLevel;
1704 	}
1705 
setTextureParams(int cellNdx)1706 	void setTextureParams (int cellNdx)
1707 	{
1708 		const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
1709 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, getMaxLevel(cellNdx));
1710 	}
1711 
getReferenceParams(ReferenceParams & params,int cellNdx)1712 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1713 	{
1714 		params.maxLevel = getMaxLevel(cellNdx);
1715 	}
1716 };
1717 
1718 // TextureCubeLodControlCase + test cases
1719 
1720 class TextureCubeLodControlCase : public TestCase
1721 {
1722 public:
1723 
1724 										TextureCubeLodControlCase	(Context& context, const char* name, const char* desc, deUint32 minFilter);
1725 										~TextureCubeLodControlCase	(void);
1726 
1727 	void								init						(void);
1728 	void								deinit						(void);
1729 	IterateResult						iterate						(void);
1730 
1731 protected:
1732 	virtual void						setTextureParams			(int cellNdx)							= DE_NULL;
1733 	virtual void						getReferenceParams			(ReferenceParams& params, int cellNdx)	= DE_NULL;
1734 
1735 	const int							m_texSize;
1736 
1737 private:
1738 										TextureCubeLodControlCase	(const TextureCubeLodControlCase& other);
1739 	TextureCubeLodControlCase&			operator=					(const TextureCubeLodControlCase& other);
1740 
1741 	deUint32							m_minFilter;
1742 
1743 	glu::TextureCube*					m_texture;
1744 	TextureTestUtil::TextureRenderer	m_renderer;
1745 };
1746 
TextureCubeLodControlCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1747 TextureCubeLodControlCase::TextureCubeLodControlCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1748 	: TestCase			(context, name, desc)
1749 	, m_texSize			(64)
1750 	, m_minFilter		(minFilter)
1751 	, m_texture			(DE_NULL)
1752 	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1753 {
1754 }
1755 
~TextureCubeLodControlCase(void)1756 TextureCubeLodControlCase::~TextureCubeLodControlCase (void)
1757 {
1758 	deinit();
1759 }
1760 
init(void)1761 void TextureCubeLodControlCase::init (void)
1762 {
1763 	const deUint32	format		= GL_RGBA8;
1764 	const int		numLevels	= deLog2Floor32(m_texSize)+1;
1765 
1766 	m_texture = new glu::TextureCube(m_context.getRenderContext(), format, m_texSize);
1767 
1768 	// Fill texture with colored grid.
1769 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1770 	{
1771 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1772 		{
1773 			deUint32	step		= 0xff / (numLevels-1);
1774 			deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
1775 			deUint32	dec			= 0xff - inc;
1776 			deUint32	rgb			= 0;
1777 
1778 			switch (faceNdx)
1779 			{
1780 				case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
1781 				case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
1782 				case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
1783 				case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
1784 				case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
1785 				case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
1786 			}
1787 
1788 			deUint32	color		= 0xff000000 | rgb;
1789 
1790 			m_texture->getRefTexture().allocLevel((tcu::CubeFace)faceNdx, levelNdx);
1791 			tcu::clear(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
1792 		}
1793 	}
1794 }
1795 
deinit(void)1796 void TextureCubeLodControlCase::deinit (void)
1797 {
1798 	delete m_texture;
1799 	m_texture = DE_NULL;
1800 
1801 	m_renderer.clear();
1802 }
1803 
iterate(void)1804 TextureCubeLodControlCase::IterateResult TextureCubeLodControlCase::iterate (void)
1805 {
1806 	const deUint32			wrapS				= GL_CLAMP_TO_EDGE;
1807 	const deUint32			wrapT				= GL_CLAMP_TO_EDGE;
1808 	const deUint32			magFilter			= GL_NEAREST;
1809 
1810 	const int				texWidth			= m_texture->getRefTexture().getSize();
1811 	const int				texHeight			= m_texture->getRefTexture().getSize();
1812 
1813 	const int				defViewportWidth	= texWidth*2;
1814 	const int				defViewportHeight	= texHeight*2;
1815 
1816 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1817 	const RandomViewport	viewport			(m_context.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
1818 
1819 	vector<float>			texCoord;
1820 
1821 	tcu::Surface			renderedFrame		(viewport.width, viewport.height);
1822 
1823 	// Upload texture data.
1824 	m_texture->upload();
1825 
1826 	// Bind gradient texture and setup sampler parameters.
1827 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
1828 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		wrapS);
1829 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		wrapT);
1830 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1831 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	magFilter);
1832 
1833 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1834 
1835 	// Compute grid.
1836 	vector<tcu::IVec4> gridLayout;
1837 	computeGridLayout(gridLayout, viewport.width, viewport.height);
1838 
1839 	for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
1840 	{
1841 		const int			curX		= gridLayout[cellNdx].x();
1842 		const int			curY		= gridLayout[cellNdx].y();
1843 		const int			curW		= gridLayout[cellNdx].z();
1844 		const int			curH		= gridLayout[cellNdx].w();
1845 		const tcu::CubeFace	cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
1846 		RenderParams		params		(TEXTURETYPE_CUBE);
1847 
1848 		computeQuadTexCoordCube(texCoord, cubeFace);
1849 
1850 		setTextureParams(cellNdx);
1851 
1852 		// Render with GL.
1853 		gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
1854 		m_renderer.renderQuad(0, &texCoord[0], params);
1855 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1856 	}
1857 
1858 	// Read result.
1859 	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
1860 	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
1861 
1862 	// Render reference and compare
1863 	{
1864 		tcu::Surface			referenceFrame		(viewport.width, viewport.height);
1865 		tcu::Surface			errorMask			(viewport.width, viewport.height);
1866 		int						numFailedPixels		= 0;
1867 		ReferenceParams			params				(TEXTURETYPE_CUBE);
1868 		tcu::LookupPrecision	lookupPrec;
1869 		tcu::LodPrecision		lodPrec;
1870 
1871 		// Params for rendering reference
1872 		params.sampler					= glu::mapGLSampler(wrapS, wrapT, m_minFilter, magFilter);
1873 		params.sampler.seamlessCubeMap	= true;
1874 		params.lodMode					= LODMODE_EXACT;
1875 
1876 		// Comparison parameters
1877 		lookupPrec.colorMask			= getCompareMask(m_context.getRenderTarget().getPixelFormat());
1878 		lookupPrec.colorThreshold		= tcu::computeFixedPointThreshold(max(getBitsVec(m_context.getRenderTarget().getPixelFormat())-2, IVec4(0)));
1879 		lookupPrec.coordBits			= tcu::IVec3(10);
1880 		lookupPrec.uvwBits				= tcu::IVec3(5,5,0);
1881 		lodPrec.derivateBits			= 10;
1882 		lodPrec.lodBits					= 6;
1883 
1884 		for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
1885 		{
1886 			const int				curX		= gridLayout[cellNdx].x();
1887 			const int				curY		= gridLayout[cellNdx].y();
1888 			const int				curW		= gridLayout[cellNdx].z();
1889 			const int				curH		= gridLayout[cellNdx].w();
1890 			const tcu::CubeFace		cubeFace	= (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
1891 
1892 			computeQuadTexCoordCube(texCoord, cubeFace);
1893 			getReferenceParams(params, cellNdx);
1894 
1895 			// Render ideal reference.
1896 			{
1897 				tcu::SurfaceAccess idealDst(referenceFrame, m_context.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
1898 				sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
1899 			}
1900 
1901 			// Compare this cell
1902 			numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
1903 														tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
1904 														tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
1905 														m_texture->getRefTexture(), &texCoord[0], params,
1906 														lookupPrec, lodPrec, m_testCtx.getWatchDog());
1907 		}
1908 
1909 		if (numFailedPixels > 0)
1910 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1911 
1912 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
1913 						   << TestLog::Image("Rendered", "Rendered image", renderedFrame);
1914 
1915 		if (numFailedPixels > 0)
1916 		{
1917 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
1918 							   << TestLog::Image("ErrorMask", "Error mask", errorMask);
1919 		}
1920 
1921 		m_testCtx.getLog() << TestLog::EndImageSet;
1922 
1923 		{
1924 			const bool isOk = numFailedPixels == 0;
1925 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1926 									isOk ? "Pass"				: "Image verification failed");
1927 		}
1928 	}
1929 
1930 	return STOP;
1931 }
1932 
1933 class TextureCubeMinLodCase : public TextureCubeLodControlCase
1934 {
1935 public:
TextureCubeMinLodCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1936 	TextureCubeMinLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1937 		: TextureCubeLodControlCase(context, name, desc, minFilter)
1938 	{
1939 	}
1940 
1941 protected:
setTextureParams(int cellNdx)1942 	void setTextureParams (int cellNdx)
1943 	{
1944 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1945 		gl.texParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_LOD, getMinLodForCell(cellNdx));
1946 	}
1947 
getReferenceParams(ReferenceParams & params,int cellNdx)1948 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1949 	{
1950 		params.minLod = getMinLodForCell(cellNdx);
1951 	}
1952 };
1953 
1954 class TextureCubeMaxLodCase : public TextureCubeLodControlCase
1955 {
1956 public:
TextureCubeMaxLodCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1957 	TextureCubeMaxLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1958 		: TextureCubeLodControlCase(context, name, desc, minFilter)
1959 	{
1960 	}
1961 
1962 protected:
setTextureParams(int cellNdx)1963 	void setTextureParams (int cellNdx)
1964 	{
1965 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1966 		gl.texParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LOD, getMaxLodForCell(cellNdx));
1967 	}
1968 
getReferenceParams(ReferenceParams & params,int cellNdx)1969 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1970 	{
1971 		params.maxLod = getMaxLodForCell(cellNdx);
1972 	}
1973 };
1974 
1975 class TextureCubeBaseLevelCase : public TextureCubeLodControlCase
1976 {
1977 public:
TextureCubeBaseLevelCase(Context & context,const char * name,const char * desc,deUint32 minFilter)1978 	TextureCubeBaseLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1979 		: TextureCubeLodControlCase(context, name, desc, minFilter)
1980 	{
1981 	}
1982 
1983 protected:
getBaseLevel(int cellNdx) const1984 	int getBaseLevel (int cellNdx) const
1985 	{
1986 		const int	numLevels	= deLog2Floor32(m_texSize)+1;
1987 		const int	baseLevel	= (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x23fae13) % numLevels;
1988 
1989 		return baseLevel;
1990 	}
1991 
setTextureParams(int cellNdx)1992 	void setTextureParams (int cellNdx)
1993 	{
1994 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1995 		gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, getBaseLevel(cellNdx));
1996 	}
1997 
getReferenceParams(ReferenceParams & params,int cellNdx)1998 	void getReferenceParams (ReferenceParams& params, int cellNdx)
1999 	{
2000 		params.baseLevel = getBaseLevel(cellNdx);
2001 	}
2002 };
2003 
2004 class TextureCubeMaxLevelCase : public TextureCubeLodControlCase
2005 {
2006 public:
TextureCubeMaxLevelCase(Context & context,const char * name,const char * desc,deUint32 minFilter)2007 	TextureCubeMaxLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2008 		: TextureCubeLodControlCase(context, name, desc, minFilter)
2009 	{
2010 	}
2011 
2012 protected:
getMaxLevel(int cellNdx) const2013 	int getMaxLevel (int cellNdx) const
2014 	{
2015 		const int	numLevels	= deLog2Floor32(m_texSize)+1;
2016 		const int	maxLevel	= (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x974e21) % numLevels;
2017 
2018 		return maxLevel;
2019 	}
2020 
setTextureParams(int cellNdx)2021 	void setTextureParams (int cellNdx)
2022 	{
2023 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2024 		gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, getMaxLevel(cellNdx));
2025 	}
2026 
getReferenceParams(ReferenceParams & params,int cellNdx)2027 	void getReferenceParams (ReferenceParams& params, int cellNdx)
2028 	{
2029 		params.maxLevel = getMaxLevel(cellNdx);
2030 	}
2031 };
2032 
2033 // Texture3DLodControlCase + test cases
2034 
2035 class Texture3DLodControlCase : public TestCase
2036 {
2037 public:
2038 
2039 										Texture3DLodControlCase		(Context& context, const char* name, const char* desc, deUint32 minFilter);
2040 										~Texture3DLodControlCase	(void);
2041 
2042 	void								init						(void);
2043 	void								deinit						(void);
2044 	IterateResult						iterate						(void);
2045 
2046 protected:
2047 	virtual void						setTextureParams			(int cellNdx)						= DE_NULL;
2048 	virtual void						getReferenceParams			(ReferenceParams& params, int cellNdx)	= DE_NULL;
2049 
2050 	const int							m_texWidth;
2051 	const int							m_texHeight;
2052 	const int							m_texDepth;
2053 
2054 private:
2055 										Texture3DLodControlCase		(const Texture3DLodControlCase& other);
2056 	Texture3DLodControlCase&			operator=					(const Texture3DLodControlCase& other);
2057 
2058 	deUint32							m_minFilter;
2059 
2060 	glu::Texture3D*						m_texture;
2061 	TextureTestUtil::TextureRenderer	m_renderer;
2062 };
2063 
Texture3DLodControlCase(Context & context,const char * name,const char * desc,deUint32 minFilter)2064 Texture3DLodControlCase::Texture3DLodControlCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2065 	: TestCase			(context, name, desc)
2066 	, m_texWidth		(32)
2067 	, m_texHeight		(32)
2068 	, m_texDepth		(32)
2069 	, m_minFilter		(minFilter)
2070 	, m_texture			(DE_NULL)
2071 	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
2072 {
2073 }
2074 
~Texture3DLodControlCase(void)2075 Texture3DLodControlCase::~Texture3DLodControlCase (void)
2076 {
2077 	Texture3DLodControlCase::deinit();
2078 }
2079 
init(void)2080 void Texture3DLodControlCase::init (void)
2081 {
2082 	const deUint32					format			= GL_RGBA8;
2083 	const tcu::TextureFormat&		texFmt			= glu::mapGLInternalFormat(format);
2084 	tcu::TextureFormatInfo			fmtInfo			= tcu::getTextureFormatInfo(texFmt);
2085 	const tcu::Vec4&				cScale			= fmtInfo.lookupScale;
2086 	const tcu::Vec4&				cBias			= fmtInfo.lookupBias;
2087 	int								numLevels		= deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth))+1;
2088 
2089 	m_texture = new glu::Texture3D(m_context.getRenderContext(), format, m_texWidth, m_texHeight, m_texDepth);
2090 
2091 	// Fill texture with colored grid.
2092 	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
2093 	{
2094 		deUint32	step		= 0xff / (numLevels-1);
2095 		deUint32	inc			= deClamp32(step*levelNdx, 0x00, 0xff);
2096 		deUint32	dec			= 0xff - inc;
2097 		deUint32	rgb			= (inc << 16) | (dec << 8) | 0xff;
2098 		deUint32	color		= 0xff000000 | rgb;
2099 
2100 		m_texture->getRefTexture().allocLevel(levelNdx);
2101 		tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec()*cScale + cBias);
2102 	}
2103 
2104 	m_texture->upload();
2105 }
2106 
deinit(void)2107 void Texture3DLodControlCase::deinit (void)
2108 {
2109 	delete m_texture;
2110 	m_texture = DE_NULL;
2111 
2112 	m_renderer.clear();
2113 }
2114 
iterate(void)2115 Texture3DLodControlCase::IterateResult Texture3DLodControlCase::iterate (void)
2116 {
2117 	const glw::Functions&			gl					= m_context.getRenderContext().getFunctions();
2118 
2119 	const deUint32					wrapS				= GL_CLAMP_TO_EDGE;
2120 	const deUint32					wrapT				= GL_CLAMP_TO_EDGE;
2121 	const deUint32					wrapR				= GL_CLAMP_TO_EDGE;
2122 	const deUint32					magFilter			= GL_NEAREST;
2123 	const tcu::Texture3D&			refTexture			= m_texture->getRefTexture();
2124 	const tcu::TextureFormat&		texFmt				= refTexture.getFormat();
2125 	const tcu::TextureFormatInfo	fmtInfo				= tcu::getTextureFormatInfo(texFmt);
2126 	const int						texWidth			= refTexture.getWidth();
2127 	const int						texHeight			= refTexture.getHeight();
2128 
2129 	const tcu::RenderTarget&		renderTarget		= m_context.getRenderContext().getRenderTarget();
2130 	const RandomViewport			viewport			(renderTarget, texWidth*4, texHeight*4, deStringHash(getName()));
2131 
2132 	// Viewport is divided into 4x4 grid.
2133 	const int						gridWidth			= 4;
2134 	const int						gridHeight			= 4;
2135 	const int						cellWidth			= viewport.width / gridWidth;
2136 	const int						cellHeight			= viewport.height / gridHeight;
2137 
2138 	tcu::Surface					renderedFrame		(viewport.width, viewport.height);
2139 	vector<float>					texCoord;
2140 	ReferenceParams					sampleParams		(TEXTURETYPE_3D);
2141 
2142 	// Sampling parameters.
2143 	sampleParams.sampler		= glu::mapGLSampler(wrapS, wrapT, wrapR, m_minFilter, magFilter);
2144 	sampleParams.samplerType	= getSamplerType(texFmt);
2145 	sampleParams.colorBias		= fmtInfo.lookupBias;
2146 	sampleParams.colorScale		= fmtInfo.lookupScale;
2147 
2148 	// Bind texture and setup sampler parameters.
2149 	gl.bindTexture	(GL_TEXTURE_3D, m_texture->getGLTexture());
2150 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,		wrapS);
2151 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,		wrapT);
2152 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,		wrapR);
2153 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
2154 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,	magFilter);
2155 
2156 	GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
2157 
2158 	// Render cells.
2159 	for (int gridY = 0; gridY < gridHeight; gridY++)
2160 	{
2161 		for (int gridX = 0; gridX < gridWidth; gridX++)
2162 		{
2163 			int		curX		= cellWidth*gridX;
2164 			int		curY		= cellHeight*gridY;
2165 			int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
2166 			int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
2167 			int		cellNdx		= gridY*gridWidth + gridX;
2168 
2169 			// Compute texcoord.
2170 			getBasicTexCoord3D(texCoord, cellNdx);
2171 
2172 			setTextureParams(cellNdx);
2173 
2174 			// Render with GL.
2175 			gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
2176 			m_renderer.renderQuad(0, &texCoord[0], sampleParams);
2177 		}
2178 	}
2179 
2180 	// Read result.
2181 	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
2182 
2183 	// Compare and log
2184 	{
2185 		const tcu::PixelFormat&	pixelFormat		= m_context.getRenderTarget().getPixelFormat();
2186 		const bool				isTrilinear		= m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
2187 		tcu::Surface			referenceFrame	(viewport.width, viewport.height);
2188 		tcu::Surface			errorMask		(viewport.width, viewport.height);
2189 		tcu::LookupPrecision	lookupPrec;
2190 		tcu::LodPrecision		lodPrec;
2191 		int						numFailedPixels	= 0;
2192 
2193 		lookupPrec.coordBits		= tcu::IVec3(20, 20, 20);
2194 		lookupPrec.uvwBits			= tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
2195 		lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
2196 		lookupPrec.colorMask		= getCompareMask(pixelFormat);
2197 		lodPrec.derivateBits		= 10;
2198 		lodPrec.lodBits				= 8;
2199 
2200 		for (int gridY = 0; gridY < gridHeight; gridY++)
2201 		{
2202 			for (int gridX = 0; gridX < gridWidth; gridX++)
2203 			{
2204 				const int		curX		= cellWidth*gridX;
2205 				const int		curY		= cellHeight*gridY;
2206 				const int		curW		= gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
2207 				const int		curH		= gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
2208 				const int		cellNdx		= gridY*gridWidth + gridX;
2209 
2210 				getBasicTexCoord3D(texCoord, cellNdx);
2211 				getReferenceParams(sampleParams, cellNdx);
2212 
2213 				// Render ideal result
2214 				sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
2215 							  refTexture, &texCoord[0], sampleParams);
2216 
2217 				// Compare this cell
2218 				numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
2219 															tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
2220 															tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
2221 															m_texture->getRefTexture(), &texCoord[0], sampleParams,
2222 															lookupPrec, lodPrec, m_testCtx.getWatchDog());
2223 			}
2224 		}
2225 
2226 		if (numFailedPixels > 0)
2227 			m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2228 
2229 		m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
2230 							<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
2231 
2232 		if (numFailedPixels > 0)
2233 		{
2234 			m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
2235 								<< TestLog::Image("ErrorMask", "Error mask", errorMask);
2236 		}
2237 
2238 		m_testCtx.getLog() << TestLog::EndImageSet;
2239 
2240 		{
2241 			const bool isOk = numFailedPixels == 0;
2242 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
2243 									isOk ? "Pass"				: "Image verification failed");
2244 		}
2245 	}
2246 
2247 	return STOP;
2248 }
2249 
2250 class Texture3DMinLodCase : public Texture3DLodControlCase
2251 {
2252 public:
Texture3DMinLodCase(Context & context,const char * name,const char * desc,deUint32 minFilter)2253 	Texture3DMinLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2254 		: Texture3DLodControlCase(context, name, desc, minFilter)
2255 	{
2256 	}
2257 
2258 protected:
setTextureParams(int cellNdx)2259 	void setTextureParams (int cellNdx)
2260 	{
2261 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2262 		gl.texParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_LOD, getMinLodForCell(cellNdx));
2263 	}
2264 
getReferenceParams(ReferenceParams & params,int cellNdx)2265 	void getReferenceParams (ReferenceParams& params, int cellNdx)
2266 	{
2267 		params.minLod = getMinLodForCell(cellNdx);
2268 	}
2269 };
2270 
2271 class Texture3DMaxLodCase : public Texture3DLodControlCase
2272 {
2273 public:
Texture3DMaxLodCase(Context & context,const char * name,const char * desc,deUint32 minFilter)2274 	Texture3DMaxLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2275 		: Texture3DLodControlCase(context, name, desc, minFilter)
2276 	{
2277 	}
2278 
2279 protected:
setTextureParams(int cellNdx)2280 	void setTextureParams (int cellNdx)
2281 	{
2282 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2283 		gl.texParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAX_LOD, getMaxLodForCell(cellNdx));
2284 	}
2285 
getReferenceParams(ReferenceParams & params,int cellNdx)2286 	void getReferenceParams (ReferenceParams& params, int cellNdx)
2287 	{
2288 		params.maxLod = getMaxLodForCell(cellNdx);
2289 	}
2290 };
2291 
2292 class Texture3DBaseLevelCase : public Texture3DLodControlCase
2293 {
2294 public:
Texture3DBaseLevelCase(Context & context,const char * name,const char * desc,deUint32 minFilter)2295 	Texture3DBaseLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2296 		: Texture3DLodControlCase(context, name, desc, minFilter)
2297 	{
2298 	}
2299 
2300 protected:
getBaseLevel(int cellNdx) const2301 	int getBaseLevel (int cellNdx) const
2302 	{
2303 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
2304 		const int	baseLevel	= (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x7347e9) % numLevels;
2305 
2306 		return baseLevel;
2307 	}
2308 
setTextureParams(int cellNdx)2309 	void setTextureParams (int cellNdx)
2310 	{
2311 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2312 		gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, getBaseLevel(cellNdx));
2313 	}
2314 
getReferenceParams(ReferenceParams & params,int cellNdx)2315 	void getReferenceParams (ReferenceParams& params, int cellNdx)
2316 	{
2317 		params.baseLevel = getBaseLevel(cellNdx);
2318 	}
2319 };
2320 
2321 class Texture3DMaxLevelCase : public Texture3DLodControlCase
2322 {
2323 public:
Texture3DMaxLevelCase(Context & context,const char * name,const char * desc,deUint32 minFilter)2324 	Texture3DMaxLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2325 		: Texture3DLodControlCase(context, name, desc, minFilter)
2326 	{
2327 	}
2328 
2329 protected:
getMaxLevel(int cellNdx) const2330 	int getMaxLevel (int cellNdx) const
2331 	{
2332 		const int	numLevels	= deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
2333 		const int	maxLevel	= (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x9111e7) % numLevels;
2334 
2335 		return maxLevel;
2336 	}
2337 
setTextureParams(int cellNdx)2338 	void setTextureParams (int cellNdx)
2339 	{
2340 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2341 		gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, getMaxLevel(cellNdx));
2342 	}
2343 
getReferenceParams(ReferenceParams & params,int cellNdx)2344 	void getReferenceParams (ReferenceParams& params, int cellNdx)
2345 	{
2346 		params.maxLevel = getMaxLevel(cellNdx);
2347 	}
2348 };
2349 
TextureMipmapTests(Context & context)2350 TextureMipmapTests::TextureMipmapTests (Context& context)
2351 	: TestCaseGroup(context, "mipmap", "Mipmapping tests")
2352 {
2353 }
2354 
~TextureMipmapTests(void)2355 TextureMipmapTests::~TextureMipmapTests (void)
2356 {
2357 }
2358 
init(void)2359 void TextureMipmapTests::init (void)
2360 {
2361 	tcu::TestCaseGroup* group2D		= new tcu::TestCaseGroup(m_testCtx, "2d",	"2D Texture Mipmapping");
2362 	tcu::TestCaseGroup*	groupCube	= new tcu::TestCaseGroup(m_testCtx, "cube",	"Cube Map Mipmapping");
2363 	tcu::TestCaseGroup*	group3D		= new tcu::TestCaseGroup(m_testCtx, "3d",	"3D Texture Mipmapping");
2364 	addChild(group2D);
2365 	addChild(groupCube);
2366 	addChild(group3D);
2367 
2368 	static const struct
2369 	{
2370 		const char*		name;
2371 		deUint32		mode;
2372 	} wrapModes[] =
2373 	{
2374 		{ "clamp",		GL_CLAMP_TO_EDGE },
2375 		{ "repeat",		GL_REPEAT },
2376 		{ "mirror",		GL_MIRRORED_REPEAT }
2377 	};
2378 
2379 	static const struct
2380 	{
2381 		const char*		name;
2382 		deUint32		mode;
2383 	} minFilterModes[] =
2384 	{
2385 		{ "nearest_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
2386 		{ "linear_nearest",		GL_LINEAR_MIPMAP_NEAREST	},
2387 		{ "nearest_linear",		GL_NEAREST_MIPMAP_LINEAR	},
2388 		{ "linear_linear",		GL_LINEAR_MIPMAP_LINEAR		}
2389 	};
2390 
2391 	static const struct
2392 	{
2393 		CoordType		type;
2394 		const char*		name;
2395 		const char*		desc;
2396 	} coordTypes[] =
2397 	{
2398 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
2399 		{ COORDTYPE_AFFINE,		"affine",		"Mipmapping with affine coordinate transform"		},
2400 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			}
2401 	};
2402 
2403 	static const struct
2404 	{
2405 		const char*		name;
2406 		deUint32		format;
2407 		deUint32		dataType;
2408 	} formats[] =
2409 	{
2410 		{ "a8",			GL_ALPHA,			GL_UNSIGNED_BYTE },
2411 		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
2412 		{ "la88",		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
2413 		{ "rgb565",		GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
2414 		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
2415 		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
2416 		{ "rgba5551",	GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
2417 		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
2418 	};
2419 
2420 	static const struct
2421 	{
2422 		const char*		name;
2423 		deUint32		hint;
2424 	} genHints[] =
2425 	{
2426 		{ "fastest",	GL_FASTEST },
2427 		{ "nicest",		GL_NICEST }
2428 	};
2429 
2430 	static const struct
2431 	{
2432 		const char*		name;
2433 		int				width;
2434 		int				height;
2435 	} tex2DSizes[] =
2436 	{
2437 		{ DE_NULL,		64, 64 }, // Default.
2438 		{ "npot",		63, 57 },
2439 		{ "non_square",	32, 64 }
2440 	};
2441 
2442 	static const struct
2443 	{
2444 		const char*		name;
2445 		int				width;
2446 		int				height;
2447 		int				depth;
2448 	} tex3DSizes[] =
2449 	{
2450 		{ DE_NULL,		32, 32, 32 }, // Default.
2451 		{ "npot",		33, 29, 27 }
2452 	};
2453 
2454 	const int cubeMapSize = 64;
2455 
2456 	static const struct
2457 	{
2458 		CoordType		type;
2459 		const char*		name;
2460 		const char*		desc;
2461 	} cubeCoordTypes[] =
2462 	{
2463 		{ COORDTYPE_BASIC,		"basic",		"Mipmapping with translated and scaled coordinates" },
2464 		{ COORDTYPE_PROJECTED,	"projected",	"Mipmapping with perspective projection"			},
2465 		{ COORDTYPE_BASIC_BIAS,	"bias",			"User-supplied bias value"							}
2466 	};
2467 
2468 	// 2D cases.
2469 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
2470 	{
2471 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
2472 		group2D->addChild(coordTypeGroup);
2473 
2474 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2475 		{
2476 			for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
2477 			{
2478 				// Add non_square variants to basic cases only.
2479 				int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
2480 
2481 				for (int size = 0; size < sizeEnd; size++)
2482 				{
2483 					std::ostringstream name;
2484 					name << minFilterModes[minFilter].name
2485 						 << "_" << wrapModes[wrapMode].name;
2486 
2487 					if (tex2DSizes[size].name)
2488 						name << "_" << tex2DSizes[size].name;
2489 
2490 					coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
2491 																	 name.str().c_str(), "",
2492 																	 coordTypes[coordType].type,
2493 																	 minFilterModes[minFilter].mode,
2494 																	 wrapModes[wrapMode].mode,
2495 																	 wrapModes[wrapMode].mode,
2496 																	 GL_RGBA, GL_UNSIGNED_BYTE,
2497 																	 tex2DSizes[size].width, tex2DSizes[size].height));
2498 				}
2499 			}
2500 		}
2501 	}
2502 
2503 	// 2D bias variants.
2504 	{
2505 		tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
2506 		group2D->addChild(biasGroup);
2507 
2508 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2509 			biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
2510 														minFilterModes[minFilter].name, "",
2511 														COORDTYPE_BASIC_BIAS,
2512 														minFilterModes[minFilter].mode,
2513 														GL_REPEAT, GL_REPEAT,
2514 														GL_RGBA, GL_UNSIGNED_BYTE,
2515 														tex2DSizes[0].width, tex2DSizes[0].height));
2516 	}
2517 
2518 	// 2D mipmap generation variants.
2519 	{
2520 		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
2521 		group2D->addChild(genMipmapGroup);
2522 
2523 		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
2524 		{
2525 			for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
2526 			{
2527 				for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
2528 				{
2529 					std::ostringstream name;
2530 					name << formats[format].name;
2531 
2532 					if (tex2DSizes[size].name)
2533 						name << "_" << tex2DSizes[size].name;
2534 
2535 					name << "_" << genHints[hint].name;
2536 
2537 					genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
2538 																		formats[format].format, formats[format].dataType, genHints[hint].hint,
2539 																		tex2DSizes[size].width, tex2DSizes[size].height));
2540 				}
2541 			}
2542 		}
2543 	}
2544 
2545 	// 2D LOD controls.
2546 	{
2547 		// MIN_LOD
2548 		tcu::TestCaseGroup* minLodGroup = new tcu::TestCaseGroup(m_testCtx, "min_lod", "Lod control: min lod");
2549 		group2D->addChild(minLodGroup);
2550 
2551 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2552 			minLodGroup->addChild(new Texture2DMinLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2553 
2554 		// MAX_LOD
2555 		tcu::TestCaseGroup* maxLodGroup = new tcu::TestCaseGroup(m_testCtx, "max_lod", "Lod control: max lod");
2556 		group2D->addChild(maxLodGroup);
2557 
2558 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2559 			maxLodGroup->addChild(new Texture2DMaxLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2560 
2561 		// BASE_LEVEL
2562 		tcu::TestCaseGroup* baseLevelGroup = new tcu::TestCaseGroup(m_testCtx, "base_level", "Base level");
2563 		group2D->addChild(baseLevelGroup);
2564 
2565 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2566 			baseLevelGroup->addChild(new Texture2DBaseLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2567 
2568 		// MAX_LEVEL
2569 		tcu::TestCaseGroup* maxLevelGroup = new tcu::TestCaseGroup(m_testCtx, "max_level", "Max level");
2570 		group2D->addChild(maxLevelGroup);
2571 
2572 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2573 			maxLevelGroup->addChild(new Texture2DMaxLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2574 	}
2575 
2576 	// Cubemap cases.
2577 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
2578 	{
2579 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
2580 		groupCube->addChild(coordTypeGroup);
2581 
2582 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2583 		{
2584 			coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
2585 															   minFilterModes[minFilter].name, "",
2586 															   cubeCoordTypes[coordType].type,
2587 															   minFilterModes[minFilter].mode,
2588 															   GL_CLAMP_TO_EDGE,
2589 															   GL_CLAMP_TO_EDGE,
2590 															   GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
2591 		}
2592 	}
2593 
2594 	// Cubemap mipmap generation variants.
2595 	{
2596 		tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
2597 		groupCube->addChild(genMipmapGroup);
2598 
2599 		for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
2600 		{
2601 			for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
2602 			{
2603 				std::ostringstream name;
2604 				name << formats[format].name
2605 					 << "_" << genHints[hint].name;
2606 
2607 				genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
2608 			}
2609 		}
2610 	}
2611 
2612 	// Cubemap LOD controls.
2613 	{
2614 		// MIN_LOD
2615 		tcu::TestCaseGroup* minLodGroup = new tcu::TestCaseGroup(m_testCtx, "min_lod", "Lod control: min lod");
2616 		groupCube->addChild(minLodGroup);
2617 
2618 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2619 			minLodGroup->addChild(new TextureCubeMinLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2620 
2621 		// MAX_LOD
2622 		tcu::TestCaseGroup* maxLodGroup = new tcu::TestCaseGroup(m_testCtx, "max_lod", "Lod control: max lod");
2623 		groupCube->addChild(maxLodGroup);
2624 
2625 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2626 			maxLodGroup->addChild(new TextureCubeMaxLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2627 
2628 		// BASE_LEVEL
2629 		tcu::TestCaseGroup* baseLevelGroup = new tcu::TestCaseGroup(m_testCtx, "base_level", "Base level");
2630 		groupCube->addChild(baseLevelGroup);
2631 
2632 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2633 			baseLevelGroup->addChild(new TextureCubeBaseLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2634 
2635 		// MAX_LEVEL
2636 		tcu::TestCaseGroup* maxLevelGroup = new tcu::TestCaseGroup(m_testCtx, "max_level", "Max level");
2637 		groupCube->addChild(maxLevelGroup);
2638 
2639 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2640 			maxLevelGroup->addChild(new TextureCubeMaxLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2641 	}
2642 
2643 	// 3D cases.
2644 	for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
2645 	{
2646 		tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
2647 		group3D->addChild(coordTypeGroup);
2648 
2649 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2650 		{
2651 			for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
2652 			{
2653 				// Add other size variants to basic cases only.
2654 				int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex3DSizes) : 1;
2655 
2656 				for (int size = 0; size < sizeEnd; size++)
2657 				{
2658 					std::ostringstream name;
2659 					name << minFilterModes[minFilter].name
2660 						 << "_" << wrapModes[wrapMode].name;
2661 
2662 					if (tex3DSizes[size].name)
2663 						name << "_" << tex3DSizes[size].name;
2664 
2665 					coordTypeGroup->addChild(new Texture3DMipmapCase(m_context,
2666 																	 name.str().c_str(), "",
2667 																	 coordTypes[coordType].type,
2668 																	 minFilterModes[minFilter].mode,
2669 																	 wrapModes[wrapMode].mode,
2670 																	 wrapModes[wrapMode].mode,
2671 																	 wrapModes[wrapMode].mode,
2672 																	 GL_RGBA8,
2673 																	 tex3DSizes[size].width, tex3DSizes[size].height, tex3DSizes[size].depth));
2674 				}
2675 			}
2676 		}
2677 	}
2678 
2679 	// 3D bias variants.
2680 	{
2681 		tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
2682 		group3D->addChild(biasGroup);
2683 
2684 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2685 			biasGroup->addChild(new Texture3DMipmapCase(m_context,
2686 														minFilterModes[minFilter].name, "",
2687 														COORDTYPE_BASIC_BIAS,
2688 														minFilterModes[minFilter].mode,
2689 														GL_REPEAT, GL_REPEAT, GL_REPEAT,
2690 														GL_RGBA8,
2691 														tex3DSizes[0].width, tex3DSizes[0].height, tex3DSizes[0].depth));
2692 	}
2693 
2694 	// 3D LOD controls.
2695 	{
2696 		// MIN_LOD
2697 		tcu::TestCaseGroup* minLodGroup = new tcu::TestCaseGroup(m_testCtx, "min_lod", "Lod control: min lod");
2698 		group3D->addChild(minLodGroup);
2699 
2700 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2701 			minLodGroup->addChild(new Texture3DMinLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2702 
2703 		// MAX_LOD
2704 		tcu::TestCaseGroup* maxLodGroup = new tcu::TestCaseGroup(m_testCtx, "max_lod", "Lod control: max lod");
2705 		group3D->addChild(maxLodGroup);
2706 
2707 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2708 			maxLodGroup->addChild(new Texture3DMaxLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2709 
2710 		// BASE_LEVEL
2711 		tcu::TestCaseGroup* baseLevelGroup = new tcu::TestCaseGroup(m_testCtx, "base_level", "Base level");
2712 		group3D->addChild(baseLevelGroup);
2713 
2714 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2715 			baseLevelGroup->addChild(new Texture3DBaseLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2716 
2717 		// MAX_LEVEL
2718 		tcu::TestCaseGroup* maxLevelGroup = new tcu::TestCaseGroup(m_testCtx, "max_level", "Max level");
2719 		group3D->addChild(maxLevelGroup);
2720 
2721 		for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2722 			maxLevelGroup->addChild(new Texture3DMaxLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2723 	}
2724 }
2725 
2726 } // Functional
2727 } // gles3
2728 } // deqp
2729