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
38using std::string;
39
40namespace deqp
41{
42namespace gles2
43{
44namespace Accuracy
45{
46
47using tcu::TestLog;
48using std::vector;
49using std::string;
50using tcu::Sampler;
51using namespace glu;
52using namespace gls::TextureTestUtil;
53using namespace glu::TextureTestUtil;
54
55class Texture2DFilteringCase : public tcu::TestCase
56{
57public:
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
66private:
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
90Texture2DFilteringCase::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
106Texture2DFilteringCase::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
123Texture2DFilteringCase::~Texture2DFilteringCase (void)
124{
125	deinit();
126}
127
128void 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
185void 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
194Texture2DFilteringCase::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
316class TextureCubeFilteringCase : public tcu::TestCase
317{
318public:
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
327private:
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
351TextureCubeFilteringCase::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
367TextureCubeFilteringCase::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
384TextureCubeFilteringCase::~TextureCubeFilteringCase (void)
385{
386	deinit();
387}
388
389void 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
458void 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
467static 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
517TextureCubeFilteringCase::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
628TextureFilteringTests::TextureFilteringTests (Context& context)
629	: TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
630{
631}
632
633TextureFilteringTests::~TextureFilteringTests (void)
634{
635}
636
637void 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