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