/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.0 Module * ------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Advanced blending (GL_KHR_blend_equation_advanced) tests. *//*--------------------------------------------------------------------*/ #include "es31fAdvancedBlendTests.hpp" #include "gluStrUtil.hpp" #include "glsFragmentOpUtil.hpp" #include "glsStateQueryUtil.hpp" #include "gluPixelTransfer.hpp" #include "gluObjectWrapper.hpp" #include "gluContextInfo.hpp" #include "gluShaderProgram.hpp" #include "gluCallLogWrapper.hpp" #include "gluStrUtil.hpp" #include "tcuPixelFormat.hpp" #include "tcuTexture.hpp" #include "tcuTextureUtil.hpp" #include "tcuImageCompare.hpp" #include "tcuRenderTarget.hpp" #include "tcuTestLog.hpp" #include "tcuStringTemplate.hpp" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "rrFragmentOperations.hpp" #include "sglrReferenceUtils.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include #include namespace deqp { using gls::FragmentOpUtil::IntegerQuad; using gls::FragmentOpUtil::ReferenceQuadRenderer; using tcu::TextureLevel; using tcu::Vec2; using tcu::Vec4; using tcu::UVec4; using tcu::TestLog; using tcu::TextureFormat; using std::string; using std::vector; using std::map; namespace gles31 { namespace Functional { namespace { enum { MAX_VIEWPORT_WIDTH = 128, MAX_VIEWPORT_HEIGHT = 128 }; enum RenderTargetType { RENDERTARGETTYPE_DEFAULT = 0, //!< Default framebuffer RENDERTARGETTYPE_SRGB_FBO, RENDERTARGETTYPE_MSAA_FBO, RENDERTARGETTYPE_LAST }; static const char* getEquationName (glw::GLenum equation) { switch (equation) { case GL_MULTIPLY: return "multiply"; case GL_SCREEN: return "screen"; case GL_OVERLAY: return "overlay"; case GL_DARKEN: return "darken"; case GL_LIGHTEN: return "lighten"; case GL_COLORDODGE: return "colordodge"; case GL_COLORBURN: return "colorburn"; case GL_HARDLIGHT: return "hardlight"; case GL_SOFTLIGHT: return "softlight"; case GL_DIFFERENCE: return "difference"; case GL_EXCLUSION: return "exclusion"; case GL_HSL_HUE: return "hsl_hue"; case GL_HSL_SATURATION: return "hsl_saturation"; case GL_HSL_COLOR: return "hsl_color"; case GL_HSL_LUMINOSITY: return "hsl_luminosity"; default: DE_ASSERT(false); return DE_NULL; } } class AdvancedBlendCase : public TestCase { public: AdvancedBlendCase (Context& context, const char* name, const char* desc, deUint32 mode, int overdrawCount, bool coherent, RenderTargetType rtType); ~AdvancedBlendCase (void); void init (void); void deinit (void); IterateResult iterate (void); private: AdvancedBlendCase (const AdvancedBlendCase&); AdvancedBlendCase& operator= (const AdvancedBlendCase&); const deUint32 m_blendMode; const int m_overdrawCount; const bool m_coherentBlending; const RenderTargetType m_rtType; const int m_numIters; bool m_coherentExtensionSupported; deUint32 m_colorRbo; deUint32 m_fbo; deUint32 m_resolveColorRbo; deUint32 m_resolveFbo; glu::ShaderProgram* m_program; ReferenceQuadRenderer* m_referenceRenderer; TextureLevel* m_refColorBuffer; const int m_renderWidth; const int m_renderHeight; const int m_viewportWidth; const int m_viewportHeight; int m_iterNdx; }; AdvancedBlendCase::AdvancedBlendCase (Context& context, const char* name, const char* desc, deUint32 mode, int overdrawCount, bool coherent, RenderTargetType rtType) : TestCase (context, name, desc) , m_blendMode (mode) , m_overdrawCount (overdrawCount) , m_coherentBlending (coherent) , m_rtType (rtType) , m_numIters (5) , m_colorRbo (0) , m_fbo (0) , m_resolveColorRbo (0) , m_resolveFbo (0) , m_program (DE_NULL) , m_referenceRenderer (DE_NULL) , m_refColorBuffer (DE_NULL) , m_renderWidth (rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_WIDTH : m_context.getRenderTarget().getWidth()) , m_renderHeight (rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_HEIGHT : m_context.getRenderTarget().getHeight()) , m_viewportWidth (de::min(m_renderWidth, MAX_VIEWPORT_WIDTH)) , m_viewportHeight (de::min(m_renderHeight, MAX_VIEWPORT_HEIGHT)) , m_iterNdx (0) { } const char* getBlendLayoutQualifier (rr::BlendEquationAdvanced equation) { static const char* s_qualifiers[] = { "blend_support_multiply", "blend_support_screen", "blend_support_overlay", "blend_support_darken", "blend_support_lighten", "blend_support_colordodge", "blend_support_colorburn", "blend_support_hardlight", "blend_support_softlight", "blend_support_difference", "blend_support_exclusion", "blend_support_hsl_hue", "blend_support_hsl_saturation", "blend_support_hsl_color", "blend_support_hsl_luminosity", }; DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qualifiers) == rr::BLENDEQUATION_ADVANCED_LAST); DE_ASSERT(de::inBounds(equation, 0, rr::BLENDEQUATION_ADVANCED_LAST)); return s_qualifiers[equation]; } glu::ProgramSources getBlendProgramSrc (rr::BlendEquationAdvanced equation, glu::RenderContext& renderContext) { const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); static const char* s_vertSrc = "${GLSL_VERSION_DECL}\n" "in highp vec4 a_position;\n" "in mediump vec4 a_color;\n" "out mediump vec4 v_color;\n" "void main()\n" "{\n" " gl_Position = a_position;\n" " v_color = a_color;\n" "}\n"; static const char* s_fragSrc = "${GLSL_VERSION_DECL}\n" "${EXTENSION}" "in mediump vec4 v_color;\n" "layout(${SUPPORT_QUALIFIER}) out;\n" "layout(location = 0) out mediump vec4 o_color;\n" "void main()\n" "{\n" " o_color = v_color;\n" "}\n"; map args; args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); args["EXTENSION"] = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n"; args["SUPPORT_QUALIFIER"] = getBlendLayoutQualifier(equation); return glu::ProgramSources() << glu::VertexSource(tcu::StringTemplate(s_vertSrc).specialize(args)) << glu::FragmentSource(tcu::StringTemplate(s_fragSrc).specialize(args)); } void AdvancedBlendCase::init (void) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); const bool useFbo = m_rtType != RENDERTARGETTYPE_DEFAULT; const bool useSRGB = m_rtType == RENDERTARGETTYPE_SRGB_FBO; m_coherentExtensionSupported = m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"); if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced")) TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced is not supported"); if (m_coherentBlending && !m_coherentExtensionSupported) TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced_coherent is not supported"); TCU_CHECK(gl.blendBarrier); DE_ASSERT(!m_program); DE_ASSERT(!m_referenceRenderer); DE_ASSERT(!m_refColorBuffer); m_program = new glu::ShaderProgram(m_context.getRenderContext(), getBlendProgramSrc(sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode), m_context.getRenderContext())); m_testCtx.getLog() << *m_program; if (!m_program->isOk()) { delete m_program; m_program = DE_NULL; TCU_FAIL("Compile failed"); } m_referenceRenderer = new ReferenceQuadRenderer; m_refColorBuffer = new TextureLevel(TextureFormat(useSRGB ? TextureFormat::sRGBA : TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight); if (useFbo) { const deUint32 format = useSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8; const int numSamples = m_rtType == RENDERTARGETTYPE_MSAA_FBO ? 4 : 0; m_testCtx.getLog() << TestLog::Message << "Using FBO of size (" << m_renderWidth << ", " << m_renderHeight << ") with format " << glu::getTextureFormatStr(format) << " and " << numSamples << " samples" << TestLog::EndMessage; gl.genRenderbuffers(1, &m_colorRbo); gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorRbo); gl.renderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, format, m_renderWidth, m_renderHeight); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create color RBO"); gl.genFramebuffers(1, &m_fbo); gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRbo); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO"); TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); if (numSamples > 0) { // Create resolve FBO gl.genRenderbuffers(1, &m_resolveColorRbo); gl.bindRenderbuffer(GL_RENDERBUFFER, m_resolveColorRbo); gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, m_renderWidth, m_renderHeight); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create resolve color RBO"); gl.genFramebuffers(1, &m_resolveFbo); gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo); gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColorRbo); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO"); TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); } } else DE_ASSERT(m_rtType == RENDERTARGETTYPE_DEFAULT); m_iterNdx = 0; } AdvancedBlendCase::~AdvancedBlendCase (void) { AdvancedBlendCase::deinit(); } void AdvancedBlendCase::deinit (void) { delete m_program; delete m_referenceRenderer; delete m_refColorBuffer; m_program = DE_NULL; m_referenceRenderer = DE_NULL; m_refColorBuffer = DE_NULL; if (m_colorRbo || m_fbo) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); gl.bindRenderbuffer(GL_RENDERBUFFER, 0); gl.bindFramebuffer(GL_FRAMEBUFFER, 0); if (m_colorRbo != 0) { gl.deleteRenderbuffers(1, &m_colorRbo); m_colorRbo = 0; } if (m_fbo != 0) { gl.deleteFramebuffers(1, &m_fbo); m_fbo = 0; } if (m_resolveColorRbo) { gl.deleteRenderbuffers(1, &m_resolveColorRbo); m_resolveColorRbo = 0; } if (m_resolveFbo) { gl.deleteRenderbuffers(1, &m_resolveFbo); m_resolveFbo = 0; } } } static tcu::Vec4 randomColor (de::Random* rnd) { 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 }; const float alphaValues[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f }; // \note Spec assumes premultiplied inputs. const float a = rnd->choose(DE_ARRAY_BEGIN(alphaValues), DE_ARRAY_END(alphaValues)); const float r = a * rnd->choose(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); const float g = a * rnd->choose(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); const float b = a * rnd->choose(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); return tcu::Vec4(r, g, b, a); } static tcu::ConstPixelBufferAccess getLinearAccess (const tcu::ConstPixelBufferAccess& access) { if (access.getFormat().order == TextureFormat::sRGBA) return tcu::ConstPixelBufferAccess(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), access.getWidth(), access.getHeight(), access.getDepth(), access.getRowPitch(), access.getSlicePitch(), access.getDataPtr()); else return access; } AdvancedBlendCase::IterateResult AdvancedBlendCase::iterate (void) { const glu::RenderContext& renderCtx = m_context.getRenderContext(); const glw::Functions& gl = renderCtx.getFunctions(); de::Random rnd (deStringHash(getName()) ^ deInt32Hash(m_iterNdx)); const int viewportX = rnd.getInt(0, m_renderWidth - m_viewportWidth); const int viewportY = rnd.getInt(0, m_renderHeight - m_viewportHeight); const bool useFbo = m_rtType != RENDERTARGETTYPE_DEFAULT; const bool requiresResolve = m_rtType == RENDERTARGETTYPE_MSAA_FBO; const int numQuads = m_overdrawCount+1; TextureLevel renderedImg (TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight); vector colors (numQuads*4); for (vector::iterator col = colors.begin(); col != colors.end(); ++col) *col = randomColor(&rnd); // Render with GL. { const deUint32 program = m_program->getProgram(); const int posLoc = gl.getAttribLocation(program, "a_position"); const int colorLoc = gl.getAttribLocation(program, "a_color"); const glu::Buffer indexBuffer (renderCtx); const glu::Buffer positionBuffer (renderCtx); const glu::Buffer colorBuffer (renderCtx); vector positions (numQuads*4); vector indices (numQuads*6); const deUint16 singleQuadIndices[] = { 0, 2, 1, 1, 2, 3 }; const Vec2 singleQuadPos[] = { Vec2(-1.0f, -1.0f), Vec2(-1.0f, +1.0f), Vec2(+1.0f, -1.0f), Vec2(+1.0f, +1.0f), }; TCU_CHECK(posLoc >= 0 && colorLoc >= 0); for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) { std::copy(DE_ARRAY_BEGIN(singleQuadPos), DE_ARRAY_END(singleQuadPos), &positions[quadNdx*4]); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleQuadIndices); ndx++) indices[quadNdx*6 + ndx] = (deUint16)(quadNdx*4 + singleQuadIndices[ndx]); } gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer); gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size()*sizeof(indices[0])), &indices[0], GL_STATIC_DRAW); gl.bindBuffer(GL_ARRAY_BUFFER, *positionBuffer); gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STATIC_DRAW); gl.enableVertexAttribArray(posLoc); gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL); gl.bindBuffer(GL_ARRAY_BUFFER, *colorBuffer); gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size()*sizeof(colors[0])), &colors[0], GL_STATIC_DRAW); gl.enableVertexAttribArray(colorLoc); gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffers"); gl.useProgram(program); gl.viewport(viewportX, viewportY, m_viewportWidth, m_viewportHeight); gl.blendEquation(m_blendMode); // \note coherent extension enables GL_BLEND_ADVANCED_COHERENT_KHR by default if (m_coherentBlending) gl.enable(GL_BLEND_ADVANCED_COHERENT_KHR); else if (m_coherentExtensionSupported) gl.disable(GL_BLEND_ADVANCED_COHERENT_KHR); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set render state"); gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); gl.disable(GL_BLEND); gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL); gl.enable(GL_BLEND); if (!m_coherentBlending) gl.blendBarrier(); if (m_coherentBlending) { gl.drawElements(GL_TRIANGLES, 6*(numQuads-1), GL_UNSIGNED_SHORT, (const void*)(deUintptr)(6*sizeof(deUint16))); } else { for (int quadNdx = 1; quadNdx < numQuads; quadNdx++) { gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void*)(deUintptr)(quadNdx*6*sizeof(deUint16))); gl.blendBarrier(); } } gl.flush(); GLU_EXPECT_NO_ERROR(gl.getError(), "Render failed"); } // Render reference. { rr::FragmentOperationState referenceState; const tcu::PixelBufferAccess colorAccess = gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()); const tcu::PixelBufferAccess nullAccess = tcu::PixelBufferAccess(); IntegerQuad quad; if (!useFbo && m_context.getRenderTarget().getPixelFormat().alphaBits == 0) { // Emulate lack of alpha by clearing to 1 and masking out alpha writes tcu::clear(*m_refColorBuffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); referenceState.colorMask = tcu::BVec4(true, true, true, false); } referenceState.blendEquationAdvaced = sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode); quad.posA = tcu::IVec2(0, 0); quad.posB = tcu::IVec2(m_viewportWidth-1, m_viewportHeight-1); for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) { referenceState.blendMode = quadNdx == 0 ? rr::BLENDMODE_NONE : rr::BLENDMODE_ADVANCED; std::copy(&colors[4*quadNdx], &colors[4*quadNdx] + 4, &quad.color[0]); m_referenceRenderer->render(colorAccess, nullAccess /* no depth */, nullAccess /* no stencil */, quad, referenceState); } } if (requiresResolve) { gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo); gl.blitFramebuffer(0, 0, m_renderWidth, m_renderHeight, 0, 0, m_renderWidth, m_renderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); GLU_EXPECT_NO_ERROR(gl.getError(), "Resolve blit failed"); gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo); } glu::readPixels(renderCtx, viewportX, viewportY, renderedImg.getAccess()); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()"); if (requiresResolve) gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); { const bool isHSLMode = m_blendMode == GL_HSL_HUE || m_blendMode == GL_HSL_SATURATION || m_blendMode == GL_HSL_COLOR || m_blendMode == GL_HSL_LUMINOSITY; bool comparePass = false; if (isHSLMode) { // Compensate for more demanding HSL code by using fuzzy comparison. const float threshold = 0.002f; comparePass = tcu::fuzzyCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", getLinearAccess(m_refColorBuffer->getAccess()), renderedImg.getAccess(), threshold, tcu::COMPARE_LOG_RESULT); } else { const UVec4 compareThreshold = (useFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat()).getColorThreshold().toIVec().asUint() * UVec4(5) / UVec4(2) + UVec4(3 * m_overdrawCount); comparePass = tcu::bilinearCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", getLinearAccess(m_refColorBuffer->getAccess()), renderedImg.getAccess(), tcu::RGBA(compareThreshold[0], compareThreshold[1], compareThreshold[2], compareThreshold[3]), tcu::COMPARE_LOG_RESULT); } if (!comparePass) { m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); return STOP; } } m_iterNdx += 1; if (m_iterNdx < m_numIters) return CONTINUE; else { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } } class BlendAdvancedCoherentStateCase : public TestCase { public: BlendAdvancedCoherentStateCase (Context& context, const char* name, const char* description, gls::StateQueryUtil::QueryType type); private: IterateResult iterate (void); const gls::StateQueryUtil::QueryType m_type; }; BlendAdvancedCoherentStateCase::BlendAdvancedCoherentStateCase (Context& context, const char* name, const char* description, gls::StateQueryUtil::QueryType type) : TestCase (context, name, description) , m_type (type) { } BlendAdvancedCoherentStateCase::IterateResult BlendAdvancedCoherentStateCase::iterate (void) { TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"), "GL_KHR_blend_equation_advanced_coherent is not supported"); glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); gl.enableLogging(true); // check inital value { const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial"); gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type); } // check toggle { const tcu::ScopedLogSection section(m_testCtx.getLog(), "Toggle", "Toggle"); gl.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR); GLU_EXPECT_NO_ERROR(gl.glGetError(), "glDisable"); gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, false, m_type); gl.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR); GLU_EXPECT_NO_ERROR(gl.glGetError(), "glEnable"); gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type); } result.setTestContextResult(m_testCtx); return STOP; } class BlendEquationStateCase : public TestCase { public: BlendEquationStateCase (Context& context, const char* name, const char* description, const glw::GLenum* equations, int numEquations, gls::StateQueryUtil::QueryType type); private: IterateResult iterate (void); const gls::StateQueryUtil::QueryType m_type; const glw::GLenum* m_equations; const int m_numEquations; }; BlendEquationStateCase::BlendEquationStateCase (Context& context, const char* name, const char* description, const glw::GLenum* equations, int numEquations, gls::StateQueryUtil::QueryType type) : TestCase (context, name, description) , m_type (type) , m_equations (equations) , m_numEquations (numEquations) { } BlendEquationStateCase::IterateResult BlendEquationStateCase::iterate (void) { if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"), "GL_KHR_blend_equation_advanced is not supported"); glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); gl.enableLogging(true); for (int ndx = 0; ndx < m_numEquations; ++ndx) { const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type", "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx]))); gl.glBlendEquation(m_equations[ndx]); GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquation"); gls::StateQueryUtil::verifyStateInteger(result, gl, GL_BLEND_EQUATION, m_equations[ndx], m_type); } result.setTestContextResult(m_testCtx); return STOP; } class BlendEquationIndexedStateCase : public TestCase { public: BlendEquationIndexedStateCase (Context& context, const char* name, const char* description, const glw::GLenum* equations, int numEquations, gls::StateQueryUtil::QueryType type); private: IterateResult iterate (void); const gls::StateQueryUtil::QueryType m_type; const glw::GLenum* m_equations; const int m_numEquations; }; BlendEquationIndexedStateCase::BlendEquationIndexedStateCase (Context& context, const char* name, const char* description, const glw::GLenum* equations, int numEquations, gls::StateQueryUtil::QueryType type) : TestCase (context, name, description) , m_type (type) , m_equations (equations) , m_numEquations (numEquations) { } BlendEquationIndexedStateCase::IterateResult BlendEquationIndexedStateCase::iterate (void) { if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) { TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"), "GL_KHR_blend_equation_advanced is not supported"); TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"), "GL_EXT_draw_buffers_indexed is not supported"); } glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); gl.enableLogging(true); for (int ndx = 0; ndx < m_numEquations; ++ndx) { const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type", "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx]))); gl.glBlendEquationi(2, m_equations[ndx]); GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquationi"); gls::StateQueryUtil::verifyStateIndexedInteger(result, gl, GL_BLEND_EQUATION, 2, m_equations[ndx], m_type); } result.setTestContextResult(m_testCtx); return STOP; } } // anonymous AdvancedBlendTests::AdvancedBlendTests (Context& context) : TestCaseGroup(context, "blend_equation_advanced", "GL_blend_equation_advanced Tests") { } AdvancedBlendTests::~AdvancedBlendTests (void) { } void AdvancedBlendTests::init (void) { static const glw::GLenum s_blendEquations[] = { GL_MULTIPLY, GL_SCREEN, GL_OVERLAY, GL_DARKEN, GL_LIGHTEN, GL_COLORDODGE, GL_COLORBURN, GL_HARDLIGHT, GL_SOFTLIGHT, GL_DIFFERENCE, GL_EXCLUSION, GL_HSL_HUE, GL_HSL_SATURATION, GL_HSL_COLOR, GL_HSL_LUMINOSITY, }; tcu::TestCaseGroup* const stateQueryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "State query tests"); tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Single quad only"); tcu::TestCaseGroup* const srgbGroup = new tcu::TestCaseGroup(m_testCtx, "srgb", "Advanced blending with sRGB FBO"); tcu::TestCaseGroup* const msaaGroup = new tcu::TestCaseGroup(m_testCtx, "msaa", "Advanced blending with MSAA FBO"); tcu::TestCaseGroup* const barrierGroup = new tcu::TestCaseGroup(m_testCtx, "barrier", "Multiple overlapping quads with blend barriers"); tcu::TestCaseGroup* const coherentGroup = new tcu::TestCaseGroup(m_testCtx, "coherent", "Overlapping quads with coherent blending"); tcu::TestCaseGroup* const coherentMsaaGroup = new tcu::TestCaseGroup(m_testCtx, "coherent_msaa", "Overlapping quads with coherent blending with MSAA FBO"); addChild(stateQueryGroup); addChild(basicGroup); addChild(srgbGroup); addChild(msaaGroup); addChild(barrierGroup); addChild(coherentGroup); addChild(coherentMsaaGroup); // .state_query { using namespace gls::StateQueryUtil; stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getboolean", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_BOOLEAN)); stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_isenabled", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_ISENABLED)); stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getinteger", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER)); stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getinteger64", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER64)); stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getfloat", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_FLOAT)); stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getboolean", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_BOOLEAN)); stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER)); stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger64", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER64)); stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getfloat", "Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_FLOAT)); 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)); 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)); 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)); } // others for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(s_blendEquations); modeNdx++) { const char* const name = getEquationName(s_blendEquations[modeNdx]); const char* const desc = ""; const deUint32 mode = s_blendEquations[modeNdx]; basicGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_DEFAULT)); srgbGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_SRGB_FBO)); msaaGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_MSAA_FBO)); barrierGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 4, false, RENDERTARGETTYPE_DEFAULT)); coherentGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 4, true, RENDERTARGETTYPE_DEFAULT)); coherentMsaaGroup->addChild (new AdvancedBlendCase(m_context, name, desc, mode, 4, true, RENDERTARGETTYPE_MSAA_FBO)); } } } // Functional } // gles31 } // deqp