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