blob: c29cdb8166714570f81d72ac7999afbda4f022e7 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 FBO multisample tests.
*//*--------------------------------------------------------------------*/
#include "es3fFboMultisampleTests.hpp"
#include "es3fFboTestCase.hpp"
#include "es3fFboTestUtil.hpp"
#include "gluTextureUtil.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuTestLog.hpp"
#include "deStringUtil.hpp"
#include "deRandom.hpp"
#include "sglrContextUtil.hpp"
#include "glwEnums.hpp"
namespace deqp
{
namespace gles3
{
namespace Functional
{
using std::string;
using tcu::TestLog;
using tcu::Vec2;
using tcu::Vec3;
using tcu::Vec4;
using tcu::IVec2;
using tcu::IVec3;
using tcu::IVec4;
using tcu::UVec4;
using namespace FboTestUtil;
class BasicFboMultisampleCase : public FboTestCase
{
public:
BasicFboMultisampleCase (Context& context, const char* name, const char* desc, deUint32 colorFormat, deUint32 depthStencilFormat, const IVec2& size, int numSamples)
: FboTestCase (context, name, desc)
, m_colorFormat (colorFormat)
, m_depthStencilFormat (depthStencilFormat)
, m_size (size)
, m_numSamples (numSamples)
{
}
protected:
void preCheck (void)
{
checkFormatSupport (m_colorFormat);
checkSampleCount (m_colorFormat, m_numSamples);
if (m_depthStencilFormat != GL_NONE)
{
checkFormatSupport (m_depthStencilFormat);
checkSampleCount (m_depthStencilFormat, m_numSamples);
}
}
void render (tcu::Surface& dst)
{
tcu::TextureFormat colorFmt = glu::mapGLInternalFormat(m_colorFormat);
tcu::TextureFormat depthStencilFmt = m_depthStencilFormat != GL_NONE ? glu::mapGLInternalFormat(m_depthStencilFormat) : tcu::TextureFormat();
tcu::TextureFormatInfo colorFmtInfo = tcu::getTextureFormatInfo(colorFmt);
bool depth = depthStencilFmt.order == tcu::TextureFormat::D || depthStencilFmt.order == tcu::TextureFormat::DS;
bool stencil = depthStencilFmt.order == tcu::TextureFormat::S || depthStencilFmt.order == tcu::TextureFormat::DS;
GradientShader gradShader (getFragmentOutputType(colorFmt));
FlatColorShader flatShader (getFragmentOutputType(colorFmt));
deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader);
deUint32 flatShaderID = getCurrentContext()->createProgram(&flatShader);
deUint32 msaaFbo = 0;
deUint32 resolveFbo = 0;
deUint32 msaaColorRbo = 0;
deUint32 resolveColorRbo = 0;
deUint32 msaaDepthStencilRbo = 0;
deUint32 resolveDepthStencilRbo = 0;
// Create framebuffers.
for (int ndx = 0; ndx < 2; ndx++)
{
deUint32& fbo = ndx ? resolveFbo : msaaFbo;
deUint32& colorRbo = ndx ? resolveColorRbo : msaaColorRbo;
deUint32& depthStencilRbo = ndx ? resolveDepthStencilRbo : msaaDepthStencilRbo;
int samples = ndx ? 0 : m_numSamples;
glGenRenderbuffers(1, &colorRbo);
glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_colorFormat, m_size.x(), m_size.y());
if (depth || stencil)
{
glGenRenderbuffers(1, &depthStencilRbo);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_depthStencilFormat, m_size.x(), m_size.y());
}
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
if (depth)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
if (stencil)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
checkError();
checkFramebufferStatus(GL_FRAMEBUFFER);
}
glBindFramebuffer(GL_FRAMEBUFFER, msaaFbo);
glViewport(0, 0, m_size.x(), m_size.y());
// Clear depth and stencil buffers.
glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
// Fill MSAA fbo with gradient, depth = [-1..1]
glEnable(GL_DEPTH_TEST);
gradShader.setGradient(*getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax);
sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
// Render random-colored quads.
{
const int numQuads = 8;
de::Random rnd (9);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0xffu);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
for (int ndx = 0; ndx < numQuads; ndx++)
{
float r = rnd.getFloat();
float g = rnd.getFloat();
float b = rnd.getFloat();
float a = rnd.getFloat();
float x0 = rnd.getFloat(-1.0f, 1.0f);
float y0 = rnd.getFloat(-1.0f, 1.0f);
float z0 = rnd.getFloat(-1.0f, 1.0f);
float x1 = rnd.getFloat(-1.0f, 1.0f);
float y1 = rnd.getFloat(-1.0f, 1.0f);
float z1 = rnd.getFloat(-1.0f, 1.0f);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(r,g,b,a) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(x0, y0, z0), Vec3(x1, y1, z1));
}
}
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
checkError();
// Resolve using glBlitFramebuffer().
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFbo);
glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT | (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFbo);
if (depth)
{
// Visualize depth.
const int numSteps = 8;
const float step = 2.0f / (float)numSteps;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_FALSE);
glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
for (int ndx = 0; ndx < numSteps; ndx++)
{
float d = -1.0f + step*(float)ndx;
float c = (float)ndx / (float)(numSteps-1);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, c, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, d), Vec3(1.0f, 1.0f, d));
}
glDisable(GL_DEPTH_TEST);
}
if (stencil)
{
// Visualize stencil.
const int numSteps = 4;
const int step = 1;
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
for (int ndx = 0; ndx < numSteps; ndx++)
{
int s = step*ndx;
float c = (float)ndx / (float)(numSteps-1);
glStencilFunc(GL_EQUAL, s, 0xffu);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, c, 0.0f, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
}
glDisable(GL_STENCIL_TEST);
}
readPixels(dst, 0, 0, m_size.x(), m_size.y(), colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias);
}
bool colorCompare (const tcu::Surface& reference, const tcu::Surface& result)
{
const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_colorFormat), tcu::RGBA(12, 12, 12, 12)));
return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
}
bool compare (const tcu::Surface& reference, const tcu::Surface& result)
{
if (m_depthStencilFormat != GL_NONE)
return FboTestCase::compare(reference, result);
else
return colorCompare(reference, result);
}
private:
deUint32 m_colorFormat;
deUint32 m_depthStencilFormat;
IVec2 m_size;
int m_numSamples;
};
FboMultisampleTests::FboMultisampleTests (Context& context)
: TestCaseGroup(context, "msaa", "Multisample FBO tests")
{
}
FboMultisampleTests::~FboMultisampleTests (void)
{
}
void FboMultisampleTests::init (void)
{
static const deUint32 colorFormats[] =
{
// RGBA formats
GL_RGBA8,
GL_SRGB8_ALPHA8,
GL_RGB10_A2,
GL_RGBA4,
GL_RGB5_A1,
// RGB formats
GL_RGB8,
GL_RGB565,
// RG formats
GL_RG8,
// R formats
GL_R8,
// GL_EXT_color_buffer_float
GL_RGBA32F,
GL_RGBA16F,
GL_R11F_G11F_B10F,
GL_RG32F,
GL_RG16F,
GL_R32F,
GL_R16F
};
static const deUint32 depthStencilFormats[] =
{
GL_DEPTH_COMPONENT32F,
GL_DEPTH_COMPONENT24,
GL_DEPTH_COMPONENT16,
GL_DEPTH32F_STENCIL8,
GL_DEPTH24_STENCIL8,
GL_STENCIL_INDEX8
};
static const int sampleCounts[] = { 2, 4, 8 };
for (int sampleCntNdx = 0; sampleCntNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCntNdx++)
{
int samples = sampleCounts[sampleCntNdx];
tcu::TestCaseGroup* sampleCountGroup = new tcu::TestCaseGroup(m_testCtx, (de::toString(samples) + "_samples").c_str(), "");
addChild(sampleCountGroup);
// Color formats.
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], GL_NONE, IVec2(119, 131), samples));
// Depth/stencil formats.
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++)
sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(depthStencilFormats[fmtNdx]), "", GL_RGBA8, depthStencilFormats[fmtNdx], IVec2(119, 131), samples));
}
}
} // Functional
} // gles3
} // deqp