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 size tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2fTextureSizeTests.hpp"
25#include "glsTextureTestUtil.hpp"
26#include "gluTexture.hpp"
27#include "gluStrUtil.hpp"
28#include "gluTextureUtil.hpp"
29#include "gluPixelTransfer.hpp"
30#include "tcuTestLog.hpp"
31#include "tcuTextureUtil.hpp"
32
33#include "glwEnums.hpp"
34#include "glwFunctions.hpp"
35
36namespace deqp
37{
38namespace gles2
39{
40namespace Functional
41{
42
43using tcu::TestLog;
44using std::vector;
45using std::string;
46using tcu::Sampler;
47using namespace glu;
48using namespace gls::TextureTestUtil;
49using namespace glu::TextureTestUtil;
50
51class Texture2DSizeCase : public tcu::TestCase
52{
53public:
54							Texture2DSizeCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps);
55							~Texture2DSizeCase		(void);
56
57	void					init					(void);
58	void					deinit					(void);
59	IterateResult			iterate					(void);
60
61private:
62							Texture2DSizeCase		(const Texture2DSizeCase& other);
63	Texture2DSizeCase&		operator=				(const Texture2DSizeCase& other);
64
65	glu::RenderContext&		m_renderCtx;
66
67	deUint32				m_format;
68	deUint32				m_dataType;
69	int						m_width;
70	int						m_height;
71	bool					m_useMipmaps;
72
73	glu::Texture2D*			m_texture;
74	TextureRenderer			m_renderer;
75};
76
77Texture2DSizeCase::Texture2DSizeCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps)
78	: TestCase		(testCtx, name, description)
79	, m_renderCtx	(renderCtx)
80	, m_format		(format)
81	, m_dataType	(dataType)
82	, m_width		(width)
83	, m_height		(height)
84	, m_useMipmaps	(mipmaps)
85	, m_texture		(DE_NULL)
86	, m_renderer	(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
87{
88}
89
90Texture2DSizeCase::~Texture2DSizeCase (void)
91{
92	Texture2DSizeCase::deinit();
93}
94
95void Texture2DSizeCase::init (void)
96{
97	DE_ASSERT(!m_texture);
98	m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
99
100	int numLevels = m_useMipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1;
101
102	// Fill levels.
103	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
104	{
105		m_texture->getRefTexture().allocLevel(levelNdx);
106		tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(levelNdx), tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
107	}
108}
109
110void Texture2DSizeCase::deinit (void)
111{
112	delete m_texture;
113	m_texture = DE_NULL;
114
115	m_renderer.clear();
116}
117
118Texture2DSizeCase::IterateResult Texture2DSizeCase::iterate (void)
119{
120	const glw::Functions&	gl				= m_renderCtx.getFunctions();
121	TestLog&				log				= m_testCtx.getLog();
122	RandomViewport			viewport		(m_renderCtx.getRenderTarget(), 128, 128, deStringHash(getName()));
123	tcu::Surface			renderedFrame	(viewport.width, viewport.height);
124	tcu::Surface			referenceFrame	(viewport.width, viewport.height);
125	tcu::RGBA				threshold		= m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7);
126	deUint32				wrapS			= GL_CLAMP_TO_EDGE;
127	deUint32				wrapT			= GL_CLAMP_TO_EDGE;
128	deUint32				minFilter		= m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
129	deUint32				magFilter		= GL_NEAREST;
130	vector<float>			texCoord;
131
132	computeQuadTexCoord2D(texCoord, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f));
133
134	// Setup base viewport.
135	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
136
137	// Upload texture data to GL.
138	m_texture->upload();
139
140	// Bind to unit 0.
141	gl.activeTexture(GL_TEXTURE0);
142	gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
143
144	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		wrapS);
145	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		wrapT);
146	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	minFilter);
147	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	magFilter);
148	GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
149
150	// Draw.
151	m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
152	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
153
154	// Compute reference.
155	sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat()), m_texture->getRefTexture(), &texCoord[0], ReferenceParams(TEXTURETYPE_2D, mapGLSampler(wrapS, wrapT, minFilter, magFilter)));
156
157	// Compare and log.
158	bool isOk = compareImages(log, referenceFrame, renderedFrame, threshold);
159
160	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
161							isOk ? "Pass"				: "Image comparison failed");
162
163	return STOP;
164}
165
166class TextureCubeSizeCase : public tcu::TestCase
167{
168public:
169							TextureCubeSizeCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps);
170							~TextureCubeSizeCase	(void);
171
172	void					init					(void);
173	void					deinit					(void);
174	IterateResult			iterate					(void);
175
176private:
177							TextureCubeSizeCase		(const TextureCubeSizeCase& other);
178	TextureCubeSizeCase&	operator=				(const TextureCubeSizeCase& other);
179
180	bool					testFace				(tcu::CubeFace face);
181
182	glu::RenderContext&		m_renderCtx;
183
184	deUint32				m_format;
185	deUint32				m_dataType;
186	int						m_width;
187	int						m_height;
188	bool					m_useMipmaps;
189
190	glu::TextureCube*		m_texture;
191	TextureRenderer			m_renderer;
192
193	int						m_curFace;
194	bool					m_isOk;
195};
196
197TextureCubeSizeCase::TextureCubeSizeCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, deUint32 format, deUint32 dataType, int width, int height, bool mipmaps)
198	: TestCase		(testCtx, name, description)
199	, m_renderCtx	(renderCtx)
200	, m_format		(format)
201	, m_dataType	(dataType)
202	, m_width		(width)
203	, m_height		(height)
204	, m_useMipmaps	(mipmaps)
205	, m_texture		(DE_NULL)
206	, m_renderer	(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
207	, m_curFace		(0)
208	, m_isOk		(false)
209{
210}
211
212TextureCubeSizeCase::~TextureCubeSizeCase (void)
213{
214	TextureCubeSizeCase::deinit();
215}
216
217void TextureCubeSizeCase::init (void)
218{
219	DE_ASSERT(!m_texture);
220	DE_ASSERT(m_width == m_height);
221	m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_width);
222
223	static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
224	{
225		{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
226		{ tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
227		{ tcu::Vec4(-1.0f,  0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
228		{ tcu::Vec4(-1.0f, -1.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
229		{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
230		{ tcu::Vec4( 0.0f,  0.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
231	};
232
233	int numLevels = m_useMipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1;
234
235	// Fill levels.
236	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
237	{
238		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
239		{
240			m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
241			fillWithComponentGradients(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0], gradients[face][1]);
242		}
243	}
244
245	// Upload texture data to GL.
246	m_texture->upload();
247
248	// Initialize iteration state.
249	m_curFace	= 0;
250	m_isOk		= true;
251}
252
253void TextureCubeSizeCase::deinit (void)
254{
255	delete m_texture;
256	m_texture = DE_NULL;
257
258	m_renderer.clear();
259}
260
261bool TextureCubeSizeCase::testFace (tcu::CubeFace face)
262{
263	const glw::Functions&	gl				= m_renderCtx.getFunctions();
264	TestLog&				log				= m_testCtx.getLog();
265	RandomViewport			viewport		(m_renderCtx.getRenderTarget(), 128, 128, deStringHash(getName())+(deUint32)face);
266	tcu::Surface			renderedFrame	(viewport.width, viewport.height);
267	tcu::Surface			referenceFrame	(viewport.width, viewport.height);
268	tcu::RGBA				threshold		= m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7);
269	deUint32				wrapS			= GL_CLAMP_TO_EDGE;
270	deUint32				wrapT			= GL_CLAMP_TO_EDGE;
271	deUint32				minFilter		= m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
272	deUint32				magFilter		= GL_NEAREST;
273	vector<float>			texCoord;
274
275	computeQuadTexCoordCube(texCoord, face);
276
277	// \todo [2011-10-28 pyry] Image set name / section?
278	log << TestLog::Message << face << TestLog::EndMessage;
279
280	// Setup base viewport.
281	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
282
283	// Bind to unit 0.
284	gl.activeTexture(GL_TEXTURE0);
285	gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
286
287	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, wrapS);
288	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, wrapT);
289	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, minFilter);
290	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, magFilter);
291	GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
292
293	m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
294	glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
295
296	// Compute reference.
297	Sampler sampler = mapGLSampler(wrapS, wrapT, minFilter, magFilter);
298	sampler.seamlessCubeMap = false;
299	sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat()), m_texture->getRefTexture(), &texCoord[0], ReferenceParams(TEXTURETYPE_CUBE, sampler));
300
301	// Compare and log.
302	return compareImages(log, referenceFrame, renderedFrame, threshold);
303}
304
305TextureCubeSizeCase::IterateResult TextureCubeSizeCase::iterate (void)
306{
307	// Execute test for all faces.
308	if (!testFace((tcu::CubeFace)m_curFace))
309		m_isOk = false;
310
311	m_curFace += 1;
312
313	if (m_curFace == tcu::CUBEFACE_LAST)
314	{
315		m_testCtx.setTestResult(m_isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
316								m_isOk ? "Pass"					: "Image comparison failed");
317		return STOP;
318	}
319	else
320		return CONTINUE;
321}
322
323TextureSizeTests::TextureSizeTests (Context& context)
324	: TestCaseGroup(context, "size", "Texture Size Tests")
325{
326}
327
328TextureSizeTests::~TextureSizeTests (void)
329{
330}
331
332void TextureSizeTests::init (void)
333{
334	struct
335	{
336		int	width;
337		int	height;
338	} sizes2D[] =
339	{
340		{   64,   64 }, // Spec-mandated minimum.
341		{   65,   63 },
342		{  512,  512 },
343		{ 1024, 1024 },
344		{ 2048, 2048 }
345	};
346
347	struct
348	{
349		int	width;
350		int	height;
351	} sizesCube[] =
352	{
353		{  15,  15 },
354		{  16,  16 }, // Spec-mandated minimum
355		{  64,  64 },
356		{ 128, 128 },
357		{ 256, 256 },
358		{ 512, 512 }
359	};
360
361	struct
362	{
363		const char*	name;
364		deUint32	format;
365		deUint32	dataType;
366	} formats[] =
367	{
368		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
369		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
370		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
371		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
372	};
373
374	// 2D cases.
375	tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Size Tests");
376	addChild(group2D);
377	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
378	{
379		int		width	= sizes2D[sizeNdx].width;
380		int		height	= sizes2D[sizeNdx].height;
381		bool	isPOT	= deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height);
382
383		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
384		{
385			for (int mipmap = 0; mipmap < (isPOT ? 2 : 1); mipmap++)
386			{
387				std::ostringstream name;
388				name << width << "x" << height << "_" << formats[formatNdx].name << (mipmap ? "_mipmap" : "");
389
390				group2D->addChild(new Texture2DSizeCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
391														formats[formatNdx].format, formats[formatNdx].dataType,
392														width, height, mipmap != 0));
393			}
394		}
395	}
396
397	// Cubemap cases.
398	tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cubemap Texture Size Tests");
399	addChild(groupCube);
400	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
401	{
402		int		width	= sizesCube[sizeNdx].width;
403		int		height	= sizesCube[sizeNdx].height;
404		bool	isPOT	= deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height);
405
406		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
407		{
408			for (int mipmap = 0; mipmap < (isPOT ? 2 : 1); mipmap++)
409			{
410				std::ostringstream name;
411				name << width << "x" << height << "_" << formats[formatNdx].name << (mipmap ? "_mipmap" : "");
412
413				groupCube->addChild(new TextureCubeSizeCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
414															formats[formatNdx].format, formats[formatNdx].dataType,
415															width, height, mipmap != 0));
416			}
417		}
418	}
419}
420
421} // Functional
422} // gles2
423} // deqp
424