1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Texture size tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fTextureSizeTests.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 
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42 
43 using tcu::TestLog;
44 using std::vector;
45 using std::string;
46 using tcu::Sampler;
47 using namespace glu;
48 using namespace gls::TextureTestUtil;
49 
50 class Texture2DSizeCase : public tcu::TestCase
51 {
52 public:
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 
60 private:
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 
Texture2DSizeCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,deUint32 format,deUint32 dataType,int width,int height,bool mipmaps)76 Texture2DSizeCase::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.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_MEDIUMP)
86 {
87 }
88 
~Texture2DSizeCase(void)89 Texture2DSizeCase::~Texture2DSizeCase (void)
90 {
91 	Texture2DSizeCase::deinit();
92 }
93 
init(void)94 void 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 
deinit(void)109 void Texture2DSizeCase::deinit (void)
110 {
111 	delete m_texture;
112 	m_texture = DE_NULL;
113 
114 	m_renderer.clear();
115 }
116 
iterate(void)117 Texture2DSizeCase::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 
165 class TextureCubeSizeCase : public tcu::TestCase
166 {
167 public:
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 
175 private:
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 
TextureCubeSizeCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,deUint32 format,deUint32 dataType,int width,int height,bool mipmaps)196 TextureCubeSizeCase::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.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_MEDIUMP)
206 	, m_curFace		(0)
207 	, m_isOk		(false)
208 {
209 }
210 
~TextureCubeSizeCase(void)211 TextureCubeSizeCase::~TextureCubeSizeCase (void)
212 {
213 	TextureCubeSizeCase::deinit();
214 }
215 
init(void)216 void 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 
deinit(void)252 void TextureCubeSizeCase::deinit (void)
253 {
254 	delete m_texture;
255 	m_texture = DE_NULL;
256 
257 	m_renderer.clear();
258 }
259 
testFace(tcu::CubeFace face)260 bool 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 = true;
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 
iterate(void)304 TextureCubeSizeCase::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 
TextureSizeTests(Context & context)322 TextureSizeTests::TextureSizeTests (Context& context)
323 	: TestCaseGroup(context, "size", "Texture Size Tests")
324 {
325 }
326 
~TextureSizeTests(void)327 TextureSizeTests::~TextureSizeTests (void)
328 {
329 }
330 
init(void)331 void 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 } // gles3
422 } // deqp
423