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
43namespace deqp
44{
45
46using gls::FragmentOpUtil::Quad;
47using gls::FragmentOpUtil::IntegerQuad;
48using gls::FragmentOpUtil::QuadRenderer;
49using gls::FragmentOpUtil::ReferenceQuadRenderer;
50using glu::getBlendEquationName;
51using glu::getBlendFactorName;
52using tcu::Vec4;
53using tcu::UVec4;
54using tcu::TestLog;
55using tcu::TextureLevel;
56using tcu::TextureFormat;
57using std::string;
58using std::vector;
59
60namespace gles3
61{
62namespace Functional
63{
64
65static const int MAX_VIEWPORT_WIDTH		= 64;
66static const int MAX_VIEWPORT_HEIGHT	= 64;
67
68static 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
84struct 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
112class BlendCase : public TestCase
113{
114public:
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
128private:
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
153BlendCase::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
175void 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
230BlendCase::~BlendCase (void)
231{
232	BlendCase::deinit();
233}
234
235void 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
260BlendCase::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
350BlendTests::BlendTests (Context& context)
351	: TestCaseGroup(context, "blend", "Blend tests")
352{
353}
354
355BlendTests::~BlendTests (void)
356{
357}
358
359void 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