You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
849 lines
30 KiB
849 lines
30 KiB
/*-------------------------------------------------------------------------
|
|
* 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);
|
|
}
|
|
|
|
if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()) && useSRGB)
|
|
gl.enable(GL_FRAMEBUFFER_SRGB);
|
|
}
|
|
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;
|
|
}
|
|
|
|
if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()) && RENDERTARGETTYPE_SRGB_FBO == m_rtType)
|
|
gl.disable(GL_FRAMEBUFFER_SRGB);
|
|
}
|
|
}
|
|
|
|
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");
|
|
deUint32 vao = 0;
|
|
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]);
|
|
}
|
|
|
|
if (!glu::isContextTypeES(renderCtx.getType()))
|
|
{
|
|
gl.genVertexArrays(1, &vao);
|
|
gl.bindVertexArray(vao);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
if (vao)
|
|
gl.deleteVertexArrays(1, &vao);
|
|
|
|
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)
|
|
{
|
|
const auto& renderContext = m_context.getRenderContext();
|
|
if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)) &&
|
|
!glu::contextSupports(renderContext.getType(), glu::ApiType::core(4, 5)))
|
|
{
|
|
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 (renderContext.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
|