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