| /*------------------------------------------------------------------------- |
| * 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 <string> |
| #include <vector> |
| |
| 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<int>(m_renderWidth, MAX_VIEWPORT_WIDTH)) |
| , m_viewportHeight (de::min<int>(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<int>(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<string, string> 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<float>(DE_ARRAY_BEGIN(alphaValues), DE_ARRAY_END(alphaValues)); |
| const float r = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); |
| const float g = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues)); |
| const float b = a * rnd->choose<float>(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<Vec4> colors (numQuads*4); |
| |
| for (vector<Vec4>::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<Vec2> positions (numQuads*4); |
| vector<deUint16> 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 |