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