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