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 Advanced blending (GL_KHR_blend_equation_advanced) tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fAdvancedBlendTests.hpp" 25 #include "gluStrUtil.hpp" 26 #include "glsFragmentOpUtil.hpp" 27 #include "glsStateQueryUtil.hpp" 28 #include "gluPixelTransfer.hpp" 29 #include "gluObjectWrapper.hpp" 30 #include "gluContextInfo.hpp" 31 #include "gluShaderProgram.hpp" 32 #include "gluCallLogWrapper.hpp" 33 #include "gluStrUtil.hpp" 34 #include "tcuPixelFormat.hpp" 35 #include "tcuTexture.hpp" 36 #include "tcuTextureUtil.hpp" 37 #include "tcuImageCompare.hpp" 38 #include "tcuRenderTarget.hpp" 39 #include "tcuTestLog.hpp" 40 #include "tcuStringTemplate.hpp" 41 #include "deRandom.hpp" 42 #include "deStringUtil.hpp" 43 #include "rrFragmentOperations.hpp" 44 #include "sglrReferenceUtils.hpp" 45 #include "glwEnums.hpp" 46 #include "glwFunctions.hpp" 47 48 #include <string> 49 #include <vector> 50 51 namespace deqp 52 { 53 54 using gls::FragmentOpUtil::IntegerQuad; 55 using gls::FragmentOpUtil::ReferenceQuadRenderer; 56 using tcu::TextureLevel; 57 using tcu::Vec2; 58 using tcu::Vec4; 59 using tcu::UVec4; 60 using tcu::TestLog; 61 using tcu::TextureFormat; 62 using std::string; 63 using std::vector; 64 using std::map; 65 66 namespace gles31 67 { 68 namespace Functional 69 { 70 71 namespace 72 { 73 74 enum 75 { 76 MAX_VIEWPORT_WIDTH = 128, 77 MAX_VIEWPORT_HEIGHT = 128 78 }; 79 80 enum RenderTargetType 81 { 82 RENDERTARGETTYPE_DEFAULT = 0, //!< Default framebuffer 83 RENDERTARGETTYPE_SRGB_FBO, 84 RENDERTARGETTYPE_MSAA_FBO, 85 86 RENDERTARGETTYPE_LAST 87 }; 88 89 static const char* getEquationName (glw::GLenum equation) 90 { 91 switch (equation) 92 { 93 case GL_MULTIPLY: return "multiply"; 94 case GL_SCREEN: return "screen"; 95 case GL_OVERLAY: return "overlay"; 96 case GL_DARKEN: return "darken"; 97 case GL_LIGHTEN: return "lighten"; 98 case GL_COLORDODGE: return "colordodge"; 99 case GL_COLORBURN: return "colorburn"; 100 case GL_HARDLIGHT: return "hardlight"; 101 case GL_SOFTLIGHT: return "softlight"; 102 case GL_DIFFERENCE: return "difference"; 103 case GL_EXCLUSION: return "exclusion"; 104 case GL_HSL_HUE: return "hsl_hue"; 105 case GL_HSL_SATURATION: return "hsl_saturation"; 106 case GL_HSL_COLOR: return "hsl_color"; 107 case GL_HSL_LUMINOSITY: return "hsl_luminosity"; 108 default: 109 DE_ASSERT(false); 110 return DE_NULL; 111 } 112 } 113 114 class AdvancedBlendCase : public TestCase 115 { 116 public: 117 AdvancedBlendCase (Context& context, const char* name, const char* desc, deUint32 mode, int overdrawCount, bool coherent, RenderTargetType rtType); 118 119 ~AdvancedBlendCase (void); 120 121 void init (void); 122 void deinit (void); 123 124 IterateResult iterate (void); 125 126 private: 127 AdvancedBlendCase (const AdvancedBlendCase&); 128 AdvancedBlendCase& operator= (const AdvancedBlendCase&); 129 130 const deUint32 m_blendMode; 131 const int m_overdrawCount; 132 const bool m_coherentBlending; 133 const RenderTargetType m_rtType; 134 const int m_numIters; 135 136 bool m_coherentExtensionSupported; 137 138 deUint32 m_colorRbo; 139 deUint32 m_fbo; 140 141 deUint32 m_resolveColorRbo; 142 deUint32 m_resolveFbo; 143 144 glu::ShaderProgram* m_program; 145 146 ReferenceQuadRenderer* m_referenceRenderer; 147 TextureLevel* m_refColorBuffer; 148 149 const int m_renderWidth; 150 const int m_renderHeight; 151 const int m_viewportWidth; 152 const int m_viewportHeight; 153 154 int m_iterNdx; 155 }; 156 157 AdvancedBlendCase::AdvancedBlendCase (Context& context, 158 const char* name, 159 const char* desc, 160 deUint32 mode, 161 int overdrawCount, 162 bool coherent, 163 RenderTargetType rtType) 164 : TestCase (context, name, desc) 165 , m_blendMode (mode) 166 , m_overdrawCount (overdrawCount) 167 , m_coherentBlending (coherent) 168 , m_rtType (rtType) 169 , m_numIters (5) 170 , m_colorRbo (0) 171 , m_fbo (0) 172 , m_resolveColorRbo (0) 173 , m_resolveFbo (0) 174 , m_program (DE_NULL) 175 , m_referenceRenderer (DE_NULL) 176 , m_refColorBuffer (DE_NULL) 177 , m_renderWidth (rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_WIDTH : m_context.getRenderTarget().getWidth()) 178 , m_renderHeight (rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_HEIGHT : m_context.getRenderTarget().getHeight()) 179 , m_viewportWidth (de::min<int>(m_renderWidth, MAX_VIEWPORT_WIDTH)) 180 , m_viewportHeight (de::min<int>(m_renderHeight, MAX_VIEWPORT_HEIGHT)) 181 , m_iterNdx (0) 182 { 183 } 184 185 const char* getBlendLayoutQualifier (rr::BlendEquationAdvanced equation) 186 { 187 static const char* s_qualifiers[] = 188 { 189 "blend_support_multiply", 190 "blend_support_screen", 191 "blend_support_overlay", 192 "blend_support_darken", 193 "blend_support_lighten", 194 "blend_support_colordodge", 195 "blend_support_colorburn", 196 "blend_support_hardlight", 197 "blend_support_softlight", 198 "blend_support_difference", 199 "blend_support_exclusion", 200 "blend_support_hsl_hue", 201 "blend_support_hsl_saturation", 202 "blend_support_hsl_color", 203 "blend_support_hsl_luminosity", 204 }; 205 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qualifiers) == rr::BLENDEQUATION_ADVANCED_LAST); 206 DE_ASSERT(de::inBounds<int>(equation, 0, rr::BLENDEQUATION_ADVANCED_LAST)); 207 return s_qualifiers[equation]; 208 } 209 210 glu::ProgramSources getBlendProgramSrc (rr::BlendEquationAdvanced equation, glu::RenderContext& renderContext) 211 { 212 const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); 213 214 static const char* s_vertSrc = "${GLSL_VERSION_DECL}\n" 215 "in highp vec4 a_position;\n" 216 "in mediump vec4 a_color;\n" 217 "out mediump vec4 v_color;\n" 218 "void main()\n" 219 "{\n" 220 " gl_Position = a_position;\n" 221 " v_color = a_color;\n" 222 "}\n"; 223 static const char* s_fragSrc = "${GLSL_VERSION_DECL}\n" 224 "${EXTENSION}" 225 "in mediump vec4 v_color;\n" 226 "layout(${SUPPORT_QUALIFIER}) out;\n" 227 "layout(location = 0) out mediump vec4 o_color;\n" 228 "void main()\n" 229 "{\n" 230 " o_color = v_color;\n" 231 "}\n"; 232 233 map<string, string> args; 234 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); 235 args["EXTENSION"] = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n"; 236 args["SUPPORT_QUALIFIER"] = getBlendLayoutQualifier(equation); 237 238 return glu::ProgramSources() 239 << glu::VertexSource(tcu::StringTemplate(s_vertSrc).specialize(args)) 240 << glu::FragmentSource(tcu::StringTemplate(s_fragSrc).specialize(args)); 241 } 242 243 void AdvancedBlendCase::init (void) 244 { 245 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 246 const bool useFbo = m_rtType != RENDERTARGETTYPE_DEFAULT; 247 const bool useSRGB = m_rtType == RENDERTARGETTYPE_SRGB_FBO; 248 249 m_coherentExtensionSupported = m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"); 250 251 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) 252 if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced")) 253 TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced is not supported"); 254 255 if (m_coherentBlending && !m_coherentExtensionSupported) 256 TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced_coherent is not supported"); 257 258 TCU_CHECK(gl.blendBarrier); 259 260 DE_ASSERT(!m_program); 261 DE_ASSERT(!m_referenceRenderer); 262 DE_ASSERT(!m_refColorBuffer); 263 264 m_program = new glu::ShaderProgram(m_context.getRenderContext(), getBlendProgramSrc(sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode), m_context.getRenderContext())); 265 m_testCtx.getLog() << *m_program; 266 267 if (!m_program->isOk()) 268 { 269 delete m_program; 270 m_program = DE_NULL; 271 TCU_FAIL("Compile failed"); 272 } 273 274 m_referenceRenderer = new ReferenceQuadRenderer; 275 m_refColorBuffer = new TextureLevel(TextureFormat(useSRGB ? TextureFormat::sRGBA : TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight); 276 277 if (useFbo) 278 { 279 const deUint32 format = useSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8; 280 const int numSamples = m_rtType == RENDERTARGETTYPE_MSAA_FBO ? 4 : 0; 281 282 m_testCtx.getLog() << TestLog::Message << "Using FBO of size (" << m_renderWidth << ", " << m_renderHeight << ") with format " 283 << glu::getTextureFormatStr(format) << " and " << numSamples << " samples" 284 << TestLog::EndMessage; 285 286 gl.genRenderbuffers(1, &m_colorRbo); 287 gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorRbo); 288 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, format, m_renderWidth, m_renderHeight); 289 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create color RBO"); 290 291 gl.genFramebuffers(1, &m_fbo); 292 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 293 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRbo); 294 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO"); 295 296 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 297 298 if (numSamples > 0) 299 { 300 // Create resolve FBO 301 gl.genRenderbuffers(1, &m_resolveColorRbo); 302 gl.bindRenderbuffer(GL_RENDERBUFFER, m_resolveColorRbo); 303 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, m_renderWidth, m_renderHeight); 304 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create resolve color RBO"); 305 306 gl.genFramebuffers(1, &m_resolveFbo); 307 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo); 308 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColorRbo); 309 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO"); 310 311 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 312 313 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 314 } 315 } 316 else 317 DE_ASSERT(m_rtType == RENDERTARGETTYPE_DEFAULT); 318 319 m_iterNdx = 0; 320 } 321 322 AdvancedBlendCase::~AdvancedBlendCase (void) 323 { 324 AdvancedBlendCase::deinit(); 325 } 326 327 void AdvancedBlendCase::deinit (void) 328 { 329 delete m_program; 330 delete m_referenceRenderer; 331 delete m_refColorBuffer; 332 333 m_program = DE_NULL; 334 m_referenceRenderer = DE_NULL; 335 m_refColorBuffer = DE_NULL; 336 337 if (m_colorRbo || m_fbo) 338 { 339 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 340 341 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 342 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 343 344 if (m_colorRbo != 0) 345 { 346 gl.deleteRenderbuffers(1, &m_colorRbo); 347 m_colorRbo = 0; 348 } 349 350 if (m_fbo != 0) 351 { 352 gl.deleteFramebuffers(1, &m_fbo); 353 m_fbo = 0; 354 } 355 356 if (m_resolveColorRbo) 357 { 358 gl.deleteRenderbuffers(1, &m_resolveColorRbo); 359 m_resolveColorRbo = 0; 360 } 361 362 if (m_resolveFbo) 363 { 364 gl.deleteRenderbuffers(1, &m_resolveFbo); 365 m_resolveFbo = 0; 366 } 367 } 368 } 369 370 static tcu::Vec4 randomColor (de::Random* rnd) 371 { 372 const float rgbValues[] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f }; 373 const float alphaValues[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f }; 374 375 // \note Spec assumes premultiplied inputs. 376 const float a = rnd->choose<float>(DE_ARRAY_BEGIN(alphaValues), DE_ARRAY_END(alphaValues)); 377 const float r = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); 378 const float g = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); 379 const float b = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); 380 return tcu::Vec4(r, g, b, a); 381 } 382 383 static tcu::ConstPixelBufferAccess getLinearAccess (const tcu::ConstPixelBufferAccess& access) 384 { 385 if (access.getFormat().order == TextureFormat::sRGBA) 386 return tcu::ConstPixelBufferAccess(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), 387 access.getWidth(), access.getHeight(), access.getDepth(), 388 access.getRowPitch(), access.getSlicePitch(), access.getDataPtr()); 389 else 390 return access; 391 } 392 393 AdvancedBlendCase::IterateResult AdvancedBlendCase::iterate (void) 394 { 395 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 396 const glw::Functions& gl = renderCtx.getFunctions(); 397 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(m_iterNdx)); 398 const int viewportX = rnd.getInt(0, m_renderWidth - m_viewportWidth); 399 const int viewportY = rnd.getInt(0, m_renderHeight - m_viewportHeight); 400 const bool useFbo = m_rtType != RENDERTARGETTYPE_DEFAULT; 401 const bool requiresResolve = m_rtType == RENDERTARGETTYPE_MSAA_FBO; 402 const int numQuads = m_overdrawCount+1; 403 TextureLevel renderedImg (TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight); 404 vector<Vec4> colors (numQuads*4); 405 406 for (vector<Vec4>::iterator col = colors.begin(); col != colors.end(); ++col) 407 *col = randomColor(&rnd); 408 409 // Render with GL. 410 { 411 const deUint32 program = m_program->getProgram(); 412 const int posLoc = gl.getAttribLocation(program, "a_position"); 413 const int colorLoc = gl.getAttribLocation(program, "a_color"); 414 const glu::Buffer indexBuffer (renderCtx); 415 const glu::Buffer positionBuffer (renderCtx); 416 const glu::Buffer colorBuffer (renderCtx); 417 vector<Vec2> positions (numQuads*4); 418 vector<deUint16> indices (numQuads*6); 419 const deUint16 singleQuadIndices[] = { 0, 2, 1, 1, 2, 3 }; 420 const Vec2 singleQuadPos[] = 421 { 422 Vec2(-1.0f, -1.0f), 423 Vec2(-1.0f, +1.0f), 424 Vec2(+1.0f, -1.0f), 425 Vec2(+1.0f, +1.0f), 426 }; 427 428 TCU_CHECK(posLoc >= 0 && colorLoc >= 0); 429 430 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) 431 { 432 std::copy(DE_ARRAY_BEGIN(singleQuadPos), DE_ARRAY_END(singleQuadPos), &positions[quadNdx*4]); 433 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleQuadIndices); ndx++) 434 indices[quadNdx*6 + ndx] = (deUint16)(quadNdx*4 + singleQuadIndices[ndx]); 435 } 436 437 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer); 438 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size()*sizeof(indices[0])), &indices[0], GL_STATIC_DRAW); 439 440 gl.bindBuffer(GL_ARRAY_BUFFER, *positionBuffer); 441 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STATIC_DRAW); 442 gl.enableVertexAttribArray(posLoc); 443 gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL); 444 445 gl.bindBuffer(GL_ARRAY_BUFFER, *colorBuffer); 446 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size()*sizeof(colors[0])), &colors[0], GL_STATIC_DRAW); 447 gl.enableVertexAttribArray(colorLoc); 448 gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 449 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffers"); 450 451 gl.useProgram(program); 452 gl.viewport(viewportX, viewportY, m_viewportWidth, m_viewportHeight); 453 gl.blendEquation(m_blendMode); 454 455 // \note coherent extension enables GL_BLEND_ADVANCED_COHERENT_KHR by default 456 if (m_coherentBlending) 457 gl.enable(GL_BLEND_ADVANCED_COHERENT_KHR); 458 else if (m_coherentExtensionSupported) 459 gl.disable(GL_BLEND_ADVANCED_COHERENT_KHR); 460 461 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set render state"); 462 463 gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 464 465 gl.disable(GL_BLEND); 466 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL); 467 gl.enable(GL_BLEND); 468 469 if (!m_coherentBlending) 470 gl.blendBarrier(); 471 472 if (m_coherentBlending) 473 { 474 gl.drawElements(GL_TRIANGLES, 6*(numQuads-1), GL_UNSIGNED_SHORT, (const void*)(deUintptr)(6*sizeof(deUint16))); 475 } 476 else 477 { 478 for (int quadNdx = 1; quadNdx < numQuads; quadNdx++) 479 { 480 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void*)(deUintptr)(quadNdx*6*sizeof(deUint16))); 481 gl.blendBarrier(); 482 } 483 } 484 485 gl.flush(); 486 GLU_EXPECT_NO_ERROR(gl.getError(), "Render failed"); 487 } 488 489 // Render reference. 490 { 491 rr::FragmentOperationState referenceState; 492 const tcu::PixelBufferAccess colorAccess = gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()); 493 const tcu::PixelBufferAccess nullAccess = tcu::PixelBufferAccess(); 494 IntegerQuad quad; 495 496 if (!useFbo && m_context.getRenderTarget().getPixelFormat().alphaBits == 0) 497 { 498 // Emulate lack of alpha by clearing to 1 and masking out alpha writes 499 tcu::clear(*m_refColorBuffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 500 referenceState.colorMask = tcu::BVec4(true, true, true, false); 501 } 502 503 referenceState.blendEquationAdvaced = sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode); 504 505 quad.posA = tcu::IVec2(0, 0); 506 quad.posB = tcu::IVec2(m_viewportWidth-1, m_viewportHeight-1); 507 508 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) 509 { 510 referenceState.blendMode = quadNdx == 0 ? rr::BLENDMODE_NONE : rr::BLENDMODE_ADVANCED; 511 std::copy(&colors[4*quadNdx], &colors[4*quadNdx] + 4, &quad.color[0]); 512 m_referenceRenderer->render(colorAccess, nullAccess /* no depth */, nullAccess /* no stencil */, quad, referenceState); 513 } 514 } 515 516 if (requiresResolve) 517 { 518 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo); 519 gl.blitFramebuffer(0, 0, m_renderWidth, m_renderHeight, 0, 0, m_renderWidth, m_renderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); 520 GLU_EXPECT_NO_ERROR(gl.getError(), "Resolve blit failed"); 521 522 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo); 523 } 524 525 glu::readPixels(renderCtx, viewportX, viewportY, renderedImg.getAccess()); 526 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()"); 527 528 if (requiresResolve) 529 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 530 531 { 532 const bool isHSLMode = m_blendMode == GL_HSL_HUE || 533 m_blendMode == GL_HSL_SATURATION || 534 m_blendMode == GL_HSL_COLOR || 535 m_blendMode == GL_HSL_LUMINOSITY; 536 bool comparePass = false; 537 538 if (isHSLMode) 539 { 540 // Compensate for more demanding HSL code by using fuzzy comparison. 541 const float threshold = 0.002f; 542 comparePass = tcu::fuzzyCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", 543 getLinearAccess(m_refColorBuffer->getAccess()), 544 renderedImg.getAccess(), 545 threshold, tcu::COMPARE_LOG_RESULT); 546 } 547 else 548 { 549 const UVec4 compareThreshold = (useFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat()).getColorThreshold().toIVec().asUint() 550 * UVec4(5) / UVec4(2) + UVec4(3 * m_overdrawCount); 551 552 comparePass = tcu::bilinearCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", 553 getLinearAccess(m_refColorBuffer->getAccess()), 554 renderedImg.getAccess(), 555 tcu::RGBA(compareThreshold[0], compareThreshold[1], compareThreshold[2], compareThreshold[3]), 556 tcu::COMPARE_LOG_RESULT); 557 } 558 559 if (!comparePass) 560 { 561 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 562 return STOP; 563 } 564 } 565 566 m_iterNdx += 1; 567 568 if (m_iterNdx < m_numIters) 569 return CONTINUE; 570 else 571 { 572 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 573 return STOP; 574 } 575 } 576 577 class BlendAdvancedCoherentStateCase : public TestCase 578 { 579 public: 580 BlendAdvancedCoherentStateCase (Context& context, 581 const char* name, 582 const char* description, 583 gls::StateQueryUtil::QueryType type); 584 private: 585 IterateResult iterate (void); 586 587 const gls::StateQueryUtil::QueryType m_type; 588 }; 589 590 BlendAdvancedCoherentStateCase::BlendAdvancedCoherentStateCase (Context& context, 591 const char* name, 592 const char* description, 593 gls::StateQueryUtil::QueryType type) 594 : TestCase (context, name, description) 595 , m_type (type) 596 { 597 } 598 599 BlendAdvancedCoherentStateCase::IterateResult BlendAdvancedCoherentStateCase::iterate (void) 600 { 601 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"), "GL_KHR_blend_equation_advanced_coherent is not supported"); 602 603 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 604 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 605 606 gl.enableLogging(true); 607 608 // check inital value 609 { 610 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial"); 611 gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type); 612 } 613 614 // check toggle 615 { 616 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Toggle", "Toggle"); 617 gl.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR); 618 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glDisable"); 619 620 gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, false, m_type); 621 622 gl.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR); 623 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glEnable"); 624 625 gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type); 626 } 627 628 result.setTestContextResult(m_testCtx); 629 return STOP; 630 } 631 632 class BlendEquationStateCase : public TestCase 633 { 634 public: 635 BlendEquationStateCase (Context& context, 636 const char* name, 637 const char* description, 638 const glw::GLenum* equations, 639 int numEquations, 640 gls::StateQueryUtil::QueryType type); 641 private: 642 IterateResult iterate (void); 643 644 const gls::StateQueryUtil::QueryType m_type; 645 const glw::GLenum* m_equations; 646 const int m_numEquations; 647 }; 648 649 BlendEquationStateCase::BlendEquationStateCase (Context& context, 650 const char* name, 651 const char* description, 652 const glw::GLenum* equations, 653 int numEquations, 654 gls::StateQueryUtil::QueryType type) 655 : TestCase (context, name, description) 656 , m_type (type) 657 , m_equations (equations) 658 , m_numEquations (numEquations) 659 { 660 } 661 662 BlendEquationStateCase::IterateResult BlendEquationStateCase::iterate (void) 663 { 664 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) 665 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"), "GL_KHR_blend_equation_advanced is not supported"); 666 667 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 668 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 669 670 gl.enableLogging(true); 671 672 for (int ndx = 0; ndx < m_numEquations; ++ndx) 673 { 674 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type", "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx]))); 675 676 gl.glBlendEquation(m_equations[ndx]); 677 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquation"); 678 679 gls::StateQueryUtil::verifyStateInteger(result, gl, GL_BLEND_EQUATION, m_equations[ndx], m_type); 680 } 681 682 result.setTestContextResult(m_testCtx); 683 return STOP; 684 } 685 686 class BlendEquationIndexedStateCase : public TestCase 687 { 688 public: 689 BlendEquationIndexedStateCase (Context& context, 690 const char* name, 691 const char* description, 692 const glw::GLenum* equations, 693 int numEquations, 694 gls::StateQueryUtil::QueryType type); 695 private: 696 IterateResult iterate (void); 697 698 const gls::StateQueryUtil::QueryType m_type; 699 const glw::GLenum* m_equations; 700 const int m_numEquations; 701 }; 702 703 BlendEquationIndexedStateCase::BlendEquationIndexedStateCase (Context& context, 704 const char* name, 705 const char* description, 706 const glw::GLenum* equations, 707 int numEquations, 708 gls::StateQueryUtil::QueryType type) 709 : TestCase (context, name, description) 710 , m_type (type) 711 , m_equations (equations) 712 , m_numEquations (numEquations) 713 { 714 } 715 716 BlendEquationIndexedStateCase::IterateResult BlendEquationIndexedStateCase::iterate (void) 717 { 718 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) 719 { 720 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"), "GL_KHR_blend_equation_advanced is not supported"); 721 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"), "GL_EXT_draw_buffers_indexed is not supported"); 722 } 723 724 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 725 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 726 727 gl.enableLogging(true); 728 729 for (int ndx = 0; ndx < m_numEquations; ++ndx) 730 { 731 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type", "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx]))); 732 733 gl.glBlendEquationi(2, m_equations[ndx]); 734 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquationi"); 735 736 gls::StateQueryUtil::verifyStateIndexedInteger(result, gl, GL_BLEND_EQUATION, 2, m_equations[ndx], m_type); 737 } 738 739 result.setTestContextResult(m_testCtx); 740 return STOP; 741 } 742 743 } // anonymous 744 745 AdvancedBlendTests::AdvancedBlendTests (Context& context) 746 : TestCaseGroup(context, "blend_equation_advanced", "GL_blend_equation_advanced Tests") 747 { 748 } 749 750 AdvancedBlendTests::~AdvancedBlendTests (void) 751 { 752 } 753 754 void AdvancedBlendTests::init (void) 755 { 756 static const glw::GLenum s_blendEquations[] = 757 { 758 GL_MULTIPLY, 759 GL_SCREEN, 760 GL_OVERLAY, 761 GL_DARKEN, 762 GL_LIGHTEN, 763 GL_COLORDODGE, 764 GL_COLORBURN, 765 GL_HARDLIGHT, 766 GL_SOFTLIGHT, 767 GL_DIFFERENCE, 768 GL_EXCLUSION, 769 GL_HSL_HUE, 770 GL_HSL_SATURATION, 771 GL_HSL_COLOR, 772 GL_HSL_LUMINOSITY, 773 }; 774 775 tcu::TestCaseGroup* const stateQueryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "State query tests"); 776 tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Single quad only"); 777 tcu::TestCaseGroup* const srgbGroup = new tcu::TestCaseGroup(m_testCtx, "srgb", "Advanced blending with sRGB FBO"); 778 tcu::TestCaseGroup* const msaaGroup = new tcu::TestCaseGroup(m_testCtx, "msaa", "Advanced blending with MSAA FBO"); 779 tcu::TestCaseGroup* const barrierGroup = new tcu::TestCaseGroup(m_testCtx, "barrier", "Multiple overlapping quads with blend barriers"); 780 tcu::TestCaseGroup* const coherentGroup = new tcu::TestCaseGroup(m_testCtx, "coherent", "Overlapping quads with coherent blending"); 781 tcu::TestCaseGroup* const coherentMsaaGroup = new tcu::TestCaseGroup(m_testCtx, "coherent_msaa", "Overlapping quads with coherent blending with MSAA FBO"); 782 783 addChild(stateQueryGroup); 784 addChild(basicGroup); 785 addChild(srgbGroup); 786 addChild(msaaGroup); 787 addChild(barrierGroup); 788 addChild(coherentGroup); 789 addChild(coherentMsaaGroup); 790 791 // .state_query 792 { 793 using namespace gls::StateQueryUtil; 794 795 stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getboolean", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_BOOLEAN)); 796 stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_isenabled", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_ISENABLED)); 797 stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getinteger", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER)); 798 stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getinteger64", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER64)); 799 stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getfloat", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_FLOAT)); 800 801 stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getboolean", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_BOOLEAN)); 802 stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER)); 803 stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger64", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER64)); 804 stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getfloat", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_FLOAT)); 805 806 stateQueryGroup->addChild(new BlendEquationIndexedStateCase(m_context, "blend_equation_getbooleani_v", "Test per-attchment BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_BOOLEAN)); 807 stateQueryGroup->addChild(new BlendEquationIndexedStateCase(m_context, "blend_equation_getintegeri_v", "Test per-attchment BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_INTEGER)); 808 stateQueryGroup->addChild(new BlendEquationIndexedStateCase(m_context, "blend_equation_getinteger64i_v", "Test per-attchment BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_INTEGER64)); 809 } 810 811 // others 812 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(s_blendEquations); modeNdx++) 813 { 814 const char* const name = getEquationName(s_blendEquations[modeNdx]); 815 const char* const desc = ""; 816 const deUint32 mode = s_blendEquations[modeNdx]; 817 818 basicGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_DEFAULT)); 819 srgbGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_SRGB_FBO)); 820 msaaGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_MSAA_FBO)); 821 barrierGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 4, false, RENDERTARGETTYPE_DEFAULT)); 822 coherentGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 4, true, RENDERTARGETTYPE_DEFAULT)); 823 coherentMsaaGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 4, true, RENDERTARGETTYPE_MSAA_FBO)); 824 } 825 } 826 827 } // Functional 828 } // gles31 829 } // deqp 830