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