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