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