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 Blend tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fBlendTests.hpp"
     25 #include "glsFragmentOpUtil.hpp"
     26 #include "gluPixelTransfer.hpp"
     27 #include "gluStrUtil.hpp"
     28 #include "tcuSurface.hpp"
     29 #include "tcuImageCompare.hpp"
     30 #include "tcuRenderTarget.hpp"
     31 #include "tcuTestLog.hpp"
     32 #include "tcuTextureUtil.hpp"
     33 #include "deRandom.hpp"
     34 #include "rrFragmentOperations.hpp"
     35 #include "sglrReferenceUtils.hpp"
     36 
     37 #include "glw.h"
     38 
     39 #include <string>
     40 #include <vector>
     41 
     42 namespace deqp
     43 {
     44 
     45 using gls::FragmentOpUtil::Quad;
     46 using gls::FragmentOpUtil::IntegerQuad;
     47 using gls::FragmentOpUtil::QuadRenderer;
     48 using gls::FragmentOpUtil::ReferenceQuadRenderer;
     49 using glu::getBlendEquationName;
     50 using glu::getBlendFactorName;
     51 using tcu::Vec4;
     52 using tcu::UVec4;
     53 using tcu::TestLog;
     54 using tcu::Surface;
     55 using tcu::TextureFormat;
     56 using tcu::TextureLevel;
     57 using std::string;
     58 using std::vector;
     59 
     60 namespace gles2
     61 {
     62 namespace Functional
     63 {
     64 
     65 static const int MAX_VIEWPORT_WIDTH		= 64;
     66 static const int MAX_VIEWPORT_HEIGHT	= 64;
     67 
     68 struct BlendParams
     69 {
     70 	GLenum	equationRGB;
     71 	GLenum	srcFuncRGB;
     72 	GLenum	dstFuncRGB;
     73 	GLenum	equationAlpha;
     74 	GLenum	srcFuncAlpha;
     75 	GLenum	dstFuncAlpha;
     76 	Vec4	blendColor;
     77 
     78 	BlendParams (GLenum		equationRGB_,
     79 				 GLenum		srcFuncRGB_,
     80 				 GLenum		dstFuncRGB_,
     81 				 GLenum		equationAlpha_,
     82 				 GLenum		srcFuncAlpha_,
     83 				 GLenum		dstFuncAlpha_,
     84 				 Vec4		blendColor_)
     85 	: equationRGB	(equationRGB_)
     86 	, srcFuncRGB	(srcFuncRGB_)
     87 	, dstFuncRGB	(dstFuncRGB_)
     88 	, equationAlpha	(equationAlpha_)
     89 	, srcFuncAlpha	(srcFuncAlpha_)
     90 	, dstFuncAlpha	(dstFuncAlpha_)
     91 	, blendColor	(blendColor_)
     92 	{
     93 	}
     94 };
     95 
     96 class BlendCase : public TestCase
     97 {
     98 public:
     99 							BlendCase	(Context&						context,
    100 										 const char*					name,
    101 										 const char*					desc,
    102 										 const vector<BlendParams>&		paramSets);
    103 
    104 							~BlendCase	(void);
    105 
    106 	void					init		(void);
    107 	void					deinit		(void);
    108 
    109 	IterateResult			iterate		(void);
    110 
    111 private:
    112 							BlendCase	(const BlendCase& other);
    113 	BlendCase&				operator=	(const BlendCase& other);
    114 
    115 	vector<BlendParams>		m_paramSets;
    116 	int						m_curParamSetNdx;
    117 
    118 	QuadRenderer*			m_renderer;
    119 	ReferenceQuadRenderer*	m_referenceRenderer;
    120 	TextureLevel*			m_refColorBuffer;
    121 	Quad					m_firstQuad;
    122 	Quad					m_secondQuad;
    123 	IntegerQuad				m_firstQuadInt;
    124 	IntegerQuad				m_secondQuadInt;
    125 
    126 	int						m_viewportW;
    127 	int						m_viewportH;
    128 };
    129 
    130 BlendCase::BlendCase (Context&						context,
    131 					  const char*					name,
    132 					  const char*					desc,
    133 					  const vector<BlendParams>&	paramSets)
    134 	: TestCase				(context, name, desc)
    135 	, m_paramSets			(paramSets)
    136 	, m_curParamSetNdx		(0)
    137 	, m_renderer			(DE_NULL)
    138 	, m_referenceRenderer	(DE_NULL)
    139 	, m_refColorBuffer		(DE_NULL)
    140 	, m_viewportW			(0)
    141 	, m_viewportH			(0)
    142 {
    143 	DE_ASSERT(!m_paramSets.empty());
    144 	for (int i = 0; i < (int)m_paramSets.size(); i++)
    145 		DE_ASSERT(m_paramSets[i].dstFuncRGB != GL_SRC_ALPHA_SATURATE && m_paramSets[i].dstFuncAlpha != GL_SRC_ALPHA_SATURATE);
    146 }
    147 
    148 void BlendCase::init (void)
    149 {
    150 	bool useRGB = m_context.getRenderTarget().getPixelFormat().alphaBits == 0;
    151 
    152 	static const Vec4 baseGradientColors[4] =
    153 	{
    154 		Vec4(0.0f, 0.5f, 1.0f, 0.5f),
    155 		Vec4(0.5f, 0.0f, 0.5f, 1.0f),
    156 		Vec4(0.5f, 1.0f, 0.5f, 0.0f),
    157 		Vec4(1.0f, 0.5f, 0.0f, 0.5f)
    158 	};
    159 
    160 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(m_firstQuad.color) == DE_LENGTH_OF_ARRAY(m_firstQuadInt.color));
    161 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_firstQuad.color); i++)
    162 	{
    163 		m_firstQuad.color[i]		= (baseGradientColors[i] - 0.5f) * 0.2f + 0.5f;
    164 		m_firstQuadInt.color[i]		= m_firstQuad.color[i];
    165 
    166 		m_secondQuad.color[i]		= (Vec4(1.0f) - baseGradientColors[i] - 0.5f) * 1.0f + 0.5f;
    167 		m_secondQuadInt.color[i]	= m_secondQuad.color[i];
    168 	}
    169 
    170 	m_viewportW = de::min<int>(m_context.getRenderTarget().getWidth(),	MAX_VIEWPORT_WIDTH);
    171 	m_viewportH = de::min<int>(m_context.getRenderTarget().getHeight(),	MAX_VIEWPORT_HEIGHT);
    172 
    173 	m_firstQuadInt.posA		= tcu::IVec2(0,					0);
    174 	m_secondQuadInt.posA	= tcu::IVec2(0,					0);
    175 	m_firstQuadInt.posB		= tcu::IVec2(m_viewportW-1,		m_viewportH-1);
    176 	m_secondQuadInt.posB	= tcu::IVec2(m_viewportW-1,		m_viewportH-1);
    177 
    178 	DE_ASSERT(!m_renderer);
    179 	DE_ASSERT(!m_referenceRenderer);
    180 	DE_ASSERT(!m_refColorBuffer);
    181 
    182 	m_renderer				= new QuadRenderer(m_context.getRenderContext(), glu::GLSL_VERSION_100_ES);
    183 	m_referenceRenderer		= new ReferenceQuadRenderer;
    184 	m_refColorBuffer		= new TextureLevel(TextureFormat(useRGB ? TextureFormat::RGB : TextureFormat::RGBA, TextureFormat::UNORM_INT8),
    185 											   m_viewportW, m_viewportH);
    186 
    187 	m_curParamSetNdx = 0;
    188 }
    189 
    190 BlendCase::~BlendCase (void)
    191 {
    192 	delete m_renderer;
    193 	delete m_referenceRenderer;
    194 	delete m_refColorBuffer;
    195 }
    196 
    197 void BlendCase::deinit (void)
    198 {
    199 	delete m_renderer;
    200 	delete m_referenceRenderer;
    201 	delete m_refColorBuffer;
    202 
    203 	m_renderer			= DE_NULL;
    204 	m_referenceRenderer	= DE_NULL;
    205 	m_refColorBuffer	= DE_NULL;
    206 }
    207 
    208 BlendCase::IterateResult BlendCase::iterate (void)
    209 {
    210 	de::Random						rnd				(deStringHash(getName()) ^ deInt32Hash(m_curParamSetNdx));
    211 	int								viewportX		= rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportW);
    212 	int								viewportY		= rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportH);
    213 	tcu::Surface					renderedImg		(m_viewportW, m_viewportH);
    214 	tcu::Surface					referenceImg	(m_viewportH, m_viewportH);
    215 	TestLog&						log				(m_testCtx.getLog());
    216 	const BlendParams&				paramSet		= m_paramSets[m_curParamSetNdx];
    217 	rr::FragmentOperationState		referenceState;
    218 
    219 	// Log the blend parameters.
    220 
    221 	log << TestLog::Message << "RGB equation = " << getBlendEquationName(paramSet.equationRGB) << TestLog::EndMessage;
    222 	log << TestLog::Message << "RGB src func = " << getBlendFactorName(paramSet.srcFuncRGB) << TestLog::EndMessage;
    223 	log << TestLog::Message << "RGB dst func = " << getBlendFactorName(paramSet.dstFuncRGB) << TestLog::EndMessage;
    224 	log << TestLog::Message << "Alpha equation = " << getBlendEquationName(paramSet.equationAlpha) << TestLog::EndMessage;
    225 	log << TestLog::Message << "Alpha src func = " << getBlendFactorName(paramSet.srcFuncAlpha) << TestLog::EndMessage;
    226 	log << TestLog::Message << "Alpha dst func = " << getBlendFactorName(paramSet.dstFuncAlpha) << TestLog::EndMessage;
    227 	log << TestLog::Message << "Blend color = (" << paramSet.blendColor.x() << ", " << paramSet.blendColor.y() << ", " << paramSet.blendColor.z() << ", " << paramSet.blendColor.w() << ")" << TestLog::EndMessage;
    228 
    229 	// Set GL state.
    230 
    231 	GLU_CHECK_CALL(glBlendEquationSeparate(paramSet.equationRGB, paramSet.equationAlpha));
    232 	GLU_CHECK_CALL(glBlendFuncSeparate(paramSet.srcFuncRGB, paramSet.dstFuncRGB, paramSet.srcFuncAlpha, paramSet.dstFuncAlpha));
    233 	GLU_CHECK_CALL(glBlendColor(paramSet.blendColor.x(), paramSet.blendColor.y(), paramSet.blendColor.z(), paramSet.blendColor.w()));
    234 
    235 	// Set reference state.
    236 
    237 	referenceState.blendRGBState.equation	= sglr::rr_util::mapGLBlendEquation(paramSet.equationRGB);
    238 	referenceState.blendRGBState.srcFunc	= sglr::rr_util::mapGLBlendFunc(paramSet.srcFuncRGB);
    239 	referenceState.blendRGBState.dstFunc	= sglr::rr_util::mapGLBlendFunc(paramSet.dstFuncRGB);
    240 	referenceState.blendAState.equation		= sglr::rr_util::mapGLBlendEquation(paramSet.equationAlpha);
    241 	referenceState.blendAState.srcFunc		= sglr::rr_util::mapGLBlendFunc(paramSet.srcFuncAlpha);
    242 	referenceState.blendAState.dstFunc		= sglr::rr_util::mapGLBlendFunc(paramSet.dstFuncAlpha);
    243 	referenceState.blendColor				= paramSet.blendColor;
    244 
    245 	// Render with GL.
    246 
    247 	glDisable(GL_BLEND);
    248 	glViewport(viewportX, viewportY, m_viewportW, m_viewportH);
    249 	m_renderer->render(m_firstQuad);
    250 	glEnable(GL_BLEND);
    251 	m_renderer->render(m_secondQuad);
    252 	glFlush();
    253 
    254 	// Render reference.
    255 
    256 	const tcu::PixelBufferAccess nullAccess = tcu::PixelBufferAccess();
    257 
    258 	referenceState.blendMode = rr::BLENDMODE_NONE;
    259 	m_referenceRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()), nullAccess /* no depth */, nullAccess /* no stencil */, m_firstQuadInt, referenceState);
    260 	referenceState.blendMode = rr::BLENDMODE_STANDARD;
    261 	m_referenceRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()), nullAccess /* no depth */, nullAccess /* no stencil */, m_secondQuadInt, referenceState);
    262 
    263 	// Expand reference color buffer to RGBA8
    264 	copy(referenceImg.getAccess(), m_refColorBuffer->getAccess());
    265 
    266 	// Read GL image.
    267 
    268 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
    269 
    270 	// Compare images.
    271 
    272 	UVec4 compareThreshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().asUint()
    273 							 * UVec4(5) / UVec4(2) + UVec4(3); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy.
    274 
    275 	bool comparePass = tcu::intThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", referenceImg.getAccess(), renderedImg.getAccess(), compareThreshold, tcu::COMPARE_LOG_RESULT);
    276 
    277 	// Fail now if images don't match.
    278 
    279 	if (!comparePass)
    280 	{
    281 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
    282 		return STOP;
    283 	}
    284 
    285 	// Continue if param sets still remain in m_paramSets; otherwise stop.
    286 
    287 	m_curParamSetNdx++;
    288 
    289 	if (m_curParamSetNdx < (int)m_paramSets.size())
    290 		return CONTINUE;
    291 	else
    292 	{
    293 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
    294 		return STOP;
    295 	}
    296 }
    297 
    298 BlendTests::BlendTests (Context& context)
    299 	: TestCaseGroup(context, "blend", "Blend tests")
    300 {
    301 }
    302 
    303 BlendTests::~BlendTests (void)
    304 {
    305 }
    306 
    307 void BlendTests::init (void)
    308 {
    309 	struct EnumGL
    310 	{
    311 		GLenum			glValue;
    312 		const char*		nameStr;
    313 	};
    314 
    315 	static const EnumGL blendEquations[] =
    316 	{
    317 		{ GL_FUNC_ADD,					"add"					},
    318 		{ GL_FUNC_SUBTRACT,				"subtract"				},
    319 		{ GL_FUNC_REVERSE_SUBTRACT,		"reverse_subtract"		}
    320 	};
    321 
    322 	static const EnumGL blendFunctions[] =
    323 	{
    324 		{ GL_ZERO,							"zero"						},
    325 		{ GL_ONE,							"one"						},
    326 		{ GL_SRC_COLOR,						"src_color"					},
    327 		{ GL_ONE_MINUS_SRC_COLOR,			"one_minus_src_color"		},
    328 		{ GL_DST_COLOR,						"dst_color"					},
    329 		{ GL_ONE_MINUS_DST_COLOR,			"one_minus_dst_color"		},
    330 		{ GL_SRC_ALPHA,						"src_alpha"					},
    331 		{ GL_ONE_MINUS_SRC_ALPHA,			"one_minus_src_alpha"		},
    332 		{ GL_DST_ALPHA,						"dst_alpha"					},
    333 		{ GL_ONE_MINUS_DST_ALPHA,			"one_minus_dst_alpha"		},
    334 		{ GL_CONSTANT_COLOR,				"constant_color"			},
    335 		{ GL_ONE_MINUS_CONSTANT_COLOR,		"one_minus_constant_color"	},
    336 		{ GL_CONSTANT_ALPHA,				"constant_alpha"			},
    337 		{ GL_ONE_MINUS_CONSTANT_ALPHA,		"one_minus_constant_alpha"	},
    338 		{ GL_SRC_ALPHA_SATURATE,			"src_alpha_saturate"		}
    339 	};
    340 
    341 	const Vec4 defaultBlendColor(0.2f, 0.4f, 0.6f, 0.8f);
    342 
    343 	// Test all blend equation, src blend function, dst blend function combinations. RGB and alpha modes are the same.
    344 
    345 	{
    346 		TestCaseGroup* group = new TestCaseGroup(m_context, "equation_src_func_dst_func", "Combinations of Blend Equations and Functions");
    347 		addChild(group);
    348 
    349 		for (int equationNdx = 0;	equationNdx < DE_LENGTH_OF_ARRAY(blendEquations);	equationNdx++)
    350 		for (int srcFuncNdx = 0;	srcFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	srcFuncNdx++)
    351 		for (int dstFuncNdx = 0;	dstFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	dstFuncNdx++)
    352 		{
    353 			const EnumGL& eq	= blendEquations[equationNdx];
    354 			const EnumGL& src	= blendFunctions[srcFuncNdx];
    355 			const EnumGL& dst	= blendFunctions[dstFuncNdx];
    356 
    357 			if (dst.glValue == GL_SRC_ALPHA_SATURATE) // SRC_ALPHA_SATURATE is only valid for src func.
    358 				continue;
    359 
    360 			string name			= string("") + eq.nameStr + "_" + src.nameStr + "_" + dst.nameStr;
    361 			string description	= string("") +
    362 								  "Equations "		+ getBlendEquationName(eq.glValue) +
    363 								  ", src funcs "	+ getBlendFactorName(src.glValue) +
    364 								  ", dst funcs "	+ getBlendFactorName(dst.glValue);
    365 
    366 			vector<BlendParams> paramSets;
    367 			paramSets.push_back(BlendParams(eq.glValue, src.glValue, dst.glValue, eq.glValue, src.glValue, dst.glValue, defaultBlendColor));
    368 
    369 			group->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
    370 		}
    371 	}
    372 
    373 	// Test all RGB src, alpha src and RGB dst, alpha dst combinations. Equations are ADD.
    374 	// \note For all RGB src, alpha src combinations, also test a couple of different RGBA dst functions, and vice versa.
    375 
    376 	{
    377 		TestCaseGroup* mainGroup = new TestCaseGroup(m_context, "rgb_func_alpha_func", "Combinations of RGB and Alpha Functions");
    378 		addChild(mainGroup);
    379 		TestCaseGroup* srcGroup = new TestCaseGroup(m_context, "src", "Source functions");
    380 		TestCaseGroup* dstGroup = new TestCaseGroup(m_context, "dst", "Destination functions");
    381 		mainGroup->addChild(srcGroup);
    382 		mainGroup->addChild(dstGroup);
    383 
    384 		for (int isDstI = 0;		isDstI <= 1;										isDstI++)
    385 		for (int rgbFuncNdx = 0;	rgbFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	rgbFuncNdx++)
    386 		for (int alphaFuncNdx = 0;	alphaFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	alphaFuncNdx++)
    387 		{
    388 			bool			isSrc			= isDstI == 0;
    389 			TestCaseGroup*	curGroup		= isSrc ? srcGroup : dstGroup;
    390 			const EnumGL&	funcRGB			= blendFunctions[rgbFuncNdx];
    391 			const EnumGL&	funcAlpha		= blendFunctions[alphaFuncNdx];
    392 			const char*		dstOrSrcStr		= isSrc ? "src" : "dst";
    393 
    394 			if (!isSrc && (funcRGB.glValue == GL_SRC_ALPHA_SATURATE || funcAlpha.glValue == GL_SRC_ALPHA_SATURATE)) // SRC_ALPHA_SATURATE is only valid for src func.
    395 				continue;
    396 
    397 			string name			= string("") + funcRGB.nameStr + "_" + funcAlpha.nameStr;
    398 			string description	= string("") +
    399 								  "RGB "		+ dstOrSrcStr + " func " + getBlendFactorName(funcRGB.glValue) +
    400 								  ", alpha "	+ dstOrSrcStr + " func " + getBlendFactorName(funcAlpha.glValue);
    401 
    402 			// First, make param sets as if this was a src case.
    403 
    404 			vector<BlendParams> paramSets;
    405 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_ONE,			GL_FUNC_ADD, funcAlpha.glValue, GL_ONE,			defaultBlendColor));
    406 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_ZERO,			GL_FUNC_ADD, funcAlpha.glValue, GL_ZERO,		defaultBlendColor));
    407 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_SRC_COLOR,		GL_FUNC_ADD, funcAlpha.glValue, GL_SRC_COLOR,	defaultBlendColor));
    408 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_DST_COLOR,		GL_FUNC_ADD, funcAlpha.glValue, GL_DST_COLOR,	defaultBlendColor));
    409 
    410 			// Swap src and dst params if this is a dst case.
    411 
    412 			if (!isSrc)
    413 			{
    414 				for (int i = 0; i < (int)paramSets.size(); i++)
    415 				{
    416 					std::swap(paramSets[i].srcFuncRGB,		paramSets[i].dstFuncRGB);
    417 					std::swap(paramSets[i].srcFuncAlpha,	paramSets[i].dstFuncAlpha);
    418 				}
    419 			}
    420 
    421 			curGroup->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
    422 		}
    423 	}
    424 
    425 	// Test all RGB and alpha equation combinations. Src and dst funcs are ONE for both.
    426 
    427 	{
    428 		TestCaseGroup* group = new TestCaseGroup(m_context, "rgb_equation_alpha_equation", "Combinations of RGB and Alpha Equation Combinations");
    429 		addChild(group);
    430 
    431 		for (int equationRGBNdx = 0;	equationRGBNdx < DE_LENGTH_OF_ARRAY(blendEquations);	equationRGBNdx++)
    432 		for (int equationAlphaNdx = 0;	equationAlphaNdx < DE_LENGTH_OF_ARRAY(blendEquations);	equationAlphaNdx++)
    433 		{
    434 			const EnumGL& eqRGB			= blendEquations[equationRGBNdx];
    435 			const EnumGL& eqAlpha		= blendEquations[equationAlphaNdx];
    436 
    437 			string name			= string("") + eqRGB.nameStr + "_" + eqAlpha.nameStr;
    438 			string description	= string("") +
    439 								  "RGB equation "		+ getBlendEquationName(eqRGB.glValue) +
    440 								  ", alpha equation "	+ getBlendEquationName(eqAlpha.glValue);
    441 
    442 			vector<BlendParams> paramSets;
    443 			paramSets.push_back(BlendParams(eqRGB.glValue, GL_ONE, GL_ONE, eqAlpha.glValue, GL_ONE, GL_ONE, defaultBlendColor));
    444 
    445 			group->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
    446 		}
    447 	}
    448 }
    449 
    450 } // Functional
    451 } // gles2
    452 } // deqp
    453