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