• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Texture filtering tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fTextureFilteringTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluTexture.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuTexLookupVerifier.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "deStringUtil.hpp"
34 #include "deString.h"
35 #include "glwFunctions.hpp"
36 #include "glwEnums.hpp"
37 #include "gluContextInfo.hpp"
38 #include "deUniquePtr.hpp"
39 
40 using de::MovePtr;
41 using glu::ContextInfo;
42 
43 namespace deqp
44 {
45 namespace gles3
46 {
47 namespace Functional
48 {
49 
50 using std::vector;
51 using std::string;
52 using tcu::TestLog;
53 using namespace gls::TextureTestUtil;
54 using namespace glu::TextureTestUtil;
55 
56 enum
57 {
58 	TEX2D_VIEWPORT_WIDTH		= 64,
59 	TEX2D_VIEWPORT_HEIGHT		= 64,
60 	TEX2D_MIN_VIEWPORT_WIDTH	= 64,
61 	TEX2D_MIN_VIEWPORT_HEIGHT	= 64,
62 
63 	TEX3D_VIEWPORT_WIDTH		= 64,
64 	TEX3D_VIEWPORT_HEIGHT		= 64,
65 	TEX3D_MIN_VIEWPORT_WIDTH	= 64,
66 	TEX3D_MIN_VIEWPORT_HEIGHT	= 64
67 };
68 
69 namespace
70 {
71 
checkSupport(const glu::ContextInfo & info,deUint32 internalFormat)72 void checkSupport (const glu::ContextInfo& info, deUint32 internalFormat)
73 {
74 	if (internalFormat == GL_SR8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_R8"))
75 		TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_R8 is not supported.");
76 
77 	if (internalFormat == GL_SRG8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_RG8"))
78 		TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_RG8 is not supported.");
79 }
80 
81 } // anonymous
82 
83 class Texture2DFilteringCase : public tcu::TestCase
84 {
85 public:
86 									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 internalFormat, int width, int height);
87 									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);
88 									~Texture2DFilteringCase		(void);
89 
90 	void							init						(void);
91 	void							deinit						(void);
92 	IterateResult					iterate						(void);
93 
94 private:
95 									Texture2DFilteringCase		(const Texture2DFilteringCase& other);
96 	Texture2DFilteringCase&			operator=					(const Texture2DFilteringCase& other);
97 
98 	glu::RenderContext&				m_renderCtx;
99 	const glu::ContextInfo&			m_renderCtxInfo;
100 
101 	const deUint32					m_minFilter;
102 	const deUint32					m_magFilter;
103 	const deUint32					m_wrapS;
104 	const deUint32					m_wrapT;
105 
106 	const deUint32					m_internalFormat;
107 	const int						m_width;
108 	const int						m_height;
109 
110 	const std::vector<std::string>	m_filenames;
111 
112 	struct FilterCase
113 	{
114 		const glu::Texture2D*	texture;
115 		tcu::Vec2				minCoord;
116 		tcu::Vec2				maxCoord;
117 
FilterCasedeqp::gles3::Functional::Texture2DFilteringCase::FilterCase118 		FilterCase (void)
119 			: texture(DE_NULL)
120 		{
121 		}
122 
FilterCasedeqp::gles3::Functional::Texture2DFilteringCase::FilterCase123 		FilterCase (const glu::Texture2D* tex_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
124 			: texture	(tex_)
125 			, minCoord	(minCoord_)
126 			, maxCoord	(maxCoord_)
127 		{
128 		}
129 	};
130 
131 	std::vector<glu::Texture2D*>	m_textures;
132 	std::vector<FilterCase>			m_cases;
133 
134 	TextureRenderer					m_renderer;
135 
136 	int								m_caseNdx;
137 };
138 
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 internalFormat,int width,int height)139 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 internalFormat, int width, int height)
140 	: TestCase			(testCtx, name, desc)
141 	, m_renderCtx		(renderCtx)
142 	, m_renderCtxInfo	(ctxInfo)
143 	, m_minFilter		(minFilter)
144 	, m_magFilter		(magFilter)
145 	, m_wrapS			(wrapS)
146 	, m_wrapT			(wrapT)
147 	, m_internalFormat	(internalFormat)
148 	, m_width			(width)
149 	, m_height			(height)
150 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
151 	, m_caseNdx			(0)
152 {
153 }
154 
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)155 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)
156 	: TestCase			(testCtx, name, desc)
157 	, m_renderCtx		(renderCtx)
158 	, m_renderCtxInfo	(ctxInfo)
159 	, m_minFilter		(minFilter)
160 	, m_magFilter		(magFilter)
161 	, m_wrapS			(wrapS)
162 	, m_wrapT			(wrapT)
163 	, m_internalFormat	(GL_NONE)
164 	, m_width			(0)
165 	, m_height			(0)
166 	, m_filenames		(filenames)
167 	, m_renderer		(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
168 	, m_caseNdx			(0)
169 {
170 }
171 
~Texture2DFilteringCase(void)172 Texture2DFilteringCase::~Texture2DFilteringCase (void)
173 {
174 	deinit();
175 }
176 
init(void)177 void Texture2DFilteringCase::init (void)
178 {
179 	checkSupport(m_renderCtxInfo, m_internalFormat);
180 
181 	try
182 	{
183 		if (!m_filenames.empty())
184 		{
185 			m_textures.reserve(1);
186 			m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size(), m_filenames));
187 		}
188 		else
189 		{
190 			// Create 2 textures.
191 			m_textures.reserve(2);
192 			for (int ndx = 0; ndx < 2; ndx++)
193 				m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height));
194 
195 			const bool						mipmaps		= true;
196 			const int						numLevels	= mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1;
197 			const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
198 			const tcu::Vec4					cBias		= fmtInfo.valueMin;
199 			const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
200 
201 			// Fill first gradient texture.
202 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
203 			{
204 				tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
205 				tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
206 
207 				m_textures[0]->getRefTexture().allocLevel(levelNdx);
208 				tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
209 			}
210 
211 			// Fill second with grid texture.
212 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
213 			{
214 				deUint32	step	= 0x00ffffff / numLevels;
215 				deUint32	rgb		= step*levelNdx;
216 				deUint32	colorA	= 0xff000000 | rgb;
217 				deUint32	colorB	= 0xff000000 | ~rgb;
218 
219 				m_textures[1]->getRefTexture().allocLevel(levelNdx);
220 				tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
221 			}
222 
223 			// Upload.
224 			for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
225 				(*i)->upload();
226 		}
227 
228 		// Compute cases.
229 		{
230 			const struct
231 			{
232 				int		texNdx;
233 				float	lodX;
234 				float	lodY;
235 				float	oX;
236 				float	oY;
237 			} cases[] =
238 			{
239 				{ 0,	1.6f,	2.9f,	-1.0f,	-2.7f	},
240 				{ 0,	-2.0f,	-1.35f,	-0.2f,	0.7f	},
241 				{ 1,	0.14f,	0.275f,	-1.5f,	-1.1f	},
242 				{ 1,	-0.92f,	-2.64f,	0.4f,	-0.1f	},
243 			};
244 
245 			const float	viewportW	= (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_renderCtx.getRenderTarget().getWidth());
246 			const float	viewportH	= (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_renderCtx.getRenderTarget().getHeight());
247 
248 			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
249 			{
250 				const int	texNdx	= de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
251 				const float	lodX	= cases[caseNdx].lodX;
252 				const float	lodY	= cases[caseNdx].lodY;
253 				const float	oX		= cases[caseNdx].oX;
254 				const float	oY		= cases[caseNdx].oY;
255 				const float	sX		= deFloatExp2(lodX)*viewportW / float(m_textures[texNdx]->getRefTexture().getWidth());
256 				const float	sY		= deFloatExp2(lodY)*viewportH / float(m_textures[texNdx]->getRefTexture().getHeight());
257 
258 				m_cases.push_back(FilterCase(m_textures[texNdx], tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
259 			}
260 		}
261 
262 		m_caseNdx = 0;
263 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
264 	}
265 	catch (...)
266 	{
267 		// Clean up to save memory.
268 		Texture2DFilteringCase::deinit();
269 		throw;
270 	}
271 }
272 
deinit(void)273 void Texture2DFilteringCase::deinit (void)
274 {
275 	for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
276 		delete *i;
277 	m_textures.clear();
278 
279 	m_renderer.clear();
280 	m_cases.clear();
281 }
282 
iterate(void)283 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void)
284 {
285 	const glw::Functions&			gl			= m_renderCtx.getFunctions();
286 	const RandomViewport			viewport	(m_renderCtx.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
287 	const tcu::TextureFormat		texFmt		= m_textures[0]->getRefTexture().getFormat();
288 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
289 	const FilterCase&				curCase		= m_cases[m_caseNdx];
290 	const tcu::ScopedLogSection		section		(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
291 	ReferenceParams					refParams	(TEXTURETYPE_2D);
292 	tcu::Surface					rendered	(viewport.width, viewport.height);
293 	vector<float>					texCoord;
294 
295 	if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
296 		throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
297 
298 	// Setup params for reference.
299 	refParams.sampler		= glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
300 	refParams.samplerType	= getSamplerType(texFmt);
301 	refParams.lodMode		= LODMODE_EXACT;
302 	refParams.colorBias		= fmtInfo.lookupBias;
303 	refParams.colorScale	= fmtInfo.lookupScale;
304 
305 	// Compute texture coordinates.
306 	m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
307 	computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
308 
309 	gl.bindTexture	(GL_TEXTURE_2D, curCase.texture->getGLTexture());
310 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
311 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
312 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
313 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
314 
315 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
316 	m_renderer.renderQuad(0, &texCoord[0], refParams);
317 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
318 
319 	{
320 		const bool				isNearestOnly	= m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
321 		const tcu::PixelFormat	pixelFormat		= m_renderCtx.getRenderTarget().getPixelFormat();
322 		const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
323 		tcu::LodPrecision		lodPrecision;
324 		tcu::LookupPrecision	lookupPrecision;
325 
326 		lodPrecision.derivateBits		= 18;
327 		lodPrecision.lodBits			= 6;
328 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
329 		lookupPrecision.coordBits		= tcu::IVec3(20,20,0);
330 		lookupPrecision.uvwBits			= tcu::IVec3(7,7,0);
331 		lookupPrecision.colorMask		= getCompareMask(pixelFormat);
332 
333 		const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
334 													   &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
335 
336 		if (!isHighQuality)
337 		{
338 			// Evaluate against lower precision requirements.
339 			lodPrecision.lodBits	= 4;
340 			lookupPrecision.uvwBits	= tcu::IVec3(4,4,0);
341 
342 			m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
343 
344 			const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
345 												  &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
346 
347 			if (!isOk)
348 			{
349 				m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
350 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
351 			}
352 			else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
353 				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
354 		}
355 	}
356 
357 	m_caseNdx += 1;
358 	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
359 }
360 
361 class TextureCubeFilteringCase : public tcu::TestCase
362 {
363 public:
364 									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, bool onlySampleFaceInterior, deUint32 internalFormat, int width, int height);
365 									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, bool onlySampleFaceInterior, const std::vector<std::string>& filenames);
366 									~TextureCubeFilteringCase	(void);
367 
368 	void							init						(void);
369 	void							deinit						(void);
370 	IterateResult					iterate						(void);
371 
372 private:
373 									TextureCubeFilteringCase	(const TextureCubeFilteringCase& other);
374 	TextureCubeFilteringCase&		operator=					(const TextureCubeFilteringCase& other);
375 
376 	glu::RenderContext&				m_renderCtx;
377 	const glu::ContextInfo&			m_renderCtxInfo;
378 
379 	const deUint32					m_minFilter;
380 	const deUint32					m_magFilter;
381 	const deUint32					m_wrapS;
382 	const deUint32					m_wrapT;
383 	const bool						m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
384 
385 	const deUint32					m_internalFormat;
386 	const int						m_width;
387 	const int						m_height;
388 
389 	const std::vector<std::string>	m_filenames;
390 
391 	struct FilterCase
392 	{
393 		const glu::TextureCube*	texture;
394 		tcu::Vec2				bottomLeft;
395 		tcu::Vec2				topRight;
396 
FilterCasedeqp::gles3::Functional::TextureCubeFilteringCase::FilterCase397 		FilterCase (void)
398 			: texture(DE_NULL)
399 		{
400 		}
401 
FilterCasedeqp::gles3::Functional::TextureCubeFilteringCase::FilterCase402 		FilterCase (const glu::TextureCube* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
403 			: texture	(tex_)
404 			, bottomLeft(bottomLeft_)
405 			, topRight	(topRight_)
406 		{
407 		}
408 	};
409 
410 	std::vector<glu::TextureCube*>	m_textures;
411 	std::vector<FilterCase>			m_cases;
412 
413 	TextureRenderer					m_renderer;
414 
415 	int								m_caseNdx;
416 };
417 
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,bool onlySampleFaceInterior,deUint32 internalFormat,int width,int height)418 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, bool onlySampleFaceInterior, deUint32 internalFormat, int width, int height)
419 	: TestCase					(testCtx, name, desc)
420 	, m_renderCtx				(renderCtx)
421 	, m_renderCtxInfo			(ctxInfo)
422 	, m_minFilter				(minFilter)
423 	, m_magFilter				(magFilter)
424 	, m_wrapS					(wrapS)
425 	, m_wrapT					(wrapT)
426 	, m_onlySampleFaceInterior	(onlySampleFaceInterior)
427 	, m_internalFormat			(internalFormat)
428 	, m_width					(width)
429 	, m_height					(height)
430 	, m_renderer				(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
431 	, m_caseNdx					(0)
432 {
433 }
434 
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,bool onlySampleFaceInterior,const std::vector<std::string> & filenames)435 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, bool onlySampleFaceInterior, const std::vector<std::string>& filenames)
436 	: TestCase					(testCtx, name, desc)
437 	, m_renderCtx				(renderCtx)
438 	, m_renderCtxInfo			(ctxInfo)
439 	, m_minFilter				(minFilter)
440 	, m_magFilter				(magFilter)
441 	, m_wrapS					(wrapS)
442 	, m_wrapT					(wrapT)
443 	, m_onlySampleFaceInterior	(onlySampleFaceInterior)
444 	, m_internalFormat			(GL_NONE)
445 	, m_width					(0)
446 	, m_height					(0)
447 	, m_filenames				(filenames)
448 	, m_renderer				(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
449 	, m_caseNdx					(0)
450 {
451 }
452 
~TextureCubeFilteringCase(void)453 TextureCubeFilteringCase::~TextureCubeFilteringCase (void)
454 {
455 	deinit();
456 }
457 
init(void)458 void TextureCubeFilteringCase::init (void)
459 {
460 	checkSupport(m_renderCtxInfo, m_internalFormat);
461 
462 	try
463 	{
464 		if (!m_filenames.empty())
465 		{
466 			m_textures.reserve(1);
467 			m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size() / 6, m_filenames));
468 		}
469 		else
470 		{
471 			DE_ASSERT(m_width == m_height);
472 			m_textures.reserve(2);
473 			for (int ndx = 0; ndx < 2; ndx++)
474 				m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width));
475 
476 			const int				numLevels	= deLog2Floor32(de::max(m_width, m_height))+1;
477 			tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
478 			tcu::Vec4				cBias		= fmtInfo.valueMin;
479 			tcu::Vec4				cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
480 
481 			// Fill first with gradient texture.
482 			static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
483 			{
484 				{ tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
485 				{ tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
486 				{ tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
487 				{ tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
488 				{ tcu::Vec4(0.0f, 0.0f, 0.0f, 0.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
489 				{ tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
490 			};
491 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
492 			{
493 				for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
494 				{
495 					m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
496 					tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
497 				}
498 			}
499 
500 			// Fill second with grid texture.
501 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
502 			{
503 				for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
504 				{
505 					deUint32	step	= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
506 					deUint32	rgb		= step*levelNdx*face;
507 					deUint32	colorA	= 0xff000000 | rgb;
508 					deUint32	colorB	= 0xff000000 | ~rgb;
509 
510 					m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
511 					tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
512 				}
513 			}
514 
515 			// Upload.
516 			for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
517 				(*i)->upload();
518 		}
519 
520 		// Compute cases
521 		{
522 			const glu::TextureCube*	tex0	= m_textures[0];
523 			const glu::TextureCube* tex1	= m_textures.size() > 1 ? m_textures[1] : tex0;
524 
525 			if (m_onlySampleFaceInterior)
526 			{
527 				m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));	// minification
528 				m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f,  0.8f)));	// magnification
529 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));	// minification
530 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f,  0.5f)));		// magnification
531 			}
532 			else
533 			{
534 				if (m_renderCtx.getRenderTarget().getNumSamples() == 0)
535 					m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f)));	// minification
536 				else
537 					m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));	// minification - w/ tweak to avoid hitting triangle edges with face switchpoint
538 
539 				m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f)));	// magnification
540 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));	// minification
541 				m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f)));	// magnification
542 			}
543 		}
544 
545 		m_caseNdx = 0;
546 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
547 	}
548 	catch (...)
549 	{
550 		// Clean up to save memory.
551 		TextureCubeFilteringCase::deinit();
552 		throw;
553 	}
554 }
555 
deinit(void)556 void TextureCubeFilteringCase::deinit (void)
557 {
558 	for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
559 		delete *i;
560 	m_textures.clear();
561 
562 	m_renderer.clear();
563 	m_cases.clear();
564 }
565 
getFaceDesc(const tcu::CubeFace face)566 static const char* getFaceDesc (const tcu::CubeFace face)
567 {
568 	switch (face)
569 	{
570 		case tcu::CUBEFACE_NEGATIVE_X:	return "-X";
571 		case tcu::CUBEFACE_POSITIVE_X:	return "+X";
572 		case tcu::CUBEFACE_NEGATIVE_Y:	return "-Y";
573 		case tcu::CUBEFACE_POSITIVE_Y:	return "+Y";
574 		case tcu::CUBEFACE_NEGATIVE_Z:	return "-Z";
575 		case tcu::CUBEFACE_POSITIVE_Z:	return "+Z";
576 		default:
577 			DE_ASSERT(false);
578 			return DE_NULL;
579 	}
580 }
581 
iterate(void)582 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void)
583 {
584 	const glw::Functions&			gl				= m_renderCtx.getFunctions();
585 	const int						viewportSize	= 28;
586 	const RandomViewport			viewport		(m_renderCtx.getRenderTarget(), viewportSize, viewportSize, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
587 	const tcu::ScopedLogSection		iterSection		(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
588 	const FilterCase&				curCase			= m_cases[m_caseNdx];
589 	const tcu::TextureFormat&		texFmt			= curCase.texture->getRefTexture().getFormat();
590 	const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(texFmt);
591 	ReferenceParams					sampleParams	(TEXTURETYPE_CUBE);
592 
593 	if (viewport.width < viewportSize || viewport.height < viewportSize)
594 		throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__);
595 
596 	// Setup texture
597 	gl.bindTexture	(GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture());
598 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
599 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
600 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
601 	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
602 
603 	// Other state
604 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
605 
606 	// Params for reference computation.
607 	sampleParams.sampler					= glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
608 	sampleParams.sampler.seamlessCubeMap	= true;
609 	sampleParams.samplerType				= getSamplerType(texFmt);
610 	sampleParams.colorBias					= fmtInfo.lookupBias;
611 	sampleParams.colorScale					= fmtInfo.lookupScale;
612 	sampleParams.lodMode					= LODMODE_EXACT;
613 
614 	m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
615 
616 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
617 	{
618 		const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
619 		tcu::Surface			result		(viewport.width, viewport.height);
620 		vector<float>			texCoord;
621 
622 		computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
623 
624 		m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
625 
626 		// \todo Log texture coordinates.
627 
628 		m_renderer.renderQuad(0, &texCoord[0], sampleParams);
629 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
630 
631 		glu::readPixels(m_renderCtx, viewport.x, viewport.y, result.getAccess());
632 		GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
633 
634 		{
635 			const bool				isNearestOnly	= m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
636 			const tcu::PixelFormat	pixelFormat		= m_renderCtx.getRenderTarget().getPixelFormat();
637 			const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
638 			tcu::LodPrecision		lodPrecision;
639 			tcu::LookupPrecision	lookupPrecision;
640 
641 			lodPrecision.derivateBits		= 10;
642 			lodPrecision.lodBits			= 5;
643 			lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / sampleParams.colorScale;
644 			lookupPrecision.coordBits		= tcu::IVec3(10,10,10);
645 			lookupPrecision.uvwBits			= tcu::IVec3(6,6,0);
646 			lookupPrecision.colorMask		= getCompareMask(pixelFormat);
647 
648 			const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
649 														   &texCoord[0], sampleParams, lookupPrecision, lodPrecision, pixelFormat);
650 
651 			if (!isHighQuality)
652 			{
653 				// Evaluate against lower precision requirements.
654 				lodPrecision.lodBits	= 4;
655 				lookupPrecision.uvwBits	= tcu::IVec3(4,4,0);
656 
657 				m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
658 
659 				const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
660 													  &texCoord[0], sampleParams, lookupPrecision, lodPrecision, pixelFormat);
661 
662 				if (!isOk)
663 				{
664 					m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
665 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
666 				}
667 				else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
668 					m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
669 			}
670 		}
671 	}
672 
673 	m_caseNdx += 1;
674 	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
675 }
676 
677 // 2D array filtering
678 
679 class Texture2DArrayFilteringCase : public TestCase
680 {
681 public:
682 									Texture2DArrayFilteringCase		(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height, int numLayers);
683 									~Texture2DArrayFilteringCase	(void);
684 
685 	void							init							(void);
686 	void							deinit							(void);
687 	IterateResult					iterate							(void);
688 
689 private:
690 									Texture2DArrayFilteringCase		(const Texture2DArrayFilteringCase&);
691 	Texture2DArrayFilteringCase&	operator=						(const Texture2DArrayFilteringCase&);
692 
693 	const deUint32					m_minFilter;
694 	const deUint32					m_magFilter;
695 	const deUint32					m_wrapS;
696 	const deUint32					m_wrapT;
697 
698 	const deUint32					m_internalFormat;
699 	const int						m_width;
700 	const int						m_height;
701 	const int						m_numLayers;
702 
703 	struct FilterCase
704 	{
705 		const glu::Texture2DArray*	texture;
706 		tcu::Vec2					lod;
707 		tcu::Vec2					offset;
708 		tcu::Vec2					layerRange;
709 
FilterCasedeqp::gles3::Functional::Texture2DArrayFilteringCase::FilterCase710 		FilterCase (void)
711 			: texture(DE_NULL)
712 		{
713 		}
714 
FilterCasedeqp::gles3::Functional::Texture2DArrayFilteringCase::FilterCase715 		FilterCase (const glu::Texture2DArray* tex_, const tcu::Vec2& lod_, const tcu::Vec2& offset_, const tcu::Vec2& layerRange_)
716 			: texture	(tex_)
717 			, lod		(lod_)
718 			, offset	(offset_)
719 			, layerRange(layerRange_)
720 		{
721 		}
722 	};
723 
724 	glu::Texture2DArray*			m_gradientTex;
725 	glu::Texture2DArray*			m_gridTex;
726 
727 	TextureRenderer					m_renderer;
728 
729 	std::vector<FilterCase>			m_cases;
730 	int								m_caseNdx;
731 };
732 
Texture2DArrayFilteringCase(Context & context,const char * name,const char * desc,deUint32 minFilter,deUint32 magFilter,deUint32 wrapS,deUint32 wrapT,deUint32 internalFormat,int width,int height,int numLayers)733 Texture2DArrayFilteringCase::Texture2DArrayFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height, int numLayers)
734 	: TestCase			(context, name, desc)
735 	, m_minFilter		(minFilter)
736 	, m_magFilter		(magFilter)
737 	, m_wrapS			(wrapS)
738 	, m_wrapT			(wrapT)
739 	, m_internalFormat	(internalFormat)
740 	, m_width			(width)
741 	, m_height			(height)
742 	, m_numLayers		(numLayers)
743 	, m_gradientTex		(DE_NULL)
744 	, m_gridTex			(DE_NULL)
745 	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
746 	, m_caseNdx			(0)
747 {
748 }
749 
~Texture2DArrayFilteringCase(void)750 Texture2DArrayFilteringCase::~Texture2DArrayFilteringCase (void)
751 {
752 	Texture2DArrayFilteringCase::deinit();
753 }
754 
init(void)755 void Texture2DArrayFilteringCase::init (void)
756 {
757 	checkSupport(m_context.getContextInfo(), m_internalFormat);
758 
759 	try
760 	{
761 		const tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(m_internalFormat);
762 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
763 		const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
764 		const tcu::Vec4					cBias		= fmtInfo.valueMin;
765 		const int						numLevels	= deLog2Floor32(de::max(m_width, m_height)) + 1;
766 
767 		// Create textures.
768 		m_gradientTex	= new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers);
769 		m_gridTex		= new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers);
770 
771 		const tcu::IVec4 levelSwz[] =
772 		{
773 			tcu::IVec4(0,1,2,3),
774 			tcu::IVec4(2,1,3,0),
775 			tcu::IVec4(3,0,1,2),
776 			tcu::IVec4(1,3,2,0),
777 		};
778 
779 		// Fill first gradient texture (gradient direction varies between layers).
780 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
781 		{
782 			m_gradientTex->getRefTexture().allocLevel(levelNdx);
783 
784 			const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
785 
786 			for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++)
787 			{
788 				const tcu::IVec4	swz		= levelSwz[layerNdx%DE_LENGTH_OF_ARRAY(levelSwz)];
789 				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;
790 				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;
791 
792 				tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax);
793 			}
794 		}
795 
796 		// Fill second with grid texture (each layer has unique colors).
797 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
798 		{
799 			m_gridTex->getRefTexture().allocLevel(levelNdx);
800 
801 			const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
802 
803 			for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++)
804 			{
805 				const deUint32	step	= 0x00ffffff / (numLevels*m_numLayers - 1);
806 				const deUint32	rgb		= step * (levelNdx + layerNdx*numLevels);
807 				const deUint32	colorA	= 0xff000000 | rgb;
808 				const deUint32	colorB	= 0xff000000 | ~rgb;
809 
810 				tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1),
811 								  4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
812 			}
813 		}
814 
815 		// Upload.
816 		m_gradientTex->upload();
817 		m_gridTex->upload();
818 
819 		// Test cases
820 		m_cases.push_back(FilterCase(m_gradientTex,	tcu::Vec2( 1.5f,  2.8f  ),	tcu::Vec2(-1.0f, -2.7f), tcu::Vec2(-0.5f, float(m_numLayers)+0.5f)));
821 		m_cases.push_back(FilterCase(m_gridTex,		tcu::Vec2( 0.2f,  0.175f),	tcu::Vec2(-2.0f, -3.7f), tcu::Vec2(-0.5f, float(m_numLayers)+0.5f)));
822 		m_cases.push_back(FilterCase(m_gridTex,		tcu::Vec2(-0.8f, -2.3f  ),	tcu::Vec2( 0.2f, -0.1f), tcu::Vec2(float(m_numLayers)+0.5f, -0.5f)));
823 
824 		// Level rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
825 		if (m_context.getRenderTarget().getNumSamples() == 0)
826 			m_cases.push_back(FilterCase(m_gradientTex,	tcu::Vec2(-2.0f, -1.5f  ),	tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
827 
828 		m_caseNdx = 0;
829 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
830 	}
831 	catch (...)
832 	{
833 		// Clean up to save memory.
834 		Texture2DArrayFilteringCase::deinit();
835 		throw;
836 	}
837 }
838 
deinit(void)839 void Texture2DArrayFilteringCase::deinit (void)
840 {
841 	delete m_gradientTex;
842 	delete m_gridTex;
843 
844 	m_gradientTex	= DE_NULL;
845 	m_gridTex		= DE_NULL;
846 
847 	m_renderer.clear();
848 	m_cases.clear();
849 }
850 
iterate(void)851 Texture2DArrayFilteringCase::IterateResult Texture2DArrayFilteringCase::iterate (void)
852 {
853 	const glw::Functions&			gl			= m_context.getRenderContext().getFunctions();
854 	const RandomViewport			viewport	(m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
855 	const FilterCase&				curCase		= m_cases[m_caseNdx];
856 	const tcu::TextureFormat		texFmt		= curCase.texture->getRefTexture().getFormat();
857 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
858 	const tcu::ScopedLogSection		section		(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
859 	ReferenceParams					refParams	(TEXTURETYPE_2D_ARRAY);
860 	tcu::Surface					rendered	(viewport.width, viewport.height);
861 	tcu::Vec3						texCoord[4];
862 
863 	if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT)
864 		throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
865 
866 	// Setup params for reference.
867 	refParams.sampler		= glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapT, m_minFilter, m_magFilter);
868 	refParams.samplerType	= getSamplerType(texFmt);
869 	refParams.lodMode		= LODMODE_EXACT;
870 	refParams.colorBias		= fmtInfo.lookupBias;
871 	refParams.colorScale	= fmtInfo.lookupScale;
872 
873 	// Compute texture coordinates.
874 	m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
875 
876 	{
877 		const float	lodX	= curCase.lod.x();
878 		const float	lodY	= curCase.lod.y();
879 		const float	oX		= curCase.offset.x();
880 		const float	oY		= curCase.offset.y();
881 		const float	sX		= deFloatExp2(lodX)*float(viewport.width)	/ float(m_gradientTex->getRefTexture().getWidth());
882 		const float	sY		= deFloatExp2(lodY)*float(viewport.height)	/ float(m_gradientTex->getRefTexture().getHeight());
883 		const float	l0		= curCase.layerRange.x();
884 		const float	l1		= curCase.layerRange.y();
885 
886 		texCoord[0] = tcu::Vec3(oX,		oY,		l0);
887 		texCoord[1] = tcu::Vec3(oX,		oY+sY,	l0*0.5f + l1*0.5f);
888 		texCoord[2] = tcu::Vec3(oX+sX,	oY,		l0*0.5f + l1*0.5f);
889 		texCoord[3] = tcu::Vec3(oX+sX,	oY+sY,	l1);
890 	}
891 
892 	gl.bindTexture	(GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture());
893 	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,	m_minFilter);
894 	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,	m_magFilter);
895 	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,		m_wrapS);
896 	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,		m_wrapT);
897 
898 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
899 	m_renderer.renderQuad(0, (const float*)&texCoord[0], refParams);
900 	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
901 
902 	{
903 		const bool				isNearestOnly	= m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
904 		const tcu::PixelFormat	pixelFormat		= m_context.getRenderTarget().getPixelFormat();
905 		const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
906 		tcu::LodPrecision		lodPrecision;
907 		tcu::LookupPrecision	lookupPrecision;
908 
909 		lodPrecision.derivateBits		= 18;
910 		lodPrecision.lodBits			= 6;
911 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
912 		lookupPrecision.coordBits		= tcu::IVec3(20,20,20);
913 		lookupPrecision.uvwBits			= tcu::IVec3(7,7,0);
914 		lookupPrecision.colorMask		= getCompareMask(pixelFormat);
915 
916 		const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
917 													   (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
918 
919 		if (!isHighQuality)
920 		{
921 			// Evaluate against lower precision requirements.
922 			lodPrecision.lodBits	= 4;
923 			lookupPrecision.uvwBits	= tcu::IVec3(4,4,0);
924 
925 			m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
926 
927 			const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
928 												  (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
929 
930 			if (!isOk)
931 			{
932 				m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
933 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
934 			}
935 			else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
936 				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
937 		}
938 	}
939 
940 	m_caseNdx += 1;
941 	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
942 }
943 
944 // 3D filtering
945 
946 class Texture3DFilteringCase : public TestCase
947 {
948 public:
949 									Texture3DFilteringCase		(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 internalFormat, int width, int height, int depth);
950 									~Texture3DFilteringCase		(void);
951 
952 	void							init						(void);
953 	void							deinit						(void);
954 	IterateResult					iterate						(void);
955 
956 private:
957 									Texture3DFilteringCase		(const Texture3DFilteringCase& other);
958 	Texture3DFilteringCase&			operator=					(const Texture3DFilteringCase& other);
959 
960 	const deUint32					m_minFilter;
961 	const deUint32					m_magFilter;
962 	const deUint32					m_wrapS;
963 	const deUint32					m_wrapT;
964 	const deUint32					m_wrapR;
965 
966 	const deUint32					m_internalFormat;
967 	const int						m_width;
968 	const int						m_height;
969 	const int						m_depth;
970 
971 	struct FilterCase
972 	{
973 		const glu::Texture3D*	texture;
974 		tcu::Vec3				lod;
975 		tcu::Vec3				offset;
976 
FilterCasedeqp::gles3::Functional::Texture3DFilteringCase::FilterCase977 		FilterCase (void)
978 			: texture(DE_NULL)
979 		{
980 		}
981 
FilterCasedeqp::gles3::Functional::Texture3DFilteringCase::FilterCase982 		FilterCase (const glu::Texture3D* tex_, const tcu::Vec3& lod_, const tcu::Vec3& offset_)
983 			: texture	(tex_)
984 			, lod		(lod_)
985 			, offset	(offset_)
986 		{
987 		}
988 	};
989 
990 	glu::Texture3D*					m_gradientTex;
991 	glu::Texture3D*					m_gridTex;
992 
993 	TextureRenderer					m_renderer;
994 
995 	std::vector<FilterCase>			m_cases;
996 	int								m_caseNdx;
997 };
998 
Texture3DFilteringCase(Context & context,const char * name,const char * desc,deUint32 minFilter,deUint32 magFilter,deUint32 wrapS,deUint32 wrapT,deUint32 wrapR,deUint32 internalFormat,int width,int height,int depth)999 Texture3DFilteringCase::Texture3DFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 internalFormat, int width, int height, int depth)
1000 	: TestCase			(context, name, desc)
1001 	, m_minFilter		(minFilter)
1002 	, m_magFilter		(magFilter)
1003 	, m_wrapS			(wrapS)
1004 	, m_wrapT			(wrapT)
1005 	, m_wrapR			(wrapR)
1006 	, m_internalFormat	(internalFormat)
1007 	, m_width			(width)
1008 	, m_height			(height)
1009 	, m_depth			(depth)
1010 	, m_gradientTex		(DE_NULL)
1011 	, m_gridTex			(DE_NULL)
1012 	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1013 	, m_caseNdx			(0)
1014 {
1015 }
1016 
~Texture3DFilteringCase(void)1017 Texture3DFilteringCase::~Texture3DFilteringCase (void)
1018 {
1019 	Texture3DFilteringCase::deinit();
1020 }
1021 
init(void)1022 void Texture3DFilteringCase::init (void)
1023 {
1024 	checkSupport(m_context.getContextInfo(), m_internalFormat);
1025 
1026 	try
1027 	{
1028 		const tcu::TextureFormat		texFmt		= glu::mapGLInternalFormat(m_internalFormat);
1029 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
1030 		const tcu::Vec4					cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
1031 		const tcu::Vec4					cBias		= fmtInfo.valueMin;
1032 		const int						numLevels	= deLog2Floor32(de::max(de::max(m_width, m_height), m_depth)) + 1;
1033 
1034 		// Create textures.
1035 		m_gradientTex	= new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1036 		m_gridTex		= new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1037 
1038 		// Fill first gradient texture.
1039 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1040 		{
1041 			tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
1042 			tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
1043 
1044 			m_gradientTex->getRefTexture().allocLevel(levelNdx);
1045 			tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
1046 		}
1047 
1048 		// Fill second with grid texture.
1049 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1050 		{
1051 			deUint32	step	= 0x00ffffff / numLevels;
1052 			deUint32	rgb		= step*levelNdx;
1053 			deUint32	colorA	= 0xff000000 | rgb;
1054 			deUint32	colorB	= 0xff000000 | ~rgb;
1055 
1056 			m_gridTex->getRefTexture().allocLevel(levelNdx);
1057 			tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
1058 		}
1059 
1060 		// Upload.
1061 		m_gradientTex->upload();
1062 		m_gridTex->upload();
1063 
1064 		// Test cases
1065 		m_cases.push_back(FilterCase(m_gradientTex,	tcu::Vec3(1.5f, 2.8f, 1.0f),	tcu::Vec3(-1.0f, -2.7f, -2.275f)));
1066 		m_cases.push_back(FilterCase(m_gradientTex,	tcu::Vec3(-2.0f, -1.5f, -1.8f),	tcu::Vec3(-0.1f, 0.9f, -0.25f)));
1067 		m_cases.push_back(FilterCase(m_gridTex,		tcu::Vec3(0.2f, 0.175f, 0.3f),	tcu::Vec3(-2.0f, -3.7f, -1.825f)));
1068 		m_cases.push_back(FilterCase(m_gridTex,		tcu::Vec3(-0.8f, -2.3f, -2.5f),	tcu::Vec3(0.2f, -0.1f, 1.325f)));
1069 
1070 		m_caseNdx = 0;
1071 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1072 	}
1073 	catch (...)
1074 	{
1075 		// Clean up to save memory.
1076 		Texture3DFilteringCase::deinit();
1077 		throw;
1078 	}
1079 }
1080 
deinit(void)1081 void Texture3DFilteringCase::deinit (void)
1082 {
1083 	delete m_gradientTex;
1084 	delete m_gridTex;
1085 
1086 	m_gradientTex	= DE_NULL;
1087 	m_gridTex		= DE_NULL;
1088 
1089 	m_renderer.clear();
1090 	m_cases.clear();
1091 }
1092 
iterate(void)1093 Texture3DFilteringCase::IterateResult Texture3DFilteringCase::iterate (void)
1094 {
1095 	const glw::Functions&			gl			= m_context.getRenderContext().getFunctions();
1096 	const RandomViewport			viewport	(m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
1097 	const FilterCase&				curCase		= m_cases[m_caseNdx];
1098 	const tcu::TextureFormat		texFmt		= curCase.texture->getRefTexture().getFormat();
1099 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
1100 	const tcu::ScopedLogSection		section		(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
1101 	ReferenceParams					refParams	(TEXTURETYPE_3D);
1102 	tcu::Surface					rendered	(viewport.width, viewport.height);
1103 	tcu::Vec3						texCoord[4];
1104 
1105 	if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT)
1106 		throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
1107 
1108 	// Setup params for reference.
1109 	refParams.sampler		= glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter);
1110 	refParams.samplerType	= getSamplerType(texFmt);
1111 	refParams.lodMode		= LODMODE_EXACT;
1112 	refParams.colorBias		= fmtInfo.lookupBias;
1113 	refParams.colorScale	= fmtInfo.lookupScale;
1114 
1115 	// Compute texture coordinates.
1116 	m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
1117 
1118 	{
1119 		const float	lodX	= curCase.lod.x();
1120 		const float	lodY	= curCase.lod.y();
1121 		const float	lodZ	= curCase.lod.z();
1122 		const float	oX		= curCase.offset.x();
1123 		const float	oY		= curCase.offset.y();
1124 		const float oZ		= curCase.offset.z();
1125 		const float	sX		= deFloatExp2(lodX)*float(viewport.width)							/ float(m_gradientTex->getRefTexture().getWidth());
1126 		const float	sY		= deFloatExp2(lodY)*float(viewport.height)							/ float(m_gradientTex->getRefTexture().getHeight());
1127 		const float	sZ		= deFloatExp2(lodZ)*float(de::max(viewport.width, viewport.height))	/ float(m_gradientTex->getRefTexture().getDepth());
1128 
1129 		texCoord[0] = tcu::Vec3(oX,		oY,		oZ);
1130 		texCoord[1] = tcu::Vec3(oX,		oY+sY,	oZ + sZ*0.5f);
1131 		texCoord[2] = tcu::Vec3(oX+sX,	oY,		oZ + sZ*0.5f);
1132 		texCoord[3] = tcu::Vec3(oX+sX,	oY+sY,	oZ + sZ);
1133 	}
1134 
1135 	gl.bindTexture	(GL_TEXTURE_3D, curCase.texture->getGLTexture());
1136 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1137 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
1138 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,		m_wrapS);
1139 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,		m_wrapT);
1140 	gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,		m_wrapR);
1141 
1142 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
1143 	m_renderer.renderQuad(0, (const float*)&texCoord[0], refParams);
1144 	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
1145 
1146 	{
1147 		const bool				isNearestOnly	= m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
1148 		const tcu::PixelFormat	pixelFormat		= m_context.getRenderTarget().getPixelFormat();
1149 		const tcu::IVec4		colorBits		= max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
1150 		tcu::LodPrecision		lodPrecision;
1151 		tcu::LookupPrecision	lookupPrecision;
1152 
1153 		lodPrecision.derivateBits		= 18;
1154 		lodPrecision.lodBits			= 6;
1155 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
1156 		lookupPrecision.coordBits		= tcu::IVec3(20,20,20);
1157 		lookupPrecision.uvwBits			= tcu::IVec3(7,7,7);
1158 		lookupPrecision.colorMask		= getCompareMask(pixelFormat);
1159 
1160 		const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1161 													   (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1162 
1163 		if (!isHighQuality)
1164 		{
1165 			// Evaluate against lower precision requirements.
1166 			lodPrecision.lodBits	= 4;
1167 			lookupPrecision.uvwBits	= tcu::IVec3(4,4,4);
1168 
1169 			m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
1170 
1171 			const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1172 												  (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1173 
1174 			if (!isOk)
1175 			{
1176 				m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
1177 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1178 			}
1179 			else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1180 				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
1181 		}
1182 	}
1183 
1184 	m_caseNdx += 1;
1185 	return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
1186 }
1187 
TextureFilteringTests(Context & context)1188 TextureFilteringTests::TextureFilteringTests (Context& context)
1189 	: TestCaseGroup(context, "filtering", "Texture Filtering Tests")
1190 {
1191 }
1192 
~TextureFilteringTests(void)1193 TextureFilteringTests::~TextureFilteringTests (void)
1194 {
1195 }
1196 
init(void)1197 void TextureFilteringTests::init (void)
1198 {
1199 	static const struct
1200 	{
1201 		const char*		name;
1202 		deUint32		mode;
1203 	} wrapModes[] =
1204 	{
1205 		{ "clamp",		GL_CLAMP_TO_EDGE },
1206 		{ "repeat",		GL_REPEAT },
1207 		{ "mirror",		GL_MIRRORED_REPEAT }
1208 	};
1209 
1210 	static const struct
1211 	{
1212 		const char*		name;
1213 		deUint32		mode;
1214 	} minFilterModes[] =
1215 	{
1216 		{ "nearest",				GL_NEAREST					},
1217 		{ "linear",					GL_LINEAR					},
1218 		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1219 		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST	},
1220 		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR	},
1221 		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR		}
1222 	};
1223 
1224 	static const struct
1225 	{
1226 		const char*		name;
1227 		deUint32		mode;
1228 	} magFilterModes[] =
1229 	{
1230 		{ "nearest",	GL_NEAREST },
1231 		{ "linear",		GL_LINEAR }
1232 	};
1233 
1234 	static const struct
1235 	{
1236 		int width;
1237 		int height;
1238 	} sizes2D[] =
1239 	{
1240 		{   4,	  8 },
1241 		{  32,	 64 },
1242 		{ 128,	128	},
1243 		{   3,	  7 },
1244 		{  31,	 55 },
1245 		{ 127,	 99 }
1246 	};
1247 
1248 	static const struct
1249 	{
1250 		int width;
1251 		int height;
1252 	} sizesCube[] =
1253 	{
1254 		{   8,   8 },
1255 		{  64,  64 },
1256 		{ 128, 128 },
1257 		{   7,   7 },
1258 		{  63,  63 }
1259 	};
1260 
1261 	static const struct
1262 	{
1263 		int width;
1264 		int height;
1265 		int numLayers;
1266 	} sizes2DArray[] =
1267 	{
1268 		{   4,   8,   8 },
1269 		{  32,  64,  16 },
1270 		{ 128,  32,  64 },
1271 		{   3,   7,   5 },
1272 		{  63,  63,  63 }
1273 	};
1274 
1275 	static const struct
1276 	{
1277 		int width;
1278 		int height;
1279 		int depth;
1280 	} sizes3D[] =
1281 	{
1282 		{   4,   8,   8 },
1283 		{  32,  64,  16 },
1284 		{ 128,  32,  64 },
1285 		{   3,   7,   5 },
1286 		{  63,  63,  63 }
1287 	};
1288 
1289 	static const struct
1290 	{
1291 		const char*		name;
1292 		deUint32		format;
1293 	} filterableFormatsByType[] =
1294 	{
1295 		{ "rgba16f",		GL_RGBA16F			},
1296 		{ "r11f_g11f_b10f",	GL_R11F_G11F_B10F	},
1297 		{ "rgb9_e5",		GL_RGB9_E5			},
1298 		{ "rgba8",			GL_RGBA8			},
1299 		{ "rgba8_snorm",	GL_RGBA8_SNORM		},
1300 		{ "rgb565",			GL_RGB565			},
1301 		{ "rgba4",			GL_RGBA4			},
1302 		{ "rgb5_a1",		GL_RGB5_A1			},
1303 		{ "srgb8_alpha8",	GL_SRGB8_ALPHA8		},
1304 		{ "srgb_r8",		GL_SR8_EXT			},
1305 		{ "srgb_rg8",		GL_SRG8_EXT			},
1306 		{ "rgb10_a2",		GL_RGB10_A2			}
1307 	};
1308 
1309 	// 2D texture filtering.
1310 	{
1311 		tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
1312 		addChild(group2D);
1313 
1314 		// Formats.
1315 		tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats");
1316 		group2D->addChild(formatsGroup);
1317 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1318 		{
1319 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1320 			{
1321 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1322 				const char*		filterName	= minFilterModes[filterNdx].name;
1323 				deUint32		format		= filterableFormatsByType[fmtNdx].format;
1324 				const char*		formatName	= filterableFormatsByType[fmtNdx].name;
1325 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1326 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1327 				string			name		= string(formatName) + "_" + filterName;
1328 				deUint32		wrapS		= GL_REPEAT;
1329 				deUint32		wrapT		= GL_REPEAT;
1330 				int				width		= 64;
1331 				int				height		= 64;
1332 
1333 				formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1334 																  name.c_str(), "",
1335 																  minFilter, magFilter,
1336 																  wrapS, wrapT,
1337 																  format,
1338 																  width, height));
1339 			}
1340 		}
1341 
1342 		// ETC1 format.
1343 		{
1344 			std::vector<std::string> filenames;
1345 			for (int i = 0; i <= 7; i++)
1346 				filenames.push_back(string("data/etc1/photo_helsinki_mip_") + de::toString(i) + ".pkm");
1347 
1348 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1349 			{
1350 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1351 				const char*		filterName	= minFilterModes[filterNdx].name;
1352 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1353 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1354 				string			name		= string("etc1_rgb8_") + filterName;
1355 				deUint32		wrapS		= GL_REPEAT;
1356 				deUint32		wrapT		= GL_REPEAT;
1357 
1358 				formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1359 																  name.c_str(), "",
1360 																  minFilter, magFilter,
1361 																  wrapS, wrapT,
1362 																  filenames));
1363 			}
1364 		}
1365 
1366 		// Sizes.
1367 		tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1368 		group2D->addChild(sizesGroup);
1369 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
1370 		{
1371 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1372 			{
1373 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1374 				const char*		filterName	= minFilterModes[filterNdx].name;
1375 				deUint32		format		= GL_RGBA8;
1376 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1377 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1378 				deUint32		wrapS		= GL_REPEAT;
1379 				deUint32		wrapT		= GL_REPEAT;
1380 				int				width		= sizes2D[sizeNdx].width;
1381 				int				height		= sizes2D[sizeNdx].height;
1382 				string			name		= de::toString(width) + "x" + de::toString(height) + "_" + filterName;
1383 
1384 				sizesGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1385 																name.c_str(), "",
1386 																minFilter, magFilter,
1387 																wrapS, wrapT,
1388 																format,
1389 																width, height));
1390 			}
1391 		}
1392 
1393 		// Wrap modes.
1394 		tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1395 		group2D->addChild(combinationsGroup);
1396 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1397 		{
1398 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1399 			{
1400 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1401 				{
1402 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1403 					{
1404 						deUint32		minFilter	= minFilterModes[minFilterNdx].mode;
1405 						deUint32		magFilter	= magFilterModes[magFilterNdx].mode;
1406 						deUint32		format		= GL_RGBA8;
1407 						deUint32		wrapS		= wrapModes[wrapSNdx].mode;
1408 						deUint32		wrapT		= wrapModes[wrapTNdx].mode;
1409 						int				width		= 63;
1410 						int				height		= 57;
1411 						string			name		= string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1412 
1413 						combinationsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1414 																			   name.c_str(), "",
1415 																			   minFilter, magFilter,
1416 																			   wrapS, wrapT,
1417 																			   format,
1418 																			   width, height));
1419 					}
1420 				}
1421 			}
1422 		}
1423 	}
1424 
1425 	// Cube map texture filtering.
1426 	{
1427 		tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Texture Filtering");
1428 		addChild(groupCube);
1429 
1430 		// Formats.
1431 		tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats");
1432 		groupCube->addChild(formatsGroup);
1433 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1434 		{
1435 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1436 			{
1437 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1438 				const char*		filterName	= minFilterModes[filterNdx].name;
1439 				deUint32		format		= filterableFormatsByType[fmtNdx].format;
1440 				const char*		formatName	= filterableFormatsByType[fmtNdx].name;
1441 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1442 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1443 				string			name		= string(formatName) + "_" + filterName;
1444 				deUint32		wrapS		= GL_REPEAT;
1445 				deUint32		wrapT		= GL_REPEAT;
1446 				int				width		= 64;
1447 				int				height		= 64;
1448 
1449 				formatsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1450 																	name.c_str(), "",
1451 																	minFilter, magFilter,
1452 																	wrapS, wrapT,
1453 																	false /* always sample exterior as well */,
1454 																	format,
1455 																	width, height));
1456 			}
1457 		}
1458 
1459 		// ETC1 format.
1460 		{
1461 			static const char* faceExt[] = { "neg_x", "pos_x", "neg_y", "pos_y", "neg_z", "pos_z" };
1462 
1463 			const int		numLevels	= 7;
1464 			vector<string>	filenames;
1465 			for (int level = 0; level < numLevels; level++)
1466 				for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1467 					filenames.push_back(string("data/etc1/skybox_") + faceExt[face] + "_mip_" + de::toString(level) + ".pkm");
1468 
1469 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1470 			{
1471 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1472 				const char*		filterName	= minFilterModes[filterNdx].name;
1473 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1474 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1475 				string			name		= string("etc1_rgb8_") + filterName;
1476 				deUint32		wrapS		= GL_REPEAT;
1477 				deUint32		wrapT		= GL_REPEAT;
1478 
1479 				formatsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1480 																	name.c_str(), "",
1481 																	minFilter, magFilter,
1482 																	wrapS, wrapT,
1483 																	false /* always sample exterior as well */,
1484 																	filenames));
1485 			}
1486 		}
1487 
1488 		// Sizes.
1489 		tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1490 		groupCube->addChild(sizesGroup);
1491 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
1492 		{
1493 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1494 			{
1495 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1496 				const char*		filterName	= minFilterModes[filterNdx].name;
1497 				deUint32		format		= GL_RGBA8;
1498 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1499 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1500 				deUint32		wrapS		= GL_REPEAT;
1501 				deUint32		wrapT		= GL_REPEAT;
1502 				int				width		= sizesCube[sizeNdx].width;
1503 				int				height		= sizesCube[sizeNdx].height;
1504 				string			name		= de::toString(width) + "x" + de::toString(height) + "_" + filterName;
1505 
1506 				sizesGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1507 																  name.c_str(), "",
1508 																  minFilter, magFilter,
1509 																  wrapS, wrapT,
1510 																  false,
1511 																  format,
1512 																  width, height));
1513 			}
1514 		}
1515 
1516 		// Filter/wrap mode combinations.
1517 		tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1518 		groupCube->addChild(combinationsGroup);
1519 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1520 		{
1521 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1522 			{
1523 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1524 				{
1525 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1526 					{
1527 						deUint32		minFilter	= minFilterModes[minFilterNdx].mode;
1528 						deUint32		magFilter	= magFilterModes[magFilterNdx].mode;
1529 						deUint32		format		= GL_RGBA8;
1530 						deUint32		wrapS		= wrapModes[wrapSNdx].mode;
1531 						deUint32		wrapT		= wrapModes[wrapTNdx].mode;
1532 						int				width		= 63;
1533 						int				height		= 63;
1534 						string			name		= string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1535 
1536 						combinationsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1537 																				 name.c_str(), "",
1538 																				 minFilter, magFilter,
1539 																				 wrapS, wrapT,
1540 																				 false,
1541 																				 format,
1542 																				 width, height));
1543 					}
1544 				}
1545 			}
1546 		}
1547 
1548 		// Cases with no visible cube edges.
1549 		tcu::TestCaseGroup* onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
1550 		groupCube->addChild(onlyFaceInteriorGroup);
1551 
1552 		for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
1553 		{
1554 			bool		isLinear	= isLinearI != 0;
1555 			deUint32	filter		= isLinear ? GL_LINEAR : GL_NEAREST;
1556 
1557 			onlyFaceInteriorGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1558 																		 isLinear ? "linear" : "nearest", "",
1559 																		 filter, filter,
1560 																		 GL_REPEAT, GL_REPEAT,
1561 																		 true,
1562 																		 GL_RGBA8,
1563 																		 63, 63));
1564 		}
1565 	}
1566 
1567 	// 2D array texture filtering.
1568 	{
1569 		tcu::TestCaseGroup* const group2DArray = new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D Array Texture Filtering");
1570 		addChild(group2DArray);
1571 
1572 		// Formats.
1573 		tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Array Texture Formats");
1574 		group2DArray->addChild(formatsGroup);
1575 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1576 		{
1577 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1578 			{
1579 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1580 				const char*		filterName	= minFilterModes[filterNdx].name;
1581 				deUint32		format		= filterableFormatsByType[fmtNdx].format;
1582 				const char*		formatName	= filterableFormatsByType[fmtNdx].name;
1583 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1584 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1585 				string			name		= string(formatName) + "_" + filterName;
1586 				deUint32		wrapS		= GL_REPEAT;
1587 				deUint32		wrapT		= GL_REPEAT;
1588 				int				width		= 128;
1589 				int				height		= 128;
1590 				int				numLayers	= 8;
1591 
1592 				formatsGroup->addChild(new Texture2DArrayFilteringCase(m_context,
1593 																	   name.c_str(), "",
1594 																	   minFilter, magFilter,
1595 																	   wrapS, wrapT,
1596 																	   format,
1597 																	   width, height, numLayers));
1598 			}
1599 		}
1600 
1601 		// Sizes.
1602 		tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1603 		group2DArray->addChild(sizesGroup);
1604 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2DArray); sizeNdx++)
1605 		{
1606 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1607 			{
1608 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1609 				const char*		filterName	= minFilterModes[filterNdx].name;
1610 				deUint32		format		= GL_RGBA8;
1611 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1612 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1613 				deUint32		wrapS		= GL_REPEAT;
1614 				deUint32		wrapT		= GL_REPEAT;
1615 				int				width		= sizes2DArray[sizeNdx].width;
1616 				int				height		= sizes2DArray[sizeNdx].height;
1617 				int				numLayers	= sizes2DArray[sizeNdx].numLayers;
1618 				string			name		= de::toString(width) + "x" + de::toString(height) + "x" + de::toString(numLayers) + "_" + filterName;
1619 
1620 				sizesGroup->addChild(new Texture2DArrayFilteringCase(m_context,
1621 																	 name.c_str(), "",
1622 																	 minFilter, magFilter,
1623 																	 wrapS, wrapT,
1624 																	 format,
1625 																	 width, height, numLayers));
1626 			}
1627 		}
1628 
1629 		// Wrap modes.
1630 		tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1631 		group2DArray->addChild(combinationsGroup);
1632 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1633 		{
1634 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1635 			{
1636 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1637 				{
1638 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1639 					{
1640 						deUint32		minFilter	= minFilterModes[minFilterNdx].mode;
1641 						deUint32		magFilter	= magFilterModes[magFilterNdx].mode;
1642 						deUint32		format		= GL_RGBA8;
1643 						deUint32		wrapS		= wrapModes[wrapSNdx].mode;
1644 						deUint32		wrapT		= wrapModes[wrapTNdx].mode;
1645 						int				width		= 123;
1646 						int				height		= 107;
1647 						int				numLayers	= 7;
1648 						string			name		= string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1649 
1650 						combinationsGroup->addChild(new Texture2DArrayFilteringCase(m_context,
1651 																					name.c_str(), "",
1652 																					minFilter, magFilter,
1653 																					wrapS, wrapT,
1654 																					format,
1655 																					width, height, numLayers));
1656 					}
1657 				}
1658 			}
1659 		}
1660 	}
1661 
1662 	// 3D texture filtering.
1663 	{
1664 		tcu::TestCaseGroup* group3D = new tcu::TestCaseGroup(m_testCtx, "3d", "3D Texture Filtering");
1665 		addChild(group3D);
1666 
1667 		// Formats.
1668 		tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "3D Texture Formats");
1669 		group3D->addChild(formatsGroup);
1670 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1671 		{
1672 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1673 			{
1674 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1675 				const char*		filterName	= minFilterModes[filterNdx].name;
1676 				deUint32		format		= filterableFormatsByType[fmtNdx].format;
1677 				const char*		formatName	= filterableFormatsByType[fmtNdx].name;
1678 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1679 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1680 				string			name		= string(formatName) + "_" + filterName;
1681 				deUint32		wrapS		= GL_REPEAT;
1682 				deUint32		wrapT		= GL_REPEAT;
1683 				deUint32		wrapR		= GL_REPEAT;
1684 				int				width		= 64;
1685 				int				height		= 64;
1686 				int				depth		= 64;
1687 
1688 				formatsGroup->addChild(new Texture3DFilteringCase(m_context,
1689 																  name.c_str(), "",
1690 																  minFilter, magFilter,
1691 																  wrapS, wrapT, wrapR,
1692 																  format,
1693 																  width, height, depth));
1694 			}
1695 		}
1696 
1697 		// Sizes.
1698 		tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1699 		group3D->addChild(sizesGroup);
1700 		for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes3D); sizeNdx++)
1701 		{
1702 			for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1703 			{
1704 				deUint32		minFilter	= minFilterModes[filterNdx].mode;
1705 				const char*		filterName	= minFilterModes[filterNdx].name;
1706 				deUint32		format		= GL_RGBA8;
1707 				bool			isMipmap	= minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1708 				deUint32		magFilter	= isMipmap ? GL_LINEAR : minFilter;
1709 				deUint32		wrapS		= GL_REPEAT;
1710 				deUint32		wrapT		= GL_REPEAT;
1711 				deUint32		wrapR		= GL_REPEAT;
1712 				int				width		= sizes3D[sizeNdx].width;
1713 				int				height		= sizes3D[sizeNdx].height;
1714 				int				depth		= sizes3D[sizeNdx].depth;
1715 				string			name		= de::toString(width) + "x" + de::toString(height) + "x" + de::toString(depth) + "_" + filterName;
1716 
1717 				sizesGroup->addChild(new Texture3DFilteringCase(m_context,
1718 																name.c_str(), "",
1719 																minFilter, magFilter,
1720 																wrapS, wrapT, wrapR,
1721 																format,
1722 																width, height, depth));
1723 			}
1724 		}
1725 
1726 		// Wrap modes.
1727 		tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1728 		group3D->addChild(combinationsGroup);
1729 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1730 		{
1731 			for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1732 			{
1733 				for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1734 				{
1735 					for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1736 					{
1737 						for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++)
1738 						{
1739 							deUint32		minFilter	= minFilterModes[minFilterNdx].mode;
1740 							deUint32		magFilter	= magFilterModes[magFilterNdx].mode;
1741 							deUint32		format		= GL_RGBA8;
1742 							deUint32		wrapS		= wrapModes[wrapSNdx].mode;
1743 							deUint32		wrapT		= wrapModes[wrapTNdx].mode;
1744 							deUint32		wrapR		= wrapModes[wrapRNdx].mode;
1745 							int				width		= 63;
1746 							int				height		= 57;
1747 							int				depth		= 67;
1748 							string			name		= string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name + "_" + wrapModes[wrapRNdx].name;
1749 
1750 							combinationsGroup->addChild(new Texture3DFilteringCase(m_context,
1751 																				   name.c_str(), "",
1752 																				   minFilter, magFilter,
1753 																				   wrapS, wrapT, wrapR,
1754 																				   format,
1755 																				   width, height, depth));
1756 						}
1757 					}
1758 				}
1759 			}
1760 		}
1761 	}
1762 }
1763 
1764 } // Functional
1765 } // gles3
1766 } // deqp
1767