/*-------------------------------------------------------------------------
* 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 stencilbuffer tests.
*//*--------------------------------------------------------------------*/
#include "es3fFboStencilbufferTests.hpp"
#include "es3fFboTestCase.hpp"
#include "es3fFboTestUtil.hpp"
#include "gluTextureUtil.hpp"
#include "tcuTextureUtil.hpp"
#include "sglrContextUtil.hpp"
#include "glwEnums.hpp"
namespace deqp
{
namespace gles3
{
namespace Functional
{
using std::string;
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 BasicFboStencilCase : public FboTestCase
{
public:
BasicFboStencilCase (Context& context, const char* name, const char* desc, deUint32 format, IVec2 size, bool useDepth)
: FboTestCase (context, name, desc)
, m_format (format)
, m_size (size)
, m_useDepth (useDepth)
{
}
protected:
void preCheck (void)
{
checkFormatSupport(m_format);
}
void render (tcu::Surface& dst)
{
const deUint32 colorFormat = GL_RGBA8;
GradientShader gradShader (glu::TYPE_FLOAT_VEC4);
FlatColorShader flatShader (glu::TYPE_FLOAT_VEC4);
deUint32 flatShaderID = getCurrentContext()->createProgram(&flatShader);
deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader);
deUint32 fbo = 0;
deUint32 colorRbo = 0;
deUint32 depthStencilRbo = 0;
// Colorbuffer.
glGenRenderbuffers(1, &colorRbo);
glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, m_size.x(), m_size.y());
// Stencil (and depth) buffer.
glGenRenderbuffers(1, &depthStencilRbo);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_size.x(), m_size.y());
// Framebuffer.
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
if (m_useDepth)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
checkError();
checkFramebufferStatus(GL_FRAMEBUFFER);
glViewport(0, 0, m_size.x(), m_size.y());
// Clear framebuffer.
glClearBufferfv(GL_COLOR, 0, Vec4(0.0f).getPtr());
glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
// Render intersecting quads - increment stencil on depth pass
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0xffu);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(1.0f, 0.0f, 0.0f, 1.0f));
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
glDisable(GL_DEPTH_TEST);
// Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
glStencilFunc(GL_EQUAL, m_useDepth ? 2 : 1, 0xffu);
glStencilOp(GL_DECR, GL_KEEP, GL_KEEP);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0));
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
// Draw quad with stencil test where stencil > 1 or 2 depending on depth buffer
glStencilFunc(GL_GREATER, m_useDepth ? 1 : 2, 0xffu);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
readPixels(dst, 0, 0, m_size.x(), m_size.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
}
private:
deUint32 m_format;
IVec2 m_size;
bool m_useDepth;
};
class DepthStencilAttachCase : public FboTestCase
{
public:
DepthStencilAttachCase (Context& context, const char* name, const char* desc, deUint32 attachDepth, deUint32 attachStencil)
: FboTestCase (context, name, desc)
, m_attachDepth (attachDepth)
, m_attachStencil (attachStencil)
{
DE_ASSERT(m_attachDepth == GL_DEPTH_ATTACHMENT || m_attachDepth == GL_DEPTH_STENCIL_ATTACHMENT || m_attachDepth == GL_NONE);
DE_ASSERT(m_attachStencil == GL_STENCIL_ATTACHMENT || m_attachStencil == GL_NONE);
DE_ASSERT(m_attachDepth != GL_DEPTH_STENCIL || m_attachStencil == GL_NONE);
}
protected:
void render (tcu::Surface& dst)
{
const deUint32 colorFormat = GL_RGBA8;
const deUint32 depthStencilFormat = GL_DEPTH24_STENCIL8;
const int width = 128;
const int height = 128;
const bool hasDepth = (m_attachDepth == GL_DEPTH_STENCIL || m_attachDepth == GL_DEPTH_ATTACHMENT);
// const bool hasStencil = (m_attachDepth == GL_DEPTH_STENCIL || m_attachStencil == GL_DEPTH_STENCIL_ATTACHMENT);
GradientShader gradShader (glu::TYPE_FLOAT_VEC4);
FlatColorShader flatShader (glu::TYPE_FLOAT_VEC4);
deUint32 flatShaderID = getCurrentContext()->createProgram(&flatShader);
deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader);
deUint32 fbo = 0;
deUint32 colorRbo = 0;
deUint32 depthStencilRbo = 0;
// Colorbuffer.
glGenRenderbuffers(1, &colorRbo);
glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
// Depth-stencil buffer.
glGenRenderbuffers(1, &depthStencilRbo);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
glRenderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
// Framebuffer.
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
if (m_attachDepth != GL_NONE)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_attachDepth, GL_RENDERBUFFER, depthStencilRbo);
if (m_attachStencil != GL_NONE)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_attachStencil, GL_RENDERBUFFER, depthStencilRbo);
checkError();
checkFramebufferStatus(GL_FRAMEBUFFER);
glViewport(0, 0, width, height);
// Clear framebuffer.
glClearBufferfv(GL_COLOR, 0, Vec4(0.0f).getPtr());
glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
// Render intersecting quads - increment stencil on depth pass
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0xffu);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(1.0f, 0.0f, 0.0f, 1.0f));
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
glDisable(GL_DEPTH_TEST);
// Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
glStencilFunc(GL_EQUAL, hasDepth ? 2 : 1, 0xffu);
glStencilOp(GL_DECR, GL_KEEP, GL_KEEP);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0));
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
// Draw quad with stencil test where stencil > 1 or 2 depending on depth buffer
glStencilFunc(GL_GREATER, hasDepth ? 1 : 2, 0xffu);
flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
readPixels(dst, 0, 0, width, height, glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
}
private:
deUint32 m_attachDepth;
deUint32 m_attachStencil;
};
FboStencilTests::FboStencilTests (Context& context)
: TestCaseGroup(context, "stencil", "FBO Stencilbuffer tests")
{
}
FboStencilTests::~FboStencilTests (void)
{
}
void FboStencilTests::init (void)
{
static const deUint32 stencilFormats[] =
{
GL_DEPTH32F_STENCIL8,
GL_DEPTH24_STENCIL8,
GL_STENCIL_INDEX8
};
// .basic
{
tcu::TestCaseGroup* basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic stencil tests");
addChild(basicGroup);
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(stencilFormats); fmtNdx++)
{
deUint32 format = stencilFormats[fmtNdx];
tcu::TextureFormat texFmt = glu::mapGLInternalFormat(format);
basicGroup->addChild(new BasicFboStencilCase(m_context, getFormatName(format), "", format, IVec2(111, 132), false));
if (texFmt.order == tcu::TextureFormat::DS)
basicGroup->addChild(new BasicFboStencilCase(m_context, (string(getFormatName(format)) + "_depth").c_str(), "", format, IVec2(111, 132), true));
}
}
// .attach
{
tcu::TestCaseGroup* attachGroup = new tcu::TestCaseGroup(m_testCtx, "attach", "Attaching depth stencil");
addChild(attachGroup);
attachGroup->addChild(new DepthStencilAttachCase(m_context, "depth_only", "Only depth part of depth-stencil RBO attached", GL_DEPTH_ATTACHMENT, GL_NONE));
attachGroup->addChild(new DepthStencilAttachCase(m_context, "stencil_only", "Only stencil part of depth-stencil RBO attached", GL_NONE, GL_STENCIL_ATTACHMENT));
attachGroup->addChild(new DepthStencilAttachCase(m_context, "depth_stencil_separate", "Depth and stencil attached separately", GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT));
attachGroup->addChild(new DepthStencilAttachCase(m_context, "depth_stencil_attachment", "Depth and stencil attached with DEPTH_STENCIL_ATTACHMENT", GL_DEPTH_STENCIL_ATTACHMENT, GL_NONE));
}
}
} // Functional
} // gles3
} // deqp