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.
1159 lines
38 KiB
1159 lines
38 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 Depth & stencil tests.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es3fDepthStencilTests.hpp"
|
|
#include "glsFragmentOpUtil.hpp"
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "gluStrUtil.hpp"
|
|
#include "tcuSurface.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuImageCompare.hpp"
|
|
#include "tcuCommandLine.hpp"
|
|
#include "tcuTextureUtil.hpp"
|
|
#include "deRandom.hpp"
|
|
#include "deStringUtil.hpp"
|
|
#include "deMemory.h"
|
|
#include "deString.h"
|
|
#include "rrFragmentOperations.hpp"
|
|
#include "sglrReferenceUtils.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
#include "glw.h"
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles3
|
|
{
|
|
namespace Functional
|
|
{
|
|
|
|
using std::vector;
|
|
using tcu::IVec2;
|
|
using tcu::Vec2;
|
|
using tcu::Vec4;
|
|
using tcu::TestLog;
|
|
using std::ostringstream;
|
|
|
|
enum
|
|
{
|
|
VIEWPORT_WIDTH = 4*3*4,
|
|
VIEWPORT_HEIGHT = 4*12,
|
|
|
|
NUM_RANDOM_CASES = 25,
|
|
NUM_RANDOM_SUB_CASES = 10
|
|
};
|
|
|
|
namespace DepthStencilCaseUtil
|
|
{
|
|
|
|
struct StencilParams
|
|
{
|
|
deUint32 function;
|
|
int reference;
|
|
deUint32 compareMask;
|
|
|
|
deUint32 stencilFailOp;
|
|
deUint32 depthFailOp;
|
|
deUint32 depthPassOp;
|
|
|
|
deUint32 writeMask;
|
|
|
|
StencilParams (void)
|
|
: function (0)
|
|
, reference (0)
|
|
, compareMask (0)
|
|
, stencilFailOp (0)
|
|
, depthFailOp (0)
|
|
, depthPassOp (0)
|
|
, writeMask (0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct DepthStencilParams
|
|
{
|
|
rr::FaceType visibleFace; //!< Quad visible face.
|
|
|
|
bool stencilTestEnabled;
|
|
StencilParams stencil[rr::FACETYPE_LAST];
|
|
|
|
bool depthTestEnabled;
|
|
deUint32 depthFunc;
|
|
float depth;
|
|
bool depthWriteMask;
|
|
|
|
DepthStencilParams (void)
|
|
: visibleFace (rr::FACETYPE_LAST)
|
|
, stencilTestEnabled (false)
|
|
, depthTestEnabled (false)
|
|
, depthFunc (0)
|
|
, depth (0.0f)
|
|
, depthWriteMask (false)
|
|
{
|
|
}
|
|
};
|
|
|
|
tcu::TestLog& operator<< (tcu::TestLog& log, const StencilParams& params)
|
|
{
|
|
log << TestLog::Message << " func = " << glu::getCompareFuncStr(params.function) << "\n"
|
|
<< " ref = " << params.reference << "\n"
|
|
<< " compare mask = " << tcu::toHex(params.compareMask) << "\n"
|
|
<< " stencil fail = " << glu::getStencilOpStr(params.stencilFailOp) << "\n"
|
|
<< " depth fail = " << glu::getStencilOpStr(params.depthFailOp) << "\n"
|
|
<< " depth pass = " << glu::getStencilOpStr(params.depthPassOp) << "\n"
|
|
<< " write mask = " << tcu::toHex(params.writeMask) << "\n"
|
|
<< TestLog::EndMessage;
|
|
return log;
|
|
}
|
|
|
|
tcu::TestLog& operator<< (tcu::TestLog& log, const DepthStencilParams& params)
|
|
{
|
|
log << TestLog::Message << "Stencil test: " << (params.stencilTestEnabled ? "enabled" : "disabled") << TestLog::EndMessage;
|
|
if (params.stencilTestEnabled)
|
|
{
|
|
log << TestLog::Message << "Front-face stencil state: " << TestLog::EndMessage;
|
|
log << params.stencil[rr::FACETYPE_FRONT];
|
|
|
|
log << TestLog::Message << "Back-face stencil state: " << TestLog::EndMessage;
|
|
log << params.stencil[rr::FACETYPE_BACK];
|
|
}
|
|
|
|
log << TestLog::Message << "Depth test: " << (params.depthTestEnabled ? "enabled" : "disabled") << TestLog::EndMessage;
|
|
if (params.depthTestEnabled)
|
|
{
|
|
log << TestLog::Message << " func = " << glu::getCompareFuncStr(params.depthFunc) << "\n"
|
|
" depth value = " << params.depth << "\n"
|
|
" write mask = " << (params.depthWriteMask ? "true" : "false") << "\n"
|
|
<< TestLog::EndMessage;
|
|
}
|
|
|
|
log << TestLog::Message << "Triangles are " << (params.visibleFace == rr::FACETYPE_FRONT ? "front" : "back") << "-facing" << TestLog::EndMessage;
|
|
|
|
return log;
|
|
}
|
|
|
|
struct ClearCommand
|
|
{
|
|
rr::WindowRectangle rect;
|
|
deUint32 buffers;
|
|
tcu::Vec4 color;
|
|
int stencil;
|
|
// \note No depth here - don't use clears for setting depth values; use quad rendering instead. Cleared depths are in [0, 1] to begin with,
|
|
// whereas rendered depths are given in [-1, 1] and then mapped to [0, 1]; this discrepancy could cause precision issues in depth tests.
|
|
|
|
ClearCommand (void)
|
|
: rect (0, 0, 0, 0)
|
|
, buffers (0)
|
|
, stencil (0)
|
|
{
|
|
}
|
|
|
|
ClearCommand (const rr::WindowRectangle& rect_,
|
|
deUint32 buffers_,
|
|
const tcu::Vec4& color_,
|
|
int stencil_)
|
|
: rect (rect_)
|
|
, buffers (buffers_)
|
|
, color (color_)
|
|
, stencil (stencil_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct RenderCommand
|
|
{
|
|
DepthStencilParams params;
|
|
rr::WindowRectangle rect;
|
|
tcu::Vec4 color;
|
|
tcu::BVec4 colorMask;
|
|
|
|
RenderCommand (void)
|
|
: rect(0, 0, 0, 0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct RefRenderCommand
|
|
{
|
|
gls::FragmentOpUtil::IntegerQuad quad;
|
|
rr::FragmentOperationState state;
|
|
};
|
|
|
|
struct TestRenderTarget
|
|
{
|
|
int width;
|
|
int height;
|
|
int depthBits;
|
|
int stencilBits;
|
|
|
|
TestRenderTarget (int width_,
|
|
int height_,
|
|
int depthBits_,
|
|
int stencilBits_)
|
|
: width (width_)
|
|
, height (height_)
|
|
, depthBits (depthBits_)
|
|
, stencilBits (stencilBits_)
|
|
{
|
|
}
|
|
|
|
TestRenderTarget (void)
|
|
: width (0)
|
|
, height (0)
|
|
, depthBits (0)
|
|
, stencilBits (0)
|
|
{
|
|
}
|
|
};
|
|
|
|
void getStencilTestValues (int stencilBits, int numValues, int* values)
|
|
{
|
|
int numLowest = numValues/2;
|
|
int numHighest = numValues-numLowest;
|
|
int maxVal = (1<<stencilBits)-1;
|
|
|
|
for (int ndx = 0; ndx < numLowest; ndx++)
|
|
values[ndx] = ndx;
|
|
|
|
for (int ndx = 0; ndx < numHighest; ndx++)
|
|
values[numValues-ndx-1] = maxVal-ndx;
|
|
}
|
|
|
|
void generateBaseClearAndDepthCommands (const TestRenderTarget& target, vector<ClearCommand>& clearCommands, vector<RenderCommand>& renderCommands)
|
|
{
|
|
DE_ASSERT(clearCommands.empty());
|
|
DE_ASSERT(renderCommands.empty());
|
|
|
|
const int numL0CellsX = 4;
|
|
const int numL0CellsY = 4;
|
|
const int numL1CellsX = 3;
|
|
const int numL1CellsY = 1;
|
|
int cellL0Width = target.width/numL0CellsX;
|
|
int cellL0Height = target.height/numL0CellsY;
|
|
int cellL1Width = cellL0Width/numL1CellsX;
|
|
int cellL1Height = cellL0Height/numL1CellsY;
|
|
|
|
int stencilValues[numL0CellsX*numL0CellsY];
|
|
float depthValues[numL1CellsX*numL1CellsY];
|
|
|
|
if (cellL0Width <= 0 || cellL1Width <= 0 || cellL0Height <= 0 || cellL1Height <= 0)
|
|
throw tcu::NotSupportedError("Too small render target");
|
|
|
|
// Fullscreen clear to black.
|
|
clearCommands.push_back(ClearCommand(rr::WindowRectangle(0, 0, target.width, target.height), GL_COLOR_BUFFER_BIT, Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0));
|
|
|
|
// Compute stencil values: numL0CellsX*numL0CellsY combinations of lowest and highest bits.
|
|
getStencilTestValues(target.stencilBits, numL0CellsX*numL0CellsY, &stencilValues[0]);
|
|
|
|
// Compute depth values
|
|
{
|
|
int numValues = DE_LENGTH_OF_ARRAY(depthValues);
|
|
float depthStep = 2.0f/(float)(numValues-1);
|
|
|
|
for (int ndx = 0; ndx < numValues; ndx++)
|
|
depthValues[ndx] = -1.0f + depthStep*(float)ndx;
|
|
}
|
|
|
|
for (int y0 = 0; y0 < numL0CellsY; y0++)
|
|
{
|
|
for (int x0 = 0; x0 < numL0CellsX; x0++)
|
|
{
|
|
int stencilValue = stencilValues[y0*numL0CellsX + x0];
|
|
|
|
for (int y1 = 0; y1 < numL1CellsY; y1++)
|
|
{
|
|
for (int x1 = 0; x1 < numL1CellsX; x1++)
|
|
{
|
|
int x = x0*cellL0Width + x1*cellL1Width;
|
|
int y = y0*cellL0Height + y1*cellL1Height;
|
|
rr::WindowRectangle cellL1Rect (x, y, cellL1Width, cellL1Height);
|
|
|
|
clearCommands.push_back(ClearCommand(cellL1Rect, GL_STENCIL_BUFFER_BIT, Vec4(0), stencilValue));
|
|
|
|
RenderCommand renderCmd;
|
|
renderCmd.params.visibleFace = rr::FACETYPE_FRONT;
|
|
renderCmd.params.depth = depthValues[y1*numL1CellsX + x1];;
|
|
renderCmd.params.depthTestEnabled = true;
|
|
renderCmd.params.depthFunc = GL_ALWAYS;
|
|
renderCmd.params.depthWriteMask = true;
|
|
renderCmd.colorMask = tcu::BVec4(false);
|
|
renderCmd.rect = cellL1Rect;
|
|
|
|
renderCommands.push_back(renderCmd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void generateDepthVisualizeCommands (const TestRenderTarget& target, vector<RenderCommand>& commands)
|
|
{
|
|
const float epsilon = -0.05f;
|
|
static const float depthSteps[] = {-1.0f, -0.5f, 0.0f, 0.5f, 1.0f};
|
|
int numSteps = DE_LENGTH_OF_ARRAY(depthSteps);
|
|
const float colorStep = 1.0f / (float)(numSteps-1);
|
|
|
|
for (int ndx = 0; ndx < numSteps; ndx++)
|
|
{
|
|
RenderCommand cmd;
|
|
|
|
cmd.params.visibleFace = rr::FACETYPE_FRONT;
|
|
cmd.rect = rr::WindowRectangle(0, 0, target.width, target.height);
|
|
cmd.color = Vec4(0.0f, 0.0f, colorStep*(float)ndx, 0.0f);
|
|
cmd.colorMask = tcu::BVec4(false, false, true, false);
|
|
cmd.params.depth = depthSteps[ndx]+epsilon;
|
|
cmd.params.depthTestEnabled = true;
|
|
cmd.params.depthFunc = GL_LESS;
|
|
cmd.params.depthWriteMask = false;
|
|
|
|
commands.push_back(cmd);
|
|
}
|
|
}
|
|
|
|
void generateStencilVisualizeCommands (const TestRenderTarget& target, vector<RenderCommand>& commands)
|
|
{
|
|
const int numValues = 4*4;
|
|
float colorStep = 1.0f / numValues; // 0 is reserved for non-matching.
|
|
int stencilValues[numValues];
|
|
|
|
getStencilTestValues(target.stencilBits, numValues, &stencilValues[0]);
|
|
|
|
for (int ndx = 0; ndx < numValues; ndx++)
|
|
{
|
|
RenderCommand cmd;
|
|
|
|
cmd.params.visibleFace = rr::FACETYPE_FRONT;
|
|
cmd.rect = rr::WindowRectangle(0, 0, target.width, target.height);
|
|
cmd.color = Vec4(0.0f, colorStep*float(ndx+1), 0.0f, 0.0f);
|
|
cmd.colorMask = tcu::BVec4(false, true, false, false);
|
|
cmd.params.stencilTestEnabled = true;
|
|
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].function = GL_EQUAL;
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].reference = stencilValues[ndx];
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].compareMask = ~0u;
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].stencilFailOp = GL_KEEP;
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].depthFailOp = GL_KEEP;
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].depthPassOp = GL_KEEP;
|
|
cmd.params.stencil[rr::FACETYPE_FRONT].writeMask = 0u;
|
|
|
|
cmd.params.stencil[rr::FACETYPE_BACK] = cmd.params.stencil[rr::FACETYPE_FRONT];
|
|
|
|
commands.push_back(cmd);
|
|
}
|
|
}
|
|
|
|
void translateStencilState (const StencilParams& src, rr::StencilState& dst)
|
|
{
|
|
dst.func = sglr::rr_util::mapGLTestFunc(src.function);
|
|
dst.ref = src.reference;
|
|
dst.compMask = src.compareMask;
|
|
dst.sFail = sglr::rr_util::mapGLStencilOp(src.stencilFailOp);
|
|
dst.dpFail = sglr::rr_util::mapGLStencilOp(src.depthFailOp);
|
|
dst.dpPass = sglr::rr_util::mapGLStencilOp(src.depthPassOp);
|
|
dst.writeMask = src.writeMask;
|
|
}
|
|
|
|
void translateCommand (const RenderCommand& src, RefRenderCommand& dst, const TestRenderTarget& renderTarget)
|
|
{
|
|
const float far = 1.0f;
|
|
const float near = 0.0f;
|
|
bool hasDepth = renderTarget.depthBits > 0;
|
|
bool hasStencil = renderTarget.stencilBits > 0;
|
|
bool isFrontFacing = src.params.visibleFace == rr::FACETYPE_FRONT;
|
|
|
|
dst.quad.posA = IVec2(isFrontFacing ? src.rect.left : (src.rect.left+src.rect.width-1), src.rect.bottom);
|
|
dst.quad.posB = IVec2(isFrontFacing ? (src.rect.left+src.rect.width-1) : src.rect.left, src.rect.bottom+src.rect.height-1);
|
|
|
|
std::fill(DE_ARRAY_BEGIN(dst.quad.color), DE_ARRAY_END(dst.quad.color), src.color);
|
|
std::fill(DE_ARRAY_BEGIN(dst.quad.depth), DE_ARRAY_END(dst.quad.depth), ((far-near)/2.0f) * src.params.depth + (near+far)/2.0f);
|
|
|
|
dst.state.colorMask = src.colorMask;
|
|
|
|
dst.state.scissorTestEnabled = false;
|
|
dst.state.stencilTestEnabled = hasStencil && src.params.stencilTestEnabled;
|
|
dst.state.depthTestEnabled = hasDepth && src.params.depthTestEnabled;
|
|
dst.state.blendMode = rr::BLENDMODE_NONE;
|
|
dst.state.numStencilBits = renderTarget.stencilBits;
|
|
|
|
if (dst.state.depthTestEnabled)
|
|
{
|
|
dst.state.depthFunc = sglr::rr_util::mapGLTestFunc(src.params.depthFunc);
|
|
dst.state.depthMask = src.params.depthWriteMask;
|
|
}
|
|
|
|
if (dst.state.stencilTestEnabled)
|
|
{
|
|
translateStencilState(src.params.stencil[rr::FACETYPE_BACK], dst.state.stencilStates[rr::FACETYPE_BACK]);
|
|
translateStencilState(src.params.stencil[rr::FACETYPE_FRONT], dst.state.stencilStates[rr::FACETYPE_FRONT]);
|
|
}
|
|
}
|
|
|
|
void render (const vector<ClearCommand>& clears, int viewportX, int viewportY)
|
|
{
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
for (int ndx = 0; ndx < (int)clears.size(); ndx++)
|
|
{
|
|
const ClearCommand& clear = clears[ndx];
|
|
|
|
if (clear.buffers & GL_COLOR_BUFFER_BIT) glClearColor(clear.color.x(), clear.color.y(), clear.color.z(), clear.color.w());
|
|
if (clear.buffers & GL_STENCIL_BUFFER_BIT) glClearStencil(clear.stencil);
|
|
|
|
DE_ASSERT(clear.buffers == (clear.buffers & (GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT))); // \note Don't use clear for depths.
|
|
|
|
glScissor(clear.rect.left+viewportX, clear.rect.bottom+viewportY, clear.rect.width, clear.rect.height);
|
|
glClear(clear.buffers);
|
|
}
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
void render (gls::FragmentOpUtil::QuadRenderer& renderer, const RenderCommand& command, int viewportX, int viewportY)
|
|
{
|
|
if (command.params.stencilTestEnabled)
|
|
{
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
for (int face = 0; face < rr::FACETYPE_LAST; face++)
|
|
{
|
|
deUint32 glFace = face == rr::FACETYPE_BACK ? GL_BACK : GL_FRONT;
|
|
const StencilParams& sParams = command.params.stencil[face];
|
|
|
|
glStencilFuncSeparate(glFace, sParams.function, sParams.reference, sParams.compareMask);
|
|
glStencilOpSeparate(glFace, sParams.stencilFailOp, sParams.depthFailOp, sParams.depthPassOp);
|
|
glStencilMaskSeparate(glFace, sParams.writeMask);
|
|
}
|
|
}
|
|
else
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
if (command.params.depthTestEnabled)
|
|
{
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(command.params.depthFunc);
|
|
glDepthMask(command.params.depthWriteMask ? GL_TRUE : GL_FALSE);
|
|
}
|
|
else
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glColorMask(command.colorMask[0] ? GL_TRUE : GL_FALSE,
|
|
command.colorMask[1] ? GL_TRUE : GL_FALSE,
|
|
command.colorMask[2] ? GL_TRUE : GL_FALSE,
|
|
command.colorMask[3] ? GL_TRUE : GL_FALSE);
|
|
glViewport(command.rect.left+viewportX, command.rect.bottom+viewportY, command.rect.width, command.rect.height);
|
|
|
|
gls::FragmentOpUtil::Quad quad;
|
|
|
|
bool isFrontFacing = command.params.visibleFace == rr::FACETYPE_FRONT;
|
|
quad.posA = Vec2(isFrontFacing ? -1.0f : 1.0f, -1.0f);
|
|
quad.posB = Vec2(isFrontFacing ? 1.0f : -1.0f, 1.0f);
|
|
|
|
std::fill(DE_ARRAY_BEGIN(quad.color), DE_ARRAY_END(quad.color), command.color);
|
|
std::fill(DE_ARRAY_BEGIN(quad.depth), DE_ARRAY_END(quad.depth), command.params.depth);
|
|
|
|
renderer.render(quad);
|
|
GLU_CHECK();
|
|
}
|
|
|
|
void renderReference (const vector<ClearCommand>& clears, const tcu::PixelBufferAccess& dstColor, const tcu::PixelBufferAccess& dstStencil, int stencilBits)
|
|
{
|
|
for (int ndx = 0; ndx < (int)clears.size(); ndx++)
|
|
{
|
|
const ClearCommand& clear = clears[ndx];
|
|
|
|
if (clear.buffers & GL_COLOR_BUFFER_BIT)
|
|
tcu::clear(tcu::getSubregion(dstColor, clear.rect.left, clear.rect.bottom, clear.rect.width, clear.rect.height), clear.color);
|
|
|
|
if (clear.buffers & GL_STENCIL_BUFFER_BIT && stencilBits > 0)
|
|
{
|
|
int maskedVal = clear.stencil & ((1<<stencilBits)-1);
|
|
tcu::clearStencil(tcu::getSubregion(dstStencil, clear.rect.left, clear.rect.bottom, clear.rect.width, clear.rect.height), maskedVal);
|
|
}
|
|
|
|
DE_ASSERT(clear.buffers == (clear.buffers & (GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT))); // \note Don't use clear for depths.
|
|
}
|
|
}
|
|
|
|
} // DepthStencilCaseUtil
|
|
|
|
using namespace DepthStencilCaseUtil;
|
|
|
|
class DepthStencilCase : public TestCase
|
|
{
|
|
public:
|
|
DepthStencilCase (Context& context, const char* name, const char* desc, const std::vector<DepthStencilParams>& cases);
|
|
~DepthStencilCase (void);
|
|
|
|
void init (void);
|
|
void deinit (void);
|
|
|
|
IterateResult iterate (void);
|
|
|
|
private:
|
|
DepthStencilCase (const DepthStencilCase& other);
|
|
DepthStencilCase& operator= (const DepthStencilCase& other);
|
|
|
|
std::vector<DepthStencilParams> m_cases;
|
|
|
|
TestRenderTarget m_renderTarget;
|
|
std::vector<ClearCommand> m_baseClears;
|
|
std::vector<RenderCommand> m_baseDepthRenders;
|
|
std::vector<RenderCommand> m_visualizeCommands;
|
|
std::vector<RefRenderCommand> m_refBaseDepthRenders;
|
|
std::vector<RefRenderCommand> m_refVisualizeCommands;
|
|
|
|
gls::FragmentOpUtil::QuadRenderer* m_renderer;
|
|
tcu::Surface* m_refColorBuffer;
|
|
tcu::TextureLevel* m_refDepthBuffer;
|
|
tcu::TextureLevel* m_refStencilBuffer;
|
|
gls::FragmentOpUtil::ReferenceQuadRenderer* m_refRenderer;
|
|
|
|
int m_iterNdx;
|
|
};
|
|
|
|
DepthStencilCase::DepthStencilCase (Context& context, const char* name, const char* desc, const std::vector<DepthStencilParams>& cases)
|
|
: TestCase (context, name, desc)
|
|
, m_cases (cases)
|
|
, m_renderer (DE_NULL)
|
|
, m_refColorBuffer (DE_NULL)
|
|
, m_refDepthBuffer (DE_NULL)
|
|
, m_refStencilBuffer (DE_NULL)
|
|
, m_refRenderer (DE_NULL)
|
|
, m_iterNdx (0)
|
|
{
|
|
}
|
|
|
|
DepthStencilCase::~DepthStencilCase (void)
|
|
{
|
|
delete m_renderer;
|
|
delete m_refColorBuffer;
|
|
delete m_refDepthBuffer;
|
|
delete m_refStencilBuffer;
|
|
delete m_refRenderer;
|
|
}
|
|
|
|
void DepthStencilCase::init (void)
|
|
{
|
|
DE_ASSERT(!m_renderer && !m_refColorBuffer && !m_refDepthBuffer && !m_refStencilBuffer && !m_refRenderer);
|
|
|
|
// Compute render target.
|
|
int viewportW = de::min<int>(m_context.getRenderTarget().getWidth(), VIEWPORT_WIDTH);
|
|
int viewportH = de::min<int>(m_context.getRenderTarget().getHeight(), VIEWPORT_HEIGHT);
|
|
m_renderTarget = TestRenderTarget(viewportW, viewportH, m_context.getRenderTarget().getDepthBits(), m_context.getRenderTarget().getStencilBits());
|
|
|
|
// Compute base clears & visualization commands.
|
|
generateBaseClearAndDepthCommands(m_renderTarget, m_baseClears, m_baseDepthRenders);
|
|
generateDepthVisualizeCommands(m_renderTarget, m_visualizeCommands);
|
|
generateStencilVisualizeCommands(m_renderTarget, m_visualizeCommands);
|
|
|
|
// Translate to ref commands.
|
|
m_refBaseDepthRenders.resize(m_baseDepthRenders.size());
|
|
for (int ndx = 0; ndx < (int)m_baseDepthRenders.size(); ndx++)
|
|
translateCommand(m_baseDepthRenders[ndx], m_refBaseDepthRenders[ndx], m_renderTarget);
|
|
|
|
m_refVisualizeCommands.resize(m_visualizeCommands.size());
|
|
for (int ndx = 0; ndx < (int)m_visualizeCommands.size(); ndx++)
|
|
translateCommand(m_visualizeCommands[ndx], m_refVisualizeCommands[ndx], m_renderTarget);
|
|
|
|
m_renderer = new gls::FragmentOpUtil::QuadRenderer(m_context.getRenderContext(), glu::GLSL_VERSION_300_ES);
|
|
m_refColorBuffer = new tcu::Surface(viewportW, viewportH);
|
|
m_refDepthBuffer = new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT), viewportW, viewportH);
|
|
m_refStencilBuffer = new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32), viewportW, viewportH);
|
|
m_refRenderer = new gls::FragmentOpUtil::ReferenceQuadRenderer();
|
|
|
|
m_iterNdx = 0;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
}
|
|
|
|
void DepthStencilCase::deinit (void)
|
|
{
|
|
delete m_renderer;
|
|
delete m_refColorBuffer;
|
|
delete m_refDepthBuffer;
|
|
delete m_refStencilBuffer;
|
|
delete m_refRenderer;
|
|
|
|
m_renderer = DE_NULL;
|
|
m_refColorBuffer = DE_NULL;
|
|
m_refDepthBuffer = DE_NULL;
|
|
m_refStencilBuffer = DE_NULL;
|
|
m_refRenderer = DE_NULL;
|
|
|
|
m_baseClears.clear();
|
|
m_baseDepthRenders.clear();
|
|
m_visualizeCommands.clear();
|
|
m_refBaseDepthRenders.clear();
|
|
m_refVisualizeCommands.clear();
|
|
}
|
|
|
|
DepthStencilCase::IterateResult DepthStencilCase::iterate (void)
|
|
{
|
|
de::Random rnd (deStringHash(getName()) ^ deInt32Hash(m_iterNdx));
|
|
int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth()-m_renderTarget.width);
|
|
int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight()-m_renderTarget.height);
|
|
RenderCommand testCmd;
|
|
|
|
tcu::Surface renderedImg (m_renderTarget.width, m_renderTarget.height);
|
|
tcu::RGBA threshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold();
|
|
|
|
// Fill in test command for this iteration.
|
|
testCmd.color = Vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
|
testCmd.colorMask = tcu::BVec4(true);
|
|
testCmd.rect = rr::WindowRectangle(0, 0, m_renderTarget.width, m_renderTarget.height);
|
|
testCmd.params = m_cases[m_iterNdx];
|
|
|
|
if (m_iterNdx == 0)
|
|
{
|
|
m_testCtx.getLog() << TestLog::Message << "Channels:\n"
|
|
" RED: passing pixels\n"
|
|
" GREEN: stencil values\n"
|
|
" BLUE: depth values"
|
|
<< TestLog::EndMessage;
|
|
}
|
|
|
|
if (m_cases.size() > 1)
|
|
m_testCtx.getLog() << TestLog::Message << "Iteration " << m_iterNdx << "..." << TestLog::EndMessage;
|
|
|
|
m_testCtx.getLog() << m_cases[m_iterNdx];
|
|
|
|
// Submit render commands to gl GL.
|
|
|
|
// Base clears.
|
|
render(m_baseClears, viewportX, viewportY);
|
|
|
|
// Base depths.
|
|
for (vector<RenderCommand>::const_iterator cmd = m_baseDepthRenders.begin(); cmd != m_baseDepthRenders.end(); ++cmd)
|
|
render(*m_renderer, *cmd, viewportX, viewportY);
|
|
|
|
// Test command.
|
|
render(*m_renderer, testCmd, viewportX, viewportY);
|
|
|
|
// Visualization commands.
|
|
for (vector<RenderCommand>::const_iterator cmd = m_visualizeCommands.begin(); cmd != m_visualizeCommands.end(); ++cmd)
|
|
render(*m_renderer, *cmd, viewportX, viewportY);
|
|
|
|
// Re-enable all write masks.
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDepthMask(GL_TRUE);
|
|
glStencilMask(~0u);
|
|
|
|
// Ask GPU to start rendering.
|
|
glFlush();
|
|
|
|
// Render reference while GPU is doing work.
|
|
{
|
|
RefRenderCommand refTestCmd;
|
|
translateCommand(testCmd, refTestCmd, m_renderTarget);
|
|
|
|
// Base clears.
|
|
renderReference(m_baseClears, m_refColorBuffer->getAccess(), m_refStencilBuffer->getAccess(), m_renderTarget.stencilBits);
|
|
|
|
// Base depths.
|
|
for (vector<RefRenderCommand>::const_iterator cmd = m_refBaseDepthRenders.begin(); cmd != m_refBaseDepthRenders.end(); ++cmd)
|
|
m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
|
|
gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
|
|
gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
|
|
cmd->quad, cmd->state);
|
|
|
|
// Test command.
|
|
m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
|
|
gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
|
|
gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
|
|
refTestCmd.quad, refTestCmd.state);
|
|
|
|
// Visualization commands.
|
|
for (vector<RefRenderCommand>::const_iterator cmd = m_refVisualizeCommands.begin(); cmd != m_refVisualizeCommands.end(); ++cmd)
|
|
m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
|
|
gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
|
|
gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
|
|
cmd->quad, cmd->state);
|
|
}
|
|
|
|
// Read rendered image.
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
|
|
|
|
m_iterNdx += 1;
|
|
|
|
// Compare to reference.
|
|
bool isLastIter = m_iterNdx >= (int)m_cases.size();
|
|
bool compareOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", *m_refColorBuffer, renderedImg, threshold,
|
|
tcu::COMPARE_LOG_RESULT);
|
|
|
|
m_testCtx.getLog() << TestLog::Message << (compareOk ? " Passed." : " FAILED!") << TestLog::EndMessage;
|
|
if (!compareOk)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
|
|
|
|
if (compareOk && !isLastIter)
|
|
return CONTINUE;
|
|
else
|
|
return STOP;
|
|
}
|
|
|
|
DepthStencilTests::DepthStencilTests (Context& context)
|
|
: TestCaseGroup(context, "depth_stencil", "Depth and Stencil Op Tests")
|
|
{
|
|
}
|
|
|
|
DepthStencilTests::~DepthStencilTests (void)
|
|
{
|
|
}
|
|
|
|
static void randomDepthStencilState (de::Random& rnd, DepthStencilParams& params)
|
|
{
|
|
const float stencilTestProbability = 0.8f;
|
|
const float depthTestProbability = 0.7f;
|
|
|
|
static const deUint32 compareFuncs[] =
|
|
{
|
|
GL_NEVER,
|
|
GL_ALWAYS,
|
|
GL_LESS,
|
|
GL_LEQUAL,
|
|
GL_EQUAL,
|
|
GL_GEQUAL,
|
|
GL_GREATER,
|
|
GL_NOTEQUAL
|
|
};
|
|
|
|
static const deUint32 stencilOps[] =
|
|
{
|
|
GL_KEEP,
|
|
GL_ZERO,
|
|
GL_REPLACE,
|
|
GL_INCR,
|
|
GL_DECR,
|
|
GL_INVERT,
|
|
GL_INCR_WRAP,
|
|
GL_DECR_WRAP
|
|
};
|
|
|
|
static const float depthValues[] = { -1.0f, -0.8f, -0.6f, -0.4f, -0.2f, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
|
|
|
|
params.visibleFace = rnd.getBool() ? rr::FACETYPE_FRONT : rr::FACETYPE_BACK;
|
|
params.stencilTestEnabled = rnd.getFloat() < stencilTestProbability;
|
|
params.depthTestEnabled = !params.stencilTestEnabled || (rnd.getFloat() < depthTestProbability);
|
|
|
|
if (params.stencilTestEnabled)
|
|
{
|
|
for (int ndx = 0; ndx < 2; ndx++)
|
|
{
|
|
params.stencil[ndx].function = rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
|
|
params.stencil[ndx].reference = rnd.getInt(-2, 260);
|
|
params.stencil[ndx].compareMask = rnd.getUint32();
|
|
params.stencil[ndx].stencilFailOp = rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
|
|
params.stencil[ndx].depthFailOp = rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
|
|
params.stencil[ndx].depthPassOp = rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
|
|
params.stencil[ndx].writeMask = rnd.getUint32();
|
|
}
|
|
}
|
|
|
|
if (params.depthTestEnabled)
|
|
{
|
|
params.depthFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
|
|
params.depth = rnd.choose<float>(DE_ARRAY_BEGIN(depthValues), DE_ARRAY_END(depthValues));
|
|
params.depthWriteMask = rnd.getBool();
|
|
}
|
|
}
|
|
|
|
void DepthStencilTests::init (void)
|
|
{
|
|
static const struct
|
|
{
|
|
const char* name;
|
|
deUint32 func;
|
|
} compareFuncs[] =
|
|
{
|
|
{ "never", GL_NEVER },
|
|
{ "always", GL_ALWAYS },
|
|
{ "less", GL_LESS },
|
|
{ "lequal", GL_LEQUAL },
|
|
{ "equal", GL_EQUAL },
|
|
{ "gequal", GL_GEQUAL },
|
|
{ "greater", GL_GREATER },
|
|
{ "notequal", GL_NOTEQUAL }
|
|
};
|
|
|
|
static const struct
|
|
{
|
|
const char* name;
|
|
deUint32 op;
|
|
} stencilOps[] =
|
|
{
|
|
{ "keep", GL_KEEP },
|
|
{ "zero", GL_ZERO },
|
|
{ "replace", GL_REPLACE },
|
|
{ "incr", GL_INCR },
|
|
{ "decr", GL_DECR },
|
|
{ "invert", GL_INVERT },
|
|
{ "incr_wrap", GL_INCR_WRAP },
|
|
{ "decr_wrap", GL_DECR_WRAP }
|
|
};
|
|
|
|
static const struct
|
|
{
|
|
rr::FaceType visibleFace;
|
|
deUint32 sFail;
|
|
deUint32 dFail;
|
|
deUint32 dPass;
|
|
int stencilRef;
|
|
deUint32 compareMask;
|
|
deUint32 writeMask;
|
|
float depth;
|
|
} functionCases[] =
|
|
{
|
|
{ rr::FACETYPE_BACK, GL_DECR, GL_INCR, GL_INVERT, 4, ~0u, ~0u, -0.7f },
|
|
{ rr::FACETYPE_FRONT, GL_DECR, GL_INCR, GL_INVERT, 2, ~0u, ~0u, 0.0f },
|
|
{ rr::FACETYPE_BACK, GL_DECR, GL_INCR, GL_INVERT, 1, ~0u, ~0u, 0.2f },
|
|
{ rr::FACETYPE_FRONT, GL_DECR_WRAP, GL_INVERT, GL_REPLACE, 4, ~0u, ~0u, 1.0f }
|
|
};
|
|
|
|
// All combinations of depth stencil functions.
|
|
{
|
|
tcu::TestCaseGroup* functionsGroup = new tcu::TestCaseGroup(m_testCtx, "stencil_depth_funcs", "Combinations of Depth and Stencil Functions");
|
|
addChild(functionsGroup);
|
|
|
|
for (int stencilFunc = 0; stencilFunc < DE_LENGTH_OF_ARRAY(compareFuncs)+1; stencilFunc++)
|
|
{
|
|
// One extra: depth test disabled.
|
|
for (int depthFunc = 0; depthFunc < DE_LENGTH_OF_ARRAY(compareFuncs)+1; depthFunc++)
|
|
{
|
|
DepthStencilParams params;
|
|
ostringstream name;
|
|
bool hasStencilFunc = de::inBounds(stencilFunc, 0, DE_LENGTH_OF_ARRAY(compareFuncs));
|
|
bool hasDepthFunc = de::inBounds(depthFunc, 0, DE_LENGTH_OF_ARRAY(compareFuncs));
|
|
|
|
if (hasStencilFunc)
|
|
name << "stencil_" << compareFuncs[stencilFunc].name << "_";
|
|
else
|
|
name << "no_stencil_";
|
|
|
|
if (hasDepthFunc)
|
|
name << "depth_" << compareFuncs[depthFunc].name;
|
|
else
|
|
name << "no_depth";
|
|
|
|
params.depthFunc = hasDepthFunc ? compareFuncs[depthFunc].func : 0;
|
|
params.depthTestEnabled = hasDepthFunc;
|
|
params.depthWriteMask = true;
|
|
|
|
params.stencilTestEnabled = hasStencilFunc;
|
|
|
|
vector<DepthStencilParams> cases;
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(functionCases); ndx++)
|
|
{
|
|
rr::FaceType visible = functionCases[ndx].visibleFace;
|
|
rr::FaceType notVisible = visible == rr::FACETYPE_FRONT ? rr::FACETYPE_BACK : rr::FACETYPE_FRONT;
|
|
|
|
params.depth = functionCases[ndx].depth;
|
|
params.visibleFace = visible;
|
|
|
|
params.stencil[visible].function = hasStencilFunc ? compareFuncs[stencilFunc].func : 0;
|
|
params.stencil[visible].reference = functionCases[ndx].stencilRef;
|
|
params.stencil[visible].stencilFailOp = functionCases[ndx].sFail;
|
|
params.stencil[visible].depthFailOp = functionCases[ndx].dFail;
|
|
params.stencil[visible].depthPassOp = functionCases[ndx].dPass;
|
|
params.stencil[visible].compareMask = functionCases[ndx].compareMask;
|
|
params.stencil[visible].writeMask = functionCases[ndx].writeMask;
|
|
|
|
params.stencil[notVisible].function = GL_ALWAYS;
|
|
params.stencil[notVisible].reference = 0;
|
|
params.stencil[notVisible].stencilFailOp = GL_REPLACE;
|
|
params.stencil[notVisible].depthFailOp = GL_REPLACE;
|
|
params.stencil[notVisible].depthPassOp = GL_REPLACE;
|
|
params.stencil[notVisible].compareMask = 0u;
|
|
params.stencil[notVisible].writeMask = ~0u;
|
|
|
|
|
|
cases.push_back(params);
|
|
}
|
|
|
|
functionsGroup->addChild(new DepthStencilCase(m_context, name.str().c_str(), "", cases));
|
|
}
|
|
}
|
|
}
|
|
|
|
static const struct
|
|
{
|
|
rr::FaceType visibleFace;
|
|
deUint32 func;
|
|
int ref;
|
|
deUint32 compareMask;
|
|
deUint32 writeMask;
|
|
} opCombinationCases[] =
|
|
{
|
|
{ rr::FACETYPE_BACK, GL_LESS, 4, ~0u, ~0u },
|
|
{ rr::FACETYPE_FRONT, GL_GREATER, 2, ~0u, ~0u },
|
|
{ rr::FACETYPE_BACK, GL_EQUAL, 3, ~2u, ~0u },
|
|
{ rr::FACETYPE_FRONT, GL_NOTEQUAL, 1, ~0u, ~1u }
|
|
};
|
|
|
|
// All combinations of stencil ops.
|
|
{
|
|
tcu::TestCaseGroup* opCombinationGroup = new tcu::TestCaseGroup(m_testCtx, "stencil_ops", "Stencil Op Combinations");
|
|
addChild(opCombinationGroup);
|
|
|
|
for (int sFail = 0; sFail < DE_LENGTH_OF_ARRAY(stencilOps); sFail++)
|
|
{
|
|
for (int dFail = 0; dFail < DE_LENGTH_OF_ARRAY(stencilOps); dFail++)
|
|
{
|
|
for (int dPass = 0; dPass < DE_LENGTH_OF_ARRAY(stencilOps); dPass++)
|
|
{
|
|
DepthStencilParams params;
|
|
ostringstream name;
|
|
|
|
name << stencilOps[sFail].name << "_" << stencilOps[dFail].name << "_" << stencilOps[dPass].name;
|
|
|
|
params.depthFunc = GL_LEQUAL;
|
|
params.depth = 0.0f;
|
|
params.depthTestEnabled = true;
|
|
params.depthWriteMask = true;
|
|
|
|
params.stencilTestEnabled = true;
|
|
|
|
vector<DepthStencilParams> cases;
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(opCombinationCases); ndx++)
|
|
{
|
|
rr::FaceType visible = opCombinationCases[ndx].visibleFace;
|
|
rr::FaceType notVisible = visible == rr::FACETYPE_FRONT ? rr::FACETYPE_BACK : rr::FACETYPE_FRONT;
|
|
|
|
params.visibleFace = visible;
|
|
|
|
params.stencil[visible].function = opCombinationCases[ndx].func;
|
|
params.stencil[visible].reference = opCombinationCases[ndx].ref;
|
|
params.stencil[visible].stencilFailOp = stencilOps[sFail].op;
|
|
params.stencil[visible].depthFailOp = stencilOps[dFail].op;
|
|
params.stencil[visible].depthPassOp = stencilOps[dPass].op;
|
|
params.stencil[visible].compareMask = opCombinationCases[ndx].compareMask;
|
|
params.stencil[visible].writeMask = opCombinationCases[ndx].writeMask;
|
|
|
|
params.stencil[notVisible].function = GL_ALWAYS;
|
|
params.stencil[notVisible].reference = 0;
|
|
params.stencil[notVisible].stencilFailOp = GL_REPLACE;
|
|
params.stencil[notVisible].depthFailOp = GL_REPLACE;
|
|
params.stencil[notVisible].depthPassOp = GL_REPLACE;
|
|
params.stencil[notVisible].compareMask = 0u;
|
|
params.stencil[notVisible].writeMask = ~0u;
|
|
|
|
|
|
cases.push_back(params);
|
|
}
|
|
|
|
opCombinationGroup->addChild(new DepthStencilCase(m_context, name.str().c_str(), "", cases));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write masks
|
|
{
|
|
tcu::TestCaseGroup* writeMaskGroup = new tcu::TestCaseGroup(m_testCtx, "write_mask", "Depth and Stencil Write Masks");
|
|
addChild(writeMaskGroup);
|
|
|
|
// Depth mask
|
|
{
|
|
DepthStencilParams params;
|
|
|
|
params.depthFunc = GL_LEQUAL;
|
|
params.depth = 0.0f;
|
|
params.depthTestEnabled = true;
|
|
params.stencilTestEnabled = true;
|
|
|
|
params.stencil[rr::FACETYPE_FRONT].function = GL_NOTEQUAL;
|
|
params.stencil[rr::FACETYPE_FRONT].reference = 1;
|
|
params.stencil[rr::FACETYPE_FRONT].stencilFailOp = GL_INVERT;
|
|
params.stencil[rr::FACETYPE_FRONT].depthFailOp = GL_INCR;
|
|
params.stencil[rr::FACETYPE_FRONT].depthPassOp = GL_DECR;
|
|
params.stencil[rr::FACETYPE_FRONT].compareMask = ~0u;
|
|
params.stencil[rr::FACETYPE_FRONT].writeMask = ~0u;
|
|
|
|
params.stencil[rr::FACETYPE_BACK].function = GL_ALWAYS;
|
|
params.stencil[rr::FACETYPE_BACK].reference = 0;
|
|
params.stencil[rr::FACETYPE_BACK].stencilFailOp = GL_REPLACE;
|
|
params.stencil[rr::FACETYPE_BACK].depthFailOp = GL_INVERT;
|
|
params.stencil[rr::FACETYPE_BACK].depthPassOp = GL_INCR;
|
|
params.stencil[rr::FACETYPE_BACK].compareMask = ~0u;
|
|
params.stencil[rr::FACETYPE_BACK].writeMask = ~0u;
|
|
|
|
vector<DepthStencilParams> cases;
|
|
|
|
// Case 1: front, depth write enabled
|
|
params.visibleFace = rr::FACETYPE_FRONT;
|
|
params.depthWriteMask = true;
|
|
cases.push_back(params);
|
|
|
|
// Case 2: front, depth write disabled
|
|
params.visibleFace = rr::FACETYPE_FRONT;
|
|
params.depthWriteMask = false;
|
|
cases.push_back(params);
|
|
|
|
// Case 3: back, depth write enabled
|
|
params.visibleFace = rr::FACETYPE_BACK;
|
|
params.depthWriteMask = true;
|
|
cases.push_back(params);
|
|
|
|
// Case 4: back, depth write disabled
|
|
params.visibleFace = rr::FACETYPE_BACK;
|
|
params.depthWriteMask = false;
|
|
cases.push_back(params);
|
|
|
|
writeMaskGroup->addChild(new DepthStencilCase(m_context, "depth", "Depth Write Mask", cases));
|
|
}
|
|
|
|
// Stencil write masks.
|
|
{
|
|
static const struct
|
|
{
|
|
rr::FaceType visibleFace;
|
|
deUint32 frontWriteMask;
|
|
deUint32 backWriteMask;
|
|
} stencilWmaskCases[] =
|
|
{
|
|
{ rr::FACETYPE_FRONT, ~0u, 0u },
|
|
{ rr::FACETYPE_FRONT, 0u, ~0u },
|
|
{ rr::FACETYPE_FRONT, 0xfu, 0xf0u },
|
|
{ rr::FACETYPE_FRONT, 0x2u, 0x4u },
|
|
{ rr::FACETYPE_BACK, 0u, ~0u },
|
|
{ rr::FACETYPE_BACK, ~0u, 0u },
|
|
{ rr::FACETYPE_BACK, 0xf0u, 0xfu },
|
|
{ rr::FACETYPE_BACK, 0x4u, 0x2u }
|
|
};
|
|
|
|
DepthStencilParams params;
|
|
|
|
params.depthFunc = GL_LEQUAL;
|
|
params.depth = 0.0f;
|
|
params.depthTestEnabled = true;
|
|
params.depthWriteMask = true;
|
|
params.stencilTestEnabled = true;
|
|
|
|
params.stencil[rr::FACETYPE_FRONT].function = GL_NOTEQUAL;
|
|
params.stencil[rr::FACETYPE_FRONT].reference = 1;
|
|
params.stencil[rr::FACETYPE_FRONT].stencilFailOp = GL_INVERT;
|
|
params.stencil[rr::FACETYPE_FRONT].depthFailOp = GL_INCR;
|
|
params.stencil[rr::FACETYPE_FRONT].depthPassOp = GL_DECR;
|
|
params.stencil[rr::FACETYPE_FRONT].compareMask = ~0u;
|
|
|
|
params.stencil[rr::FACETYPE_BACK].function = GL_ALWAYS;
|
|
params.stencil[rr::FACETYPE_BACK].reference = 0;
|
|
params.stencil[rr::FACETYPE_BACK].stencilFailOp = GL_REPLACE;
|
|
params.stencil[rr::FACETYPE_BACK].depthFailOp = GL_INVERT;
|
|
params.stencil[rr::FACETYPE_BACK].depthPassOp = GL_INCR;
|
|
params.stencil[rr::FACETYPE_BACK].compareMask = ~0u;
|
|
|
|
vector<DepthStencilParams> cases;
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilWmaskCases); ndx++)
|
|
{
|
|
params.visibleFace = stencilWmaskCases[ndx].visibleFace;
|
|
params.stencil[rr::FACETYPE_FRONT].writeMask = stencilWmaskCases[ndx].frontWriteMask;
|
|
params.stencil[rr::FACETYPE_BACK].writeMask = stencilWmaskCases[ndx].backWriteMask;
|
|
cases.push_back(params);
|
|
}
|
|
|
|
writeMaskGroup->addChild(new DepthStencilCase(m_context, "stencil", "Stencil Write Mask", cases));
|
|
}
|
|
|
|
// Depth & stencil write masks.
|
|
{
|
|
static const struct
|
|
{
|
|
bool depthWriteMask;
|
|
rr::FaceType visibleFace;
|
|
deUint32 frontWriteMask;
|
|
deUint32 backWriteMask;
|
|
} depthStencilWmaskCases[] =
|
|
{
|
|
{ false, rr::FACETYPE_FRONT, ~0u, 0u },
|
|
{ false, rr::FACETYPE_FRONT, 0u, ~0u },
|
|
{ false, rr::FACETYPE_FRONT, 0xfu, 0xf0u },
|
|
{ true, rr::FACETYPE_FRONT, ~0u, 0u },
|
|
{ true, rr::FACETYPE_FRONT, 0u, ~0u },
|
|
{ true, rr::FACETYPE_FRONT, 0xfu, 0xf0u },
|
|
{ false, rr::FACETYPE_BACK, 0u, ~0u },
|
|
{ false, rr::FACETYPE_BACK, ~0u, 0u },
|
|
{ false, rr::FACETYPE_BACK, 0xf0u, 0xfu },
|
|
{ true, rr::FACETYPE_BACK, 0u, ~0u },
|
|
{ true, rr::FACETYPE_BACK, ~0u, 0u },
|
|
{ true, rr::FACETYPE_BACK, 0xf0u, 0xfu }
|
|
};
|
|
|
|
DepthStencilParams params;
|
|
|
|
params.depthFunc = GL_LEQUAL;
|
|
params.depth = 0.0f;
|
|
params.depthTestEnabled = true;
|
|
params.depthWriteMask = true;
|
|
params.stencilTestEnabled = true;
|
|
|
|
params.stencil[rr::FACETYPE_FRONT].function = GL_NOTEQUAL;
|
|
params.stencil[rr::FACETYPE_FRONT].reference = 1;
|
|
params.stencil[rr::FACETYPE_FRONT].stencilFailOp = GL_INVERT;
|
|
params.stencil[rr::FACETYPE_FRONT].depthFailOp = GL_INCR;
|
|
params.stencil[rr::FACETYPE_FRONT].depthPassOp = GL_DECR;
|
|
params.stencil[rr::FACETYPE_FRONT].compareMask = ~0u;
|
|
|
|
params.stencil[rr::FACETYPE_BACK].function = GL_ALWAYS;
|
|
params.stencil[rr::FACETYPE_BACK].reference = 0;
|
|
params.stencil[rr::FACETYPE_BACK].stencilFailOp = GL_REPLACE;
|
|
params.stencil[rr::FACETYPE_BACK].depthFailOp = GL_INVERT;
|
|
params.stencil[rr::FACETYPE_BACK].depthPassOp = GL_INCR;
|
|
params.stencil[rr::FACETYPE_BACK].compareMask = ~0u;
|
|
|
|
vector<DepthStencilParams> cases;
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthStencilWmaskCases); ndx++)
|
|
{
|
|
params.depthWriteMask = depthStencilWmaskCases[ndx].depthWriteMask;
|
|
params.visibleFace = depthStencilWmaskCases[ndx].visibleFace;
|
|
params.stencil[rr::FACETYPE_FRONT].writeMask = depthStencilWmaskCases[ndx].frontWriteMask;
|
|
params.stencil[rr::FACETYPE_BACK].writeMask = depthStencilWmaskCases[ndx].backWriteMask;
|
|
cases.push_back(params);
|
|
}
|
|
|
|
writeMaskGroup->addChild(new DepthStencilCase(m_context, "both", "Depth and Stencil Write Masks", cases));
|
|
}
|
|
}
|
|
|
|
// Randomized cases
|
|
{
|
|
tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized Depth and Stencil Test Cases");
|
|
addChild(randomGroup);
|
|
|
|
for (int caseNdx = 0; caseNdx < NUM_RANDOM_CASES; caseNdx++)
|
|
{
|
|
vector<DepthStencilParams> subCases (NUM_RANDOM_SUB_CASES);
|
|
de::Random rnd (deInt32Hash(caseNdx) ^ deInt32Hash(m_testCtx.getCommandLine().getBaseSeed()));
|
|
|
|
for (vector<DepthStencilParams>::iterator iter = subCases.begin(); iter != subCases.end(); ++iter)
|
|
randomDepthStencilState(rnd, *iter);
|
|
|
|
randomGroup->addChild(new DepthStencilCase(m_context, de::toString(caseNdx).c_str(), "", subCases));
|
|
}
|
|
}
|
|
}
|
|
|
|
} // Functional
|
|
} // gles3
|
|
} // deqp
|