Home | History | Annotate | Download | only in accuracy
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Texture filtering accuracy tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2aTextureFilteringTests.hpp"
     25 #include "glsTextureTestUtil.hpp"
     26 #include "gluTexture.hpp"
     27 #include "gluStrUtil.hpp"
     28 #include "gluTextureUtil.hpp"
     29 #include "gluPixelTransfer.hpp"
     30 #include "tcuTestLog.hpp"
     31 #include "tcuTextureUtil.hpp"
     32 #include "deStringUtil.hpp"
     33 
     34 #include "glwFunctions.hpp"
     35 #include "glwEnums.hpp"
     36 
     37 using std::string;
     38 
     39 namespace deqp
     40 {
     41 namespace gles2
     42 {
     43 namespace Accuracy
     44 {
     45 
     46 using tcu::TestLog;
     47 using std::vector;
     48 using std::string;
     49 using tcu::Sampler;
     50 using namespace glu;
     51 using namespace gls::TextureTestUtil;
     52 
     53 class Texture2DFilteringCase : public tcu::TestCase
     54 {
     55 public:
     56 								Texture2DFilteringCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, deUint32 dataType, int width, int height);
     57 								Texture2DFilteringCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames);
     58 								~Texture2DFilteringCase		(void);
     59 
     60 	void						init						(void);
     61 	void						deinit						(void);
     62 	IterateResult				iterate						(void);
     63 
     64 private:
     65 								Texture2DFilteringCase		(const Texture2DFilteringCase& other);
     66 	Texture2DFilteringCase&		operator=					(const Texture2DFilteringCase& other);
     67 
     68 	glu::RenderContext&			m_renderCtx;
     69 	const glu::ContextInfo&		m_renderCtxInfo;
     70 
     71 	deUint32					m_minFilter;
     72 	deUint32					m_magFilter;
     73 	deUint32					m_wrapS;
     74 	deUint32					m_wrapT;
     75 
     76 	deUint32					m_format;
     77 	deUint32					m_dataType;
     78 	int							m_width;
     79 	int							m_height;
     80 
     81 	std::vector<std::string>	m_filenames;
     82 
     83 	std::vector<glu::Texture2D*>	m_textures;
     84 	TextureRenderer					m_renderer;
     85 };
     86 
     87 
     88 Texture2DFilteringCase::Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, deUint32 dataType, int width, int height)
     89 	: TestCase			(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
     90 	, m_renderCtx		(renderCtx)
     91 	, m_renderCtxInfo	(ctxInfo)
     92 	, m_minFilter		(minFilter)
     93 	, m_magFilter		(magFilter)
     94 	, m_wrapS			(wrapS)
     95 	, m_wrapT			(wrapT)
     96 	, m_format			(format)
     97 	, m_dataType		(dataType)
     98 	, m_width			(width)
     99 	, m_height			(height)
    100 	, m_renderer		(renderCtx, testCtx, glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
    101 {
    102 }
    103 
    104 Texture2DFilteringCase::Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames)
    105 	: TestCase			(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
    106 	, m_renderCtx		(renderCtx)
    107 	, m_renderCtxInfo	(ctxInfo)
    108 	, m_minFilter		(minFilter)
    109 	, m_magFilter		(magFilter)
    110 	, m_wrapS			(wrapS)
    111 	, m_wrapT			(wrapT)
    112 	, m_format			(GL_NONE)
    113 	, m_dataType		(GL_NONE)
    114 	, m_width			(0)
    115 	, m_height			(0)
    116 	, m_filenames		(filenames)
    117 	, m_renderer		(renderCtx, testCtx, glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
    118 {
    119 }
    120 
    121 Texture2DFilteringCase::~Texture2DFilteringCase (void)
    122 {
    123 	deinit();
    124 }
    125 
    126 void Texture2DFilteringCase::init (void)
    127 {
    128 	try
    129 	{
    130 		if (!m_filenames.empty())
    131 		{
    132 			m_textures.reserve(1);
    133 			m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size(), m_filenames));
    134 		}
    135 		else
    136 		{
    137 			// Create 2 textures.
    138 			m_textures.reserve(2);
    139 			for (int ndx = 0; ndx < 2; ndx++)
    140 				m_textures.push_back(new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height));
    141 
    142 			const bool				mipmaps		= deIsPowerOfTwo32(m_width) && deIsPowerOfTwo32(m_height);
    143 			const int				numLevels	= mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1;
    144 			tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
    145 			tcu::Vec4				cBias		= fmtInfo.valueMin;
    146 			tcu::Vec4				cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
    147 
    148 			// Fill first gradient texture.
    149 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    150 			{
    151 				tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
    152 				tcu::Vec4 gMax = tcu::Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
    153 
    154 				m_textures[0]->getRefTexture().allocLevel(levelNdx);
    155 				tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
    156 			}
    157 
    158 			// Fill second with grid texture.
    159 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    160 			{
    161 				deUint32	step	= 0x00ffffff / numLevels;
    162 				deUint32	rgb		= step*levelNdx;
    163 				deUint32	colorA	= 0xff000000 | rgb;
    164 				deUint32	colorB	= 0xff000000 | ~rgb;
    165 
    166 				m_textures[1]->getRefTexture().allocLevel(levelNdx);
    167 				tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
    168 			}
    169 
    170 			// Upload.
    171 			for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
    172 				(*i)->upload();
    173 		}
    174 	}
    175 	catch (...)
    176 	{
    177 		// Clean up to save memory.
    178 		Texture2DFilteringCase::deinit();
    179 		throw;
    180 	}
    181 }
    182 
    183 void Texture2DFilteringCase::deinit (void)
    184 {
    185 	for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
    186 		delete *i;
    187 	m_textures.clear();
    188 
    189 	m_renderer.clear();
    190 }
    191 
    192 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void)
    193 {
    194 	const glw::Functions&		gl					= m_renderCtx.getFunctions();
    195 	TestLog&					log					= m_testCtx.getLog();
    196 	const int					defViewportWidth	= 256;
    197 	const int					defViewportHeight	= 256;
    198 	RandomViewport				viewport			(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
    199 	tcu::Surface				renderedFrame		(viewport.width, viewport.height);
    200 	tcu::Surface				referenceFrame		(viewport.width, viewport.height);
    201 	const tcu::TextureFormat&	texFmt				= m_textures[0]->getRefTexture().getFormat();
    202 	tcu::TextureFormatInfo		fmtInfo				= tcu::getTextureFormatInfo(texFmt);
    203 	ReferenceParams				refParams			(TEXTURETYPE_2D);
    204 	vector<float>				texCoord;
    205 
    206 	// Accuracy measurements are off unless viewport size is 256x256
    207 	if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
    208 		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
    209 
    210 	// Viewport is divided into 4 sections.
    211 	int				leftWidth			= viewport.width / 2;
    212 	int				rightWidth			= viewport.width - leftWidth;
    213 	int				bottomHeight		= viewport.height / 2;
    214 	int				topHeight			= viewport.height - bottomHeight;
    215 
    216 	int				curTexNdx			= 0;
    217 
    218 	// Use unit 0.
    219 	gl.activeTexture(GL_TEXTURE0);
    220 
    221 	// Bind gradient texture and setup sampler parameters.
    222 	gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
    223 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
    224 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
    225 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
    226 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
    227 
    228 	// Setup params for reference.
    229 	refParams.sampler		= mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
    230 	refParams.samplerType	= getSamplerType(texFmt);
    231 	refParams.lodMode		= LODMODE_EXACT;
    232 	refParams.colorBias		= fmtInfo.lookupBias;
    233 	refParams.colorScale	= fmtInfo.lookupScale;
    234 
    235 	// Bottom left: Minification
    236 	{
    237 		gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight);
    238 
    239 		computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f));
    240 
    241 		m_renderer.renderQuad(0, &texCoord[0], refParams);
    242 		sampleTexture(SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight),
    243 					  m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
    244 	}
    245 
    246 	// Bottom right: Magnification
    247 	{
    248 		gl.viewport(viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight);
    249 
    250 		computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
    251 
    252 		m_renderer.renderQuad(0, &texCoord[0], refParams);
    253 		sampleTexture(SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight),
    254 					  m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
    255 	}
    256 
    257 	if (m_textures.size() >= 2)
    258 	{
    259 		curTexNdx += 1;
    260 
    261 		// Setup second texture.
    262 		gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
    263 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
    264 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
    265 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
    266 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
    267 	}
    268 
    269 	// Top left: Minification
    270 	// \note Minification is chosen so that 0.0 < lod <= 0.5. This way special minification threshold rule will be triggered.
    271 	{
    272 		gl.viewport(viewport.x, viewport.y+bottomHeight, leftWidth, topHeight);
    273 
    274 		float	sMin		= -0.5f;
    275 		float	tMin		= -0.2f;
    276 		float	sRange		= ((float)leftWidth * 1.2f) / (float)m_textures[curTexNdx]->getRefTexture().getWidth();
    277 		float	tRange		= ((float)topHeight * 1.1f) / (float)m_textures[curTexNdx]->getRefTexture().getHeight();
    278 
    279 		computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin+sRange, tMin+tRange));
    280 
    281 		m_renderer.renderQuad(0, &texCoord[0], refParams);
    282 		sampleTexture(SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight),
    283 					  m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
    284 	}
    285 
    286 	// Top right: Magnification
    287 	{
    288 		gl.viewport(viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight);
    289 
    290 		computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
    291 
    292 		m_renderer.renderQuad(0, &texCoord[0], refParams);
    293 		sampleTexture(SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight),
    294 					  m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
    295 	}
    296 
    297 	// Read result.
    298 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
    299 
    300 	// Compare and log.
    301 	{
    302 		DE_ASSERT(getNodeType() == tcu::NODETYPE_ACCURACY);
    303 
    304 		const int	bestScoreDiff	= 16;
    305 		const int	worstScoreDiff	= 3200;
    306 
    307 		int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
    308 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
    309 	}
    310 
    311 	return STOP;
    312 }
    313 
    314 class TextureCubeFilteringCase : public tcu::TestCase
    315 {
    316 public:
    317 								TextureCubeFilteringCase	(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, deUint32 dataType, int width, int height);
    318 								TextureCubeFilteringCase	(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames);
    319 								~TextureCubeFilteringCase	(void);
    320 
    321 	void						init						(void);
    322 	void						deinit						(void);
    323 	IterateResult				iterate						(void);
    324 
    325 private:
    326 								TextureCubeFilteringCase	(const TextureCubeFilteringCase& other);
    327 	TextureCubeFilteringCase&	operator=					(const TextureCubeFilteringCase& other);
    328 
    329 	glu::RenderContext&			m_renderCtx;
    330 	const glu::ContextInfo&		m_renderCtxInfo;
    331 
    332 	deUint32					m_minFilter;
    333 	deUint32					m_magFilter;
    334 	deUint32					m_wrapS;
    335 	deUint32					m_wrapT;
    336 
    337 	deUint32					m_format;
    338 	deUint32					m_dataType;
    339 	int							m_width;
    340 	int							m_height;
    341 
    342 	std::vector<std::string>	m_filenames;
    343 
    344 	std::vector<glu::TextureCube*>	m_textures;
    345 	TextureRenderer					m_renderer;
    346 };
    347 
    348 
    349 TextureCubeFilteringCase::TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, deUint32 dataType, int width, int height)
    350 	: TestCase					(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
    351 	, m_renderCtx				(renderCtx)
    352 	, m_renderCtxInfo			(ctxInfo)
    353 	, m_minFilter				(minFilter)
    354 	, m_magFilter				(magFilter)
    355 	, m_wrapS					(wrapS)
    356 	, m_wrapT					(wrapT)
    357 	, m_format					(format)
    358 	, m_dataType				(dataType)
    359 	, m_width					(width)
    360 	, m_height					(height)
    361 	, m_renderer				(renderCtx, testCtx, glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
    362 {
    363 }
    364 
    365 TextureCubeFilteringCase::TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames)
    366 	: TestCase					(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
    367 	, m_renderCtx				(renderCtx)
    368 	, m_renderCtxInfo			(ctxInfo)
    369 	, m_minFilter				(minFilter)
    370 	, m_magFilter				(magFilter)
    371 	, m_wrapS					(wrapS)
    372 	, m_wrapT					(wrapT)
    373 	, m_format					(GL_NONE)
    374 	, m_dataType				(GL_NONE)
    375 	, m_width					(0)
    376 	, m_height					(0)
    377 	, m_filenames				(filenames)
    378 	, m_renderer				(renderCtx, testCtx, glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
    379 {
    380 }
    381 
    382 TextureCubeFilteringCase::~TextureCubeFilteringCase (void)
    383 {
    384 	deinit();
    385 }
    386 
    387 void TextureCubeFilteringCase::init (void)
    388 {
    389 	try
    390 	{
    391 		if (!m_filenames.empty())
    392 		{
    393 			m_textures.reserve(1);
    394 			m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size() / 6, m_filenames));
    395 		}
    396 		else
    397 		{
    398 			m_textures.reserve(2);
    399 			DE_ASSERT(m_width == m_height);
    400 			for (int ndx = 0; ndx < 2; ndx++)
    401 				m_textures.push_back(new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_width));
    402 
    403 			const bool				mipmaps		= deIsPowerOfTwo32(m_width) && deIsPowerOfTwo32(m_height);
    404 			const int				numLevels	= mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1;
    405 			tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
    406 			tcu::Vec4				cBias		= fmtInfo.valueMin;
    407 			tcu::Vec4				cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
    408 
    409 			// Fill first with gradient texture.
    410 			static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
    411 			{
    412 				{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
    413 				{ tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
    414 				{ tcu::Vec4(-1.0f,  0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
    415 				{ tcu::Vec4(-1.0f, -1.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
    416 				{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
    417 				{ tcu::Vec4( 0.0f,  0.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
    418 			};
    419 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
    420 			{
    421 				for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    422 				{
    423 					m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
    424 					tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
    425 				}
    426 			}
    427 
    428 			// Fill second with grid texture.
    429 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
    430 			{
    431 				for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    432 				{
    433 					deUint32	step	= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
    434 					deUint32	rgb		= step*levelNdx*face;
    435 					deUint32	colorA	= 0xff000000 | rgb;
    436 					deUint32	colorB	= 0xff000000 | ~rgb;
    437 
    438 					m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
    439 					tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
    440 				}
    441 			}
    442 
    443 			// Upload.
    444 			for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
    445 				(*i)->upload();
    446 		}
    447 	}
    448 	catch (const std::exception&)
    449 	{
    450 		// Clean up to save memory.
    451 		TextureCubeFilteringCase::deinit();
    452 		throw;
    453 	}
    454 }
    455 
    456 void TextureCubeFilteringCase::deinit (void)
    457 {
    458 	for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
    459 		delete *i;
    460 	m_textures.clear();
    461 
    462 	m_renderer.clear();
    463 }
    464 
    465 static void renderFaces (
    466 	const glw::Functions&		gl,
    467 	const SurfaceAccess&		dstRef,
    468 	const tcu::TextureCube&		refTexture,
    469 	const ReferenceParams&		params,
    470 	TextureRenderer&			renderer,
    471 	int							x,
    472 	int							y,
    473 	int							width,
    474 	int							height,
    475 	const tcu::Vec2&			bottomLeft,
    476 	const tcu::Vec2&			topRight,
    477 	const tcu::Vec2&			texCoordTopRightFactor)
    478 {
    479 	DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight());
    480 
    481 	vector<float> texCoord;
    482 
    483 	DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6);
    484 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
    485 	{
    486 		bool	isRightmost		= (face == 2) || (face == 5);
    487 		bool	isTop			= face >= 3;
    488 		int		curX			= (face % 3) * (width  / 3);
    489 		int		curY			= (face / 3) * (height / 2);
    490 		int		curW			= isRightmost	? (width-curX)	: (width	/ 3);
    491 		int		curH			= isTop			? (height-curY)	: (height	/ 2);
    492 
    493 		computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight);
    494 
    495 		{
    496 			// Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible.
    497 			int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0;
    498 			int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1;
    499 			texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x();
    500 			texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x();
    501 			texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y();
    502 			texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y();
    503 		}
    504 
    505 		gl.viewport(x+curX, y+curY, curW, curH);
    506 
    507 		renderer.renderQuad(0, &texCoord[0], params);
    508 
    509 		sampleTexture(SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params);
    510 	}
    511 
    512 	GLU_EXPECT_NO_ERROR(gl.getError(), "Post render");
    513 }
    514 
    515 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void)
    516 {
    517 	const glw::Functions&		gl					= m_renderCtx.getFunctions();
    518 	TestLog&					log					= m_testCtx.getLog();
    519 	const int					cellSize			= 28;
    520 	const int					defViewportWidth	= cellSize*6;
    521 	const int					defViewportHeight	= cellSize*4;
    522 	RandomViewport				viewport			(m_renderCtx.getRenderTarget(), cellSize*6, cellSize*4, deStringHash(getName()));
    523 	tcu::Surface				renderedFrame		(viewport.width, viewport.height);
    524 	tcu::Surface				referenceFrame		(viewport.width, viewport.height);
    525 	ReferenceParams				sampleParams		(TEXTURETYPE_CUBE);
    526 	const tcu::TextureFormat&	texFmt				= m_textures[0]->getRefTexture().getFormat();
    527 	tcu::TextureFormatInfo		fmtInfo				= tcu::getTextureFormatInfo(texFmt);
    528 
    529 	// Accuracy measurements are off unless viewport size is exactly as expected.
    530 	if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
    531 		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
    532 
    533 	// Viewport is divided into 4 sections.
    534 	int				leftWidth			= viewport.width / 2;
    535 	int				rightWidth			= viewport.width - leftWidth;
    536 	int				bottomHeight		= viewport.height / 2;
    537 	int				topHeight			= viewport.height - bottomHeight;
    538 
    539 	int				curTexNdx			= 0;
    540 
    541 	// Sampling parameters.
    542 	sampleParams.sampler					= mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
    543 	sampleParams.sampler.seamlessCubeMap	= false;
    544 	sampleParams.samplerType				= getSamplerType(texFmt);
    545 	sampleParams.colorBias					= fmtInfo.lookupBias;
    546 	sampleParams.colorScale					= fmtInfo.lookupScale;
    547 	sampleParams.lodMode					= LODMODE_EXACT;
    548 
    549 	// Use unit 0.
    550 	gl.activeTexture(GL_TEXTURE0);
    551 
    552 	// Setup gradient texture.
    553 	gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
    554 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
    555 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
    556 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
    557 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
    558 
    559 	// Bottom left: Minification
    560 	renderFaces(gl,
    561 				SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight),
    562 				m_textures[curTexNdx]->getRefTexture(), sampleParams,
    563 				m_renderer,
    564 				viewport.x, viewport.y, leftWidth, bottomHeight,
    565 				tcu::Vec2(-0.81f, -0.81f),
    566 				tcu::Vec2( 0.8f,  0.8f),
    567 				tcu::Vec2(1.0f, 1.0f));
    568 
    569 	// Bottom right: Magnification
    570 	renderFaces(gl,
    571 				SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight),
    572 				m_textures[curTexNdx]->getRefTexture(), sampleParams,
    573 				m_renderer,
    574 				viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight,
    575 				tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f),
    576 				tcu::Vec2(1.0f, 1.0f));
    577 
    578 	if (m_textures.size() >= 2)
    579 	{
    580 		curTexNdx += 1;
    581 
    582 		// Setup second texture.
    583 		gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
    584 		gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
    585 		gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
    586 		gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
    587 		gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
    588 	}
    589 
    590 	// Top left: Minification
    591 	renderFaces(gl,
    592 				SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight),
    593 				m_textures[curTexNdx]->getRefTexture(), sampleParams,
    594 				m_renderer,
    595 				viewport.x, viewport.y+bottomHeight, leftWidth, topHeight,
    596 				tcu::Vec2(-0.81f, -0.81f),
    597 				tcu::Vec2( 0.8f,  0.8f),
    598 				tcu::Vec2(1.0f, 1.0f));
    599 
    600 	// Top right: Magnification
    601 	renderFaces(gl,
    602 				SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight),
    603 				m_textures[curTexNdx]->getRefTexture(), sampleParams,
    604 				m_renderer,
    605 				viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight,
    606 				tcu::Vec2(0.5f, -0.65f), tcu::Vec2(0.8f, -0.8f),
    607 				tcu::Vec2(1.0f, 1.0f));
    608 
    609 	// Read result.
    610 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
    611 
    612 	// Compare and log.
    613 	{
    614 		DE_ASSERT(getNodeType() == tcu::NODETYPE_ACCURACY);
    615 
    616 		const int	bestScoreDiff	= 16;
    617 		const int	worstScoreDiff	= 10000;
    618 
    619 		int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
    620 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
    621 	}
    622 
    623 	return STOP;
    624 }
    625 
    626 TextureFilteringTests::TextureFilteringTests (Context& context)
    627 	: TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
    628 {
    629 }
    630 
    631 TextureFilteringTests::~TextureFilteringTests (void)
    632 {
    633 }
    634 
    635 void TextureFilteringTests::init (void)
    636 {
    637 	tcu::TestCaseGroup* group2D		= new tcu::TestCaseGroup(m_testCtx, "2d",	"2D Texture Filtering");
    638 	tcu::TestCaseGroup*	groupCube	= new tcu::TestCaseGroup(m_testCtx, "cube",	"Cube Map Filtering");
    639 	addChild(group2D);
    640 	addChild(groupCube);
    641 
    642 	static const struct
    643 	{
    644 		const char*		name;
    645 		deUint32		mode;
    646 	} wrapModes[] =
    647 	{
    648 		{ "clamp",		GL_CLAMP_TO_EDGE },
    649 		{ "repeat",		GL_REPEAT },
    650 		{ "mirror",		GL_MIRRORED_REPEAT }
    651 	};
    652 
    653 	static const struct
    654 	{
    655 		const char*		name;
    656 		deUint32		mode;
    657 	} minFilterModes[] =
    658 	{
    659 		{ "nearest",				GL_NEAREST					},
    660 		{ "linear",					GL_LINEAR					},
    661 		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
    662 		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST	},
    663 		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR	},
    664 		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR		}
    665 	};
    666 
    667 	static const struct
    668 	{
    669 		const char*		name;
    670 		deUint32		mode;
    671 	} magFilterModes[] =
    672 	{
    673 		{ "nearest",	GL_NEAREST },
    674 		{ "linear",		GL_LINEAR }
    675 	};
    676 
    677 	static const struct
    678 	{
    679 		const char*		name;
    680 		int				width;
    681 		int				height;
    682 	} sizes2D[] =
    683 	{
    684 		{ "pot",		32, 64 },
    685 		{ "npot",		31, 55 }
    686 	};
    687 
    688 	static const struct
    689 	{
    690 		const char*		name;
    691 		int				width;
    692 		int				height;
    693 	} sizesCube[] =
    694 	{
    695 		{ "pot",		64, 64 },
    696 		{ "npot",		63, 63 }
    697 	};
    698 
    699 	static const struct
    700 	{
    701 		const char*		name;
    702 		deUint32		format;
    703 		deUint32		dataType;
    704 	} formats[] =
    705 	{
    706 		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE			},
    707 		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4	}
    708 	};
    709 
    710 #define FOR_EACH(ITERATOR, ARRAY, BODY)	\
    711 	for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++)	\
    712 		BODY
    713 
    714 	// 2D cases.
    715 	FOR_EACH(minFilter,		minFilterModes,
    716 	FOR_EACH(magFilter,		magFilterModes,
    717 	FOR_EACH(wrapMode,		wrapModes,
    718 	FOR_EACH(format,		formats,
    719 	FOR_EACH(size,			sizes2D,
    720 		{
    721 			bool isMipmap		= minFilterModes[minFilter].mode != GL_NEAREST && minFilterModes[minFilter].mode != GL_LINEAR;
    722 			bool isClamp		= wrapModes[wrapMode].mode == GL_CLAMP_TO_EDGE;
    723 			bool isRepeat		= wrapModes[wrapMode].mode == GL_REPEAT;
    724 			bool isMagNearest	= magFilterModes[magFilter].mode == GL_NEAREST;
    725 			bool isPotSize		= deIsPowerOfTwo32(sizes2D[size].width) && deIsPowerOfTwo32(sizes2D[size].height);
    726 
    727 			if ((isMipmap || !isClamp) && !isPotSize)
    728 				continue; // Not supported.
    729 
    730 			if ((format != 0) && !(!isMipmap || (isRepeat && isMagNearest)))
    731 				continue; // Skip.
    732 
    733 			string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name;
    734 
    735 			if (!isMipmap)
    736 				name += string("_") + sizes2D[size].name;
    737 
    738 			group2D->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
    739 														 name.c_str(), "",
    740 														 minFilterModes[minFilter].mode,
    741 														 magFilterModes[magFilter].mode,
    742 														 wrapModes[wrapMode].mode,
    743 														 wrapModes[wrapMode].mode,
    744 														 formats[format].format, formats[format].dataType,
    745 														 sizes2D[size].width, sizes2D[size].height));
    746 		})))));
    747 
    748 	// Cubemap cases.
    749 	FOR_EACH(minFilter,		minFilterModes,
    750 	FOR_EACH(magFilter,		magFilterModes,
    751 	FOR_EACH(wrapMode,		wrapModes,
    752 	FOR_EACH(format,		formats,
    753 	FOR_EACH(size,			sizesCube,
    754 		{
    755 			bool isMipmap		= minFilterModes[minFilter].mode != GL_NEAREST && minFilterModes[minFilter].mode != GL_LINEAR;
    756 			bool isClamp		= wrapModes[wrapMode].mode == GL_CLAMP_TO_EDGE;
    757 			bool isRepeat		= wrapModes[wrapMode].mode == GL_REPEAT;
    758 			bool isMagNearest	= magFilterModes[magFilter].mode == GL_NEAREST;
    759 			bool isPotSize		= deIsPowerOfTwo32(sizesCube[size].width) && deIsPowerOfTwo32(sizesCube[size].height);
    760 
    761 			if ((isMipmap || !isClamp) && !isPotSize)
    762 				continue; // Not supported.
    763 
    764 			if (format != 0 && !(!isMipmap || (isRepeat && isMagNearest)))
    765 				continue; // Skip.
    766 
    767 			string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name;
    768 
    769 			if (!isMipmap)
    770 				name += string("_") + sizesCube[size].name;
    771 
    772 			groupCube->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
    773 															 name.c_str(), "",
    774 															 minFilterModes[minFilter].mode,
    775 															 magFilterModes[magFilter].mode,
    776 															 wrapModes[wrapMode].mode,
    777 															 wrapModes[wrapMode].mode,
    778 															 formats[format].format, formats[format].dataType,
    779 															 sizesCube[size].width, sizesCube[size].height));
    780 		})))));
    781 }
    782 
    783 } // Accuracy
    784 } // gles2
    785 } // deqp
    786