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