Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 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 tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fTextureFilteringTests.hpp"
     25 
     26 #include "glsTextureTestUtil.hpp"
     27 
     28 #include "gluPixelTransfer.hpp"
     29 #include "gluTexture.hpp"
     30 #include "gluTextureUtil.hpp"
     31 
     32 #include "tcuCommandLine.hpp"
     33 #include "tcuTextureUtil.hpp"
     34 #include "tcuImageCompare.hpp"
     35 #include "tcuTexLookupVerifier.hpp"
     36 #include "tcuVectorUtil.hpp"
     37 
     38 #include "deStringUtil.hpp"
     39 #include "deString.h"
     40 
     41 #include "glwFunctions.hpp"
     42 #include "glwEnums.hpp"
     43 
     44 namespace deqp
     45 {
     46 namespace gles31
     47 {
     48 namespace Functional
     49 {
     50 
     51 using std::vector;
     52 using std::string;
     53 using tcu::TestLog;
     54 using namespace gls::TextureTestUtil;
     55 
     56 static const char* getFaceDesc (const tcu::CubeFace face)
     57 {
     58 	switch (face)
     59 	{
     60 		case tcu::CUBEFACE_NEGATIVE_X:	return "-X";
     61 		case tcu::CUBEFACE_POSITIVE_X:	return "+X";
     62 		case tcu::CUBEFACE_NEGATIVE_Y:	return "-Y";
     63 		case tcu::CUBEFACE_POSITIVE_Y:	return "+Y";
     64 		case tcu::CUBEFACE_NEGATIVE_Z:	return "-Z";
     65 		case tcu::CUBEFACE_POSITIVE_Z:	return "+Z";
     66 		default:
     67 			DE_ASSERT(false);
     68 			return DE_NULL;
     69 	}
     70 }
     71 
     72 static void logCubeArrayTexCoords(TestLog& log, vector<float>& texCoord)
     73 {
     74 	const size_t numVerts = texCoord.size() / 4;
     75 
     76 	DE_ASSERT(texCoord.size() % 4 == 0);
     77 
     78 	for (size_t vertNdx = 0; vertNdx < numVerts; vertNdx++)
     79 	{
     80 		const size_t	coordNdx	= vertNdx * 4;
     81 
     82 		const float		u			= texCoord[coordNdx + 0];
     83 		const float		v			= texCoord[coordNdx + 1];
     84 		const float		w			= texCoord[coordNdx + 2];
     85 		const float		q			= texCoord[coordNdx + 3];
     86 
     87 		log << TestLog::Message
     88 			<< vertNdx << ": ("
     89 			<< u << ", "
     90 			<< v << ", "
     91 			<< w << ", "
     92 			<< q << ")"
     93 			<< TestLog::EndMessage;
     94 	}
     95 }
     96 
     97 // Cube map array filtering
     98 
     99 class TextureCubeArrayFilteringCase : public TestCase
    100 {
    101 public:
    102 									TextureCubeArrayFilteringCase	(Context& context,
    103 																	 const char* name,
    104 																	 const char* desc,
    105 																	 deUint32 minFilter,
    106 																	 deUint32 magFilter,
    107 																	 deUint32 wrapS,
    108 																	 deUint32 wrapT,
    109 																	 deUint32 internalFormat,
    110 																	 int size,
    111 																	 int depth,
    112 																	 bool onlySampleFaceInterior = false);
    113 
    114 									~TextureCubeArrayFilteringCase	(void);
    115 
    116 	void							init							(void);
    117 	void							deinit							(void);
    118 	IterateResult					iterate							(void);
    119 
    120 private:
    121 									TextureCubeArrayFilteringCase	(const TextureCubeArrayFilteringCase&);
    122 	TextureCubeArrayFilteringCase&	operator=						(const TextureCubeArrayFilteringCase&);
    123 
    124 	const deUint32					m_minFilter;
    125 	const deUint32					m_magFilter;
    126 	const deUint32					m_wrapS;
    127 	const deUint32					m_wrapT;
    128 
    129 	const deUint32					m_internalFormat;
    130 	const int						m_size;
    131 	const int						m_depth;
    132 
    133 	const bool						m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
    134 
    135 	struct FilterCase
    136 	{
    137 		const glu::TextureCubeArray*	texture;
    138 		tcu::Vec2						bottomLeft;
    139 		tcu::Vec2						topRight;
    140 		tcu::Vec2						layerRange;
    141 
    142 		FilterCase (void)
    143 			: texture(DE_NULL)
    144 		{
    145 		}
    146 
    147 		FilterCase (const glu::TextureCubeArray* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_, const tcu::Vec2& layerRange_)
    148 			: texture		(tex_)
    149 			, bottomLeft	(bottomLeft_)
    150 			, topRight		(topRight_)
    151 			, layerRange	(layerRange_)
    152 		{
    153 		}
    154 	};
    155 
    156 	glu::TextureCubeArray*	m_gradientTex;
    157 	glu::TextureCubeArray*	m_gridTex;
    158 
    159 	TextureRenderer			m_renderer;
    160 
    161 	std::vector<FilterCase>	m_cases;
    162 	int						m_caseNdx;
    163 };
    164 
    165 TextureCubeArrayFilteringCase::TextureCubeArrayFilteringCase (Context& context,
    166 															  const char* name,
    167 															  const char* desc,
    168 															  deUint32 minFilter,
    169 															  deUint32 magFilter,
    170 															  deUint32 wrapS,
    171 															  deUint32 wrapT,
    172 															  deUint32 internalFormat,
    173 															  int size,
    174 															  int depth,
    175 															  bool onlySampleFaceInterior)
    176 	: TestCase					(context, name, desc)
    177 	, m_minFilter				(minFilter)
    178 	, m_magFilter				(magFilter)
    179 	, m_wrapS					(wrapS)
    180 	, m_wrapT					(wrapT)
    181 	, m_internalFormat			(internalFormat)
    182 	, m_size					(size)
    183 	, m_depth					(depth)
    184 	, m_onlySampleFaceInterior	(onlySampleFaceInterior)
    185 	, m_gradientTex				(DE_NULL)
    186 	, m_gridTex					(DE_NULL)
    187 	, m_renderer				(m_context.getRenderContext(), context.getTestContext(), glu::GLSL_VERSION_310_ES, glu::PRECISION_HIGHP)
    188 	, m_caseNdx					(0)
    189 {
    190 }
    191 
    192 TextureCubeArrayFilteringCase::~TextureCubeArrayFilteringCase (void)
    193 {
    194 	TextureCubeArrayFilteringCase::deinit();
    195 }
    196 
    197 void TextureCubeArrayFilteringCase::init (void)
    198 {
    199 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
    200 		throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
    201 
    202 	try
    203 	{
    204 		const tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(m_internalFormat);
    205 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
    206 		const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
    207 		const tcu::Vec4					cBias		= fmtInfo.valueMin;
    208 		const int						numLevels	= deLog2Floor32(m_size) + 1;
    209 		const int						numLayers	= m_depth / 6;
    210 
    211 		// Create textures.
    212 		m_gradientTex	= new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
    213 		m_gridTex		= new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
    214 
    215 		const tcu::IVec4 levelSwz[] =
    216 		{
    217 			tcu::IVec4(0,1,2,3),
    218 			tcu::IVec4(2,1,3,0),
    219 			tcu::IVec4(3,0,1,2),
    220 			tcu::IVec4(1,3,2,0),
    221 		};
    222 
    223 		// Fill first gradient texture (gradient direction varies between layers).
    224 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    225 		{
    226 			m_gradientTex->getRefTexture().allocLevel(levelNdx);
    227 
    228 			const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
    229 
    230 			for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
    231 			{
    232 				const tcu::IVec4	swz		= levelSwz[layerFaceNdx % DE_LENGTH_OF_ARRAY(levelSwz)];
    233 				const tcu::Vec4		gMin	= tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
    234 				const tcu::Vec4		gMax	= tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
    235 
    236 				tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax);
    237 			}
    238 		}
    239 
    240 		// Fill second with grid texture (each layer has unique colors).
    241 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
    242 		{
    243 			m_gridTex->getRefTexture().allocLevel(levelNdx);
    244 
    245 			const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
    246 
    247 			for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
    248 			{
    249 				const deUint32	step	= 0x00ffffff / (numLevels*m_depth - 1);
    250 				const deUint32	rgb		= step * (levelNdx + layerFaceNdx*numLevels);
    251 				const deUint32	colorA	= 0xff000000 | rgb;
    252 				const deUint32	colorB	= 0xff000000 | ~rgb;
    253 
    254 				tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1),
    255 								  4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
    256 			}
    257 		}
    258 
    259 		// Upload.
    260 		m_gradientTex->upload();
    261 		m_gridTex->upload();
    262 
    263 		// Test cases
    264 		{
    265 			const glu::TextureCubeArray* const	tex0	= m_gradientTex;
    266 			const glu::TextureCubeArray* const	tex1	= m_gridTex;
    267 
    268 			if (m_onlySampleFaceInterior)
    269 			{
    270 				m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f),	tcu::Vec2(0.8f,  0.8f),	tcu::Vec2(-0.5f, float(numLayers)+0.5f)));	// minification
    271 				m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f),	tcu::Vec2(0.8f,  0.8f),	tcu::Vec2(-0.5f, float(numLayers)+0.5f)));	// magnification
    272 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f),	tcu::Vec2(0.8f,  0.8f),	tcu::Vec2(float(numLayers)+0.5f, -0.5f)));	// minification
    273 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f),	tcu::Vec2(0.6f,  0.5f),	tcu::Vec2(float(numLayers)+0.5f, -0.5f)));	// magnification
    274 			}
    275 			else
    276 			{
    277 				const bool isSingleSample = (m_context.getRenderTarget().getNumSamples() == 0);
    278 
    279 				// minification - w/ tweak to avoid hitting triangle edges with a face switchpoint in multisample configs
    280 				if (isSingleSample)
    281 					m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
    282 				else
    283 					m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
    284 
    285 				m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f),		tcu::Vec2(1.25f, 1.20f),	tcu::Vec2(-0.5f, float(numLayers)+0.5f)));	// magnification
    286 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f),	tcu::Vec2(1.1f, 1.35f),		tcu::Vec2(float(numLayers)+0.5f, -0.5f)));	// minification
    287 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f),		tcu::Vec2(-0.8f, -0.8f),	tcu::Vec2(float(numLayers)+0.5f, -0.5f)));	// magnification
    288 
    289 				// Layer rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
    290 				if (isSingleSample && (numLayers > 1))
    291 					m_cases.push_back(FilterCase(tex0,	tcu::Vec2(-2.0f, -1.5f  ),	tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
    292 			}
    293 		}
    294 
    295 		m_caseNdx = 0;
    296 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    297 	}
    298 	catch (...)
    299 	{
    300 		// Clean up to save memory.
    301 		TextureCubeArrayFilteringCase::deinit();
    302 		throw;
    303 	}
    304 }
    305 
    306 void TextureCubeArrayFilteringCase::deinit (void)
    307 {
    308 	delete m_gradientTex;
    309 	delete m_gridTex;
    310 
    311 	m_gradientTex	= DE_NULL;
    312 	m_gridTex		= DE_NULL;
    313 
    314 	m_renderer.clear();
    315 	m_cases.clear();
    316 }
    317 
    318 TextureCubeArrayFilteringCase::IterateResult TextureCubeArrayFilteringCase::iterate (void)
    319 {
    320 	TestLog&						log				= m_testCtx.getLog();
    321 	const glu::RenderContext&		renderCtx		= m_context.getRenderContext();
    322 	const glw::Functions&			gl				= renderCtx.getFunctions();
    323 	const int						viewportSize	= 28;
    324 	const deUint32					randomSeed		= deStringHash(getName()) ^ deInt32Hash(m_caseNdx) ^ m_testCtx.getCommandLine().getBaseSeed();
    325 	const RandomViewport			viewport		(m_context.getRenderTarget(), viewportSize, viewportSize, randomSeed);
    326 	const FilterCase&				curCase			= m_cases[m_caseNdx];
    327 	const tcu::TextureFormat		texFmt			= curCase.texture->getRefTexture().getFormat();
    328 	const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(texFmt);
    329 	const tcu::ScopedLogSection		section			(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
    330 	ReferenceParams					refParams		(TEXTURETYPE_CUBE_ARRAY);
    331 
    332 	if (viewport.width < viewportSize || viewport.height < viewportSize)
    333 		throw tcu::NotSupportedError("Render target too small", "", __FILE__, __LINE__);
    334 
    335 	// Params for reference computation.
    336 	refParams.sampler					= glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
    337 	refParams.sampler.seamlessCubeMap	= true;
    338 	refParams.samplerType				= getSamplerType(texFmt);
    339 	refParams.colorBias					= fmtInfo.lookupBias;
    340 	refParams.colorScale				= fmtInfo.lookupScale;
    341 	refParams.lodMode					= LODMODE_EXACT;
    342 
    343 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP_ARRAY, curCase.texture->getGLTexture());
    344 	gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER,	m_minFilter);
    345 	gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER,	m_magFilter);
    346 	gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S,		m_wrapS);
    347 	gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T,		m_wrapT);
    348 
    349 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
    350 
    351 	m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
    352 
    353 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
    354 	{
    355 		const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
    356 		tcu::Surface			result		(viewport.width, viewport.height);
    357 		vector<float>			texCoord;
    358 
    359 		computeQuadTexCoordCubeArray(texCoord, face, curCase.bottomLeft, curCase.topRight, curCase.layerRange);
    360 
    361 		log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
    362 
    363 		log << TestLog::Message << "Texture coordinates:" << TestLog::EndMessage;
    364 
    365 		logCubeArrayTexCoords(log, texCoord);
    366 
    367 		m_renderer.renderQuad(0, &texCoord[0], refParams);
    368 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
    369 
    370 		glu::readPixels(renderCtx, viewport.x, viewport.y, result.getAccess());
    371 		GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
    372 
    373 		{
    374 			const bool				isNearestOnly	= m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
    375 			const tcu::PixelFormat	pixelFormat		= renderCtx.getRenderTarget().getPixelFormat();
    376 			const tcu::IVec4		coordBits		= tcu::IVec4(10);
    377 			const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
    378 			tcu::LodPrecision		lodPrecision;
    379 			tcu::LookupPrecision	lookupPrecision;
    380 
    381 			lodPrecision.derivateBits		= 10;
    382 			lodPrecision.lodBits			= 5;
    383 			lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
    384 			lookupPrecision.coordBits		= coordBits.toWidth<3>();
    385 			lookupPrecision.uvwBits			= tcu::IVec3(6);
    386 			lookupPrecision.colorMask		= getCompareMask(pixelFormat);
    387 
    388 			const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
    389 														   &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
    390 
    391 			if (!isHighQuality)
    392 			{
    393 				// Evaluate against lower precision requirements.
    394 				lodPrecision.lodBits	= 4;
    395 				lookupPrecision.uvwBits	= tcu::IVec3(4);
    396 
    397 				m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
    398 
    399 				const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
    400 													  &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
    401 
    402 				if (!isOk)
    403 				{
    404 					m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
    405 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
    406 				}
    407 				else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    408 					m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
    409 			}
    410 		}
    411 	}
    412 
    413 	m_caseNdx += 1;
    414 	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
    415 }
    416 
    417 TextureFilteringTests::TextureFilteringTests (Context& context)
    418 	: TestCaseGroup(context, "filtering", "Texture Filtering Tests")
    419 {
    420 }
    421 
    422 TextureFilteringTests::~TextureFilteringTests (void)
    423 {
    424 }
    425 
    426 void TextureFilteringTests::init (void)
    427 {
    428 	static const struct
    429 	{
    430 		const char*		name;
    431 		deUint32		mode;
    432 	} wrapModes[] =
    433 	{
    434 		{ "clamp",		GL_CLAMP_TO_EDGE },
    435 		{ "repeat",		GL_REPEAT },
    436 		{ "mirror",		GL_MIRRORED_REPEAT }
    437 	};
    438 
    439 	static const struct
    440 	{
    441 		const char*		name;
    442 		deUint32		mode;
    443 	} minFilterModes[] =
    444 	{
    445 		{ "nearest",				GL_NEAREST					},
    446 		{ "linear",					GL_LINEAR					},
    447 		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
    448 		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST	},
    449 		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR	},
    450 		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR		}
    451 	};
    452 
    453 	static const struct
    454 	{
    455 		const char*		name;
    456 		deUint32		mode;
    457 	} magFilterModes[] =
    458 	{
    459 		{ "nearest",	GL_NEAREST },
    460 		{ "linear",		GL_LINEAR }
    461 	};
    462 
    463 	static const struct
    464 	{
    465 		int size;
    466 		int depth;
    467 	} sizesCubeArray[] =
    468 	{
    469 		{   8,	 6 },
    470 		{  64,	12 },
    471 		{ 128,	12 },
    472 		{   7,	12 },
    473 		{  63,	18 }
    474 	};
    475 
    476 	static const struct
    477 	{
    478 		const char*		name;
    479 		deUint32		format;
    480 	} filterableFormatsByType[] =
    481 	{
    482 		{ "rgba16f",		GL_RGBA16F			},
    483 		{ "r11f_g11f_b10f",	GL_R11F_G11F_B10F	},
    484 		{ "rgb9_e5",		GL_RGB9_E5			},
    485 		{ "rgba8",			GL_RGBA8			},
    486 		{ "rgba8_snorm",	GL_RGBA8_SNORM		},
    487 		{ "rgb565",			GL_RGB565			},
    488 		{ "rgba4",			GL_RGBA4			},
    489 		{ "rgb5_a1",		GL_RGB5_A1			},
    490 		{ "srgb8_alpha8",	GL_SRGB8_ALPHA8		},
    491 		{ "rgb10_a2",		GL_RGB10_A2			}
    492 	};
    493 
    494 	// Cube map array texture filtering.
    495 	{
    496 		tcu::TestCaseGroup* const groupCubeArray = new tcu::TestCaseGroup(m_testCtx, "cube_array", "Cube Map Array Texture Filtering");
    497 		addChild(groupCubeArray);
    498 
    499 		// Formats.
    500 		{
    501 			tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "Cube Map Array Texture Formats");
    502 			groupCubeArray->addChild(formatsGroup);
    503 
    504 			for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
    505 			{
    506 				for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
    507 				{
    508 					const deUint32	minFilter	= minFilterModes[filterNdx].mode;
    509 					const char*		filterName	= minFilterModes[filterNdx].name;
    510 					const deUint32	format		= filterableFormatsByType[fmtNdx].format;
    511 					const char*		formatName	= filterableFormatsByType[fmtNdx].name;
    512 					const bool		isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
    513 					const deUint32	magFilter	= isMipmap ? GL_LINEAR : minFilter;
    514 					const string	name		= string(formatName) + "_" + filterName;
    515 					const deUint32	wrapS		= GL_REPEAT;
    516 					const deUint32	wrapT		= GL_REPEAT;
    517 					const int		size		= 64;
    518 					const int		depth		= 12;
    519 
    520 					formatsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
    521 																			 name.c_str(), "",
    522 																			 minFilter, magFilter,
    523 																			 wrapS, wrapT,
    524 																			 format,
    525 																			 size, depth));
    526 				}
    527 			}
    528 		}
    529 
    530 		// Sizes.
    531 		{
    532 			tcu::TestCaseGroup* const sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
    533 			groupCubeArray->addChild(sizesGroup);
    534 
    535 			for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCubeArray); sizeNdx++)
    536 			{
    537 				for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
    538 				{
    539 					const deUint32	minFilter	= minFilterModes[filterNdx].mode;
    540 					const char*		filterName	= minFilterModes[filterNdx].name;
    541 					const deUint32	format		= GL_RGBA8;
    542 					const bool		isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
    543 					const deUint32	magFilter	= isMipmap ? GL_LINEAR : minFilter;
    544 					const deUint32	wrapS		= GL_REPEAT;
    545 					const deUint32	wrapT		= GL_REPEAT;
    546 					const int		size		= sizesCubeArray[sizeNdx].size;
    547 					const int		depth		= sizesCubeArray[sizeNdx].depth;
    548 					const string	name		= de::toString(size) + "x" + de::toString(size) + "x" + de::toString(depth) + "_" + filterName;
    549 
    550 					sizesGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
    551 																		   name.c_str(), "",
    552 																		   minFilter, magFilter,
    553 																		   wrapS, wrapT,
    554 																		   format,
    555 																		   size, depth));
    556 				}
    557 			}
    558 		}
    559 
    560 		// Wrap modes.
    561 		{
    562 			tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
    563 			groupCubeArray->addChild(combinationsGroup);
    564 
    565 			for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
    566 			{
    567 				for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
    568 				{
    569 					for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
    570 					{
    571 						for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
    572 						{
    573 							const deUint32	minFilter	= minFilterModes[minFilterNdx].mode;
    574 							const deUint32	magFilter	= magFilterModes[magFilterNdx].mode;
    575 							const deUint32	format		= GL_RGBA8;
    576 							const deUint32	wrapS		= wrapModes[wrapSNdx].mode;
    577 							const deUint32	wrapT		= wrapModes[wrapTNdx].mode;
    578 							const int		size		= 63;
    579 							const int		depth		= 12;
    580 							const string	name		= string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
    581 
    582 							combinationsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
    583 																						  name.c_str(), "",
    584 																						  minFilter, magFilter,
    585 																						  wrapS, wrapT,
    586 																						  format,
    587 																						  size, depth));
    588 						}
    589 					}
    590 				}
    591 			}
    592 		}
    593 
    594 		// Cases with no visible cube edges.
    595 		{
    596 			tcu::TestCaseGroup* const onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
    597 			groupCubeArray->addChild(onlyFaceInteriorGroup);
    598 
    599 			for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
    600 			{
    601 				const bool		isLinear	= isLinearI != 0;
    602 				const deUint32	filter		= isLinear ? GL_LINEAR : GL_NEAREST;
    603 
    604 				onlyFaceInteriorGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
    605 																				  isLinear ? "linear" : "nearest", "",
    606 																				  filter, filter,
    607 																				  GL_REPEAT, GL_REPEAT,
    608 																				  GL_RGBA8,
    609 																				  63, 12,
    610 																				  true));
    611 			}
    612 		}
    613 	}
    614 }
    615 
    616 } // Functional
    617 } // gles31
    618 } // deqp
    619