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