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.
927 lines
28 KiB
927 lines
28 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL (ES) 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 GLES Scissor tests
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "glsScissorTests.hpp"
|
|
#include "glsTextureTestUtil.hpp"
|
|
|
|
#include "deMath.h"
|
|
#include "deRandom.hpp"
|
|
#include "deUniquePtr.hpp"
|
|
|
|
#include "tcuTestCase.hpp"
|
|
#include "tcuImageCompare.hpp"
|
|
#include "tcuVector.hpp"
|
|
#include "tcuVectorUtil.hpp"
|
|
#include "tcuTexture.hpp"
|
|
#include "tcuStringTemplate.hpp"
|
|
|
|
#include "gluStrUtil.hpp"
|
|
#include "gluDrawUtil.hpp"
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "gluObjectWrapper.hpp"
|
|
|
|
#include "glwEnums.hpp"
|
|
#include "glwFunctions.hpp"
|
|
|
|
#include <map>
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gls
|
|
{
|
|
namespace Functional
|
|
{
|
|
namespace
|
|
{
|
|
|
|
using namespace ScissorTestInternal;
|
|
using namespace glw; // GL types
|
|
|
|
using tcu::ConstPixelBufferAccess;
|
|
using tcu::PixelBufferAccess;
|
|
using tcu::TestLog;
|
|
|
|
using std::vector;
|
|
using std::string;
|
|
using std::map;
|
|
using tcu::Vec3;
|
|
using tcu::Vec4;
|
|
using tcu::IVec4;
|
|
using tcu::UVec4;
|
|
|
|
void drawQuad (const glw::Functions& gl, deUint32 program, const Vec3& p0, const Vec3& p1)
|
|
{
|
|
// Vertex data.
|
|
const float hz = (p0.z() + p1.z()) * 0.5f;
|
|
const float position[] =
|
|
{
|
|
p0.x(), p0.y(), p0.z(), 1.0f,
|
|
p0.x(), p1.y(), hz, 1.0f,
|
|
p1.x(), p0.y(), hz, 1.0f,
|
|
p1.x(), p1.y(), p1.z(), 1.0f
|
|
};
|
|
|
|
const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
|
|
|
|
const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
|
|
|
|
gl.useProgram(program);
|
|
gl.enableVertexAttribArray(posLoc);
|
|
gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
|
|
|
|
gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
|
|
|
|
gl.disableVertexAttribArray(posLoc);
|
|
|
|
}
|
|
|
|
void drawPrimitives (const glw::Functions& gl, deUint32 program, const deUint32 type, const vector<float>& vertices, const vector<deUint16>& indices)
|
|
{
|
|
const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
|
|
|
|
TCU_CHECK(posLoc >= 0);
|
|
|
|
gl.useProgram(program);
|
|
gl.enableVertexAttribArray(posLoc);
|
|
gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]);
|
|
|
|
gl.drawElements(type, GLsizei(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
|
|
|
|
gl.disableVertexAttribArray(posLoc);
|
|
}
|
|
|
|
template<typename T>
|
|
void clearEdges (const tcu::PixelBufferAccess& access, const T& color, const IVec4& scissorArea)
|
|
{
|
|
for (int y = 0; y < access.getHeight(); y++)
|
|
for (int x = 0; x < access.getWidth(); x++)
|
|
{
|
|
if (y < scissorArea.y() ||
|
|
y >= scissorArea.y() + scissorArea.w() ||
|
|
x < scissorArea.x() ||
|
|
x >= scissorArea.x()+ scissorArea.z())
|
|
access.setPixel(color, x, y);
|
|
}
|
|
}
|
|
|
|
glu::ProgramSources genShaders(glu::GLSLVersion version, bool isPoint)
|
|
{
|
|
string vtxSource;
|
|
|
|
if (isPoint)
|
|
{
|
|
vtxSource = "${VERSION}\n"
|
|
"${IN} highp vec4 a_position;\n"
|
|
"void main(){\n"
|
|
" gl_Position = a_position;\n"
|
|
" gl_PointSize = 1.0;\n"
|
|
"}\n";
|
|
}
|
|
else
|
|
{
|
|
vtxSource = "${VERSION}\n"
|
|
"${IN} highp vec4 a_position;\n"
|
|
"void main(){\n"
|
|
" gl_Position = a_position;\n"
|
|
"}\n";
|
|
}
|
|
|
|
const string frgSource = "${VERSION}\n"
|
|
"${OUT_DECL}"
|
|
"uniform highp vec4 u_color;\n"
|
|
"void main(){\n"
|
|
" ${OUTPUT} = u_color;\n"
|
|
"}\n";
|
|
|
|
map<string, string> params;
|
|
|
|
switch(version)
|
|
{
|
|
case glu::GLSL_VERSION_100_ES:
|
|
params["VERSION"] = "#version 100";
|
|
params["IN"] = "attribute";
|
|
params["OUT_DECL"] = "";
|
|
params["OUTPUT"] = "gl_FragColor";
|
|
break;
|
|
|
|
case glu::GLSL_VERSION_300_ES:
|
|
case glu::GLSL_VERSION_310_ES: // Assumed to support 3.0
|
|
params["VERSION"] = "#version 300 es";
|
|
params["IN"] = "in";
|
|
params["OUT_DECL"] = "out mediump vec4 f_color;\n";
|
|
params["OUTPUT"] = "f_color";
|
|
break;
|
|
|
|
default:
|
|
DE_FATAL("Unsupported version");
|
|
}
|
|
|
|
return glu::makeVtxFragSources(tcu::StringTemplate(vtxSource).specialize(params), tcu::StringTemplate(frgSource).specialize(params));
|
|
}
|
|
|
|
// Wrapper class, provides iterator & reporting logic
|
|
class ScissorCase : public tcu::TestCase
|
|
{
|
|
public:
|
|
ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea);
|
|
virtual ~ScissorCase (void) {}
|
|
|
|
virtual IterateResult iterate (void);
|
|
|
|
protected:
|
|
virtual void render (GLuint program, const IVec4& viewport) const = 0;
|
|
|
|
// Initialize gl_PointSize to 1.0f when drawing points, or the point size is undefined according to spec.
|
|
virtual bool isPoint (void) const = 0;
|
|
|
|
glu::RenderContext& m_renderCtx;
|
|
const Vec4 m_scissorArea;
|
|
};
|
|
|
|
ScissorCase::ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea)
|
|
: TestCase (testCtx, name, desc)
|
|
, m_renderCtx (renderCtx)
|
|
, m_scissorArea (scissorArea)
|
|
{
|
|
}
|
|
|
|
ScissorCase::IterateResult ScissorCase::iterate (void)
|
|
{
|
|
using TextureTestUtil::RandomViewport;
|
|
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
TestLog& log = m_testCtx.getLog();
|
|
const tcu::PixelFormat renderFormat = m_renderCtx.getRenderTarget().getPixelFormat();
|
|
const tcu::Vec4 threshold = 0.02f * UVec4(1u << de::max(0, 8 - renderFormat.redBits),
|
|
1u << de::max(0, 8 - renderFormat.greenBits),
|
|
1u << de::max(0, 8 - renderFormat.blueBits),
|
|
1u << de::max(0, 8 - renderFormat.alphaBits)).asFloat();
|
|
const glu::ShaderProgram shader (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType()), isPoint()));
|
|
|
|
const RandomViewport viewport (m_renderCtx.getRenderTarget(), 256, 256, deStringHash(getName()));
|
|
const IVec4 relScissorArea (int(m_scissorArea.x() * (float)viewport.width),
|
|
int(m_scissorArea.y() * (float)viewport.height),
|
|
int(m_scissorArea.z() * (float)viewport.width),
|
|
int(m_scissorArea.w() * (float)viewport.height));
|
|
const IVec4 absScissorArea (relScissorArea.x() + viewport.x,
|
|
relScissorArea.y() + viewport.y,
|
|
relScissorArea.z(),
|
|
relScissorArea.w());
|
|
|
|
tcu::Surface refImage (viewport.width, viewport.height);
|
|
tcu::Surface resImage (viewport.width, viewport.height);
|
|
|
|
if (!shader.isOk())
|
|
{
|
|
log << shader;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
|
|
return STOP;
|
|
}
|
|
|
|
log << TestLog::Message << "Viewport area is " << IVec4(viewport.x, viewport.y, viewport.width, viewport.height) << TestLog::EndMessage;
|
|
log << TestLog::Message << "Scissor area is " << absScissorArea << TestLog::EndMessage;
|
|
|
|
// Render reference (no scissors)
|
|
{
|
|
log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
|
|
|
|
gl.useProgram(shader.getProgram());
|
|
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
|
|
|
gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
|
|
gl.clearDepthf(1.0f);
|
|
gl.clearStencil(0);
|
|
gl.disable(GL_DEPTH_TEST);
|
|
gl.disable(GL_STENCIL_TEST);
|
|
gl.disable(GL_SCISSOR_TEST);
|
|
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
|
|
render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
|
|
|
|
glu::readPixels(m_renderCtx, viewport.x, viewport.y, refImage.getAccess());
|
|
GLU_CHECK_ERROR(gl.getError());
|
|
}
|
|
|
|
// Render result (scissors)
|
|
{
|
|
log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
|
|
|
|
gl.useProgram(shader.getProgram());
|
|
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
|
|
|
gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
|
|
gl.clearDepthf(1.0f);
|
|
gl.clearStencil(0);
|
|
gl.disable(GL_DEPTH_TEST);
|
|
gl.disable(GL_STENCIL_TEST);
|
|
gl.disable(GL_SCISSOR_TEST);
|
|
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
|
|
gl.scissor(absScissorArea.x(), absScissorArea.y(), absScissorArea.z(), absScissorArea.w());
|
|
gl.enable(GL_SCISSOR_TEST);
|
|
|
|
render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
|
|
|
|
glu::readPixels(m_renderCtx, viewport.x, viewport.y, resImage.getAccess());
|
|
GLU_CHECK_ERROR(gl.getError());
|
|
}
|
|
|
|
// Manual 'scissors' for reference image
|
|
log << TestLog::Message << "Clearing area outside scissor area from reference" << TestLog::EndMessage;
|
|
clearEdges(refImage.getAccess(), IVec4(32, 64, 128, 255), relScissorArea);
|
|
|
|
if (tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), threshold, tcu::COMPARE_LOG_RESULT))
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
|
|
|
|
return STOP;
|
|
}
|
|
|
|
// Tests scissoring with multiple primitive types
|
|
class ScissorPrimitiveCase : public ScissorCase
|
|
{
|
|
public:
|
|
ScissorPrimitiveCase (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea,
|
|
const Vec4& renderArea,
|
|
PrimitiveType type,
|
|
int primitiveCount);
|
|
virtual ~ScissorPrimitiveCase (void){}
|
|
|
|
protected:
|
|
virtual void render (GLuint program, const IVec4& viewport) const;
|
|
virtual bool isPoint (void) const;
|
|
|
|
private:
|
|
const Vec4 m_renderArea;
|
|
const PrimitiveType m_primitiveType;
|
|
const int m_primitiveCount;
|
|
};
|
|
|
|
ScissorPrimitiveCase::ScissorPrimitiveCase (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea,
|
|
const Vec4& renderArea,
|
|
PrimitiveType type,
|
|
int primitiveCount)
|
|
: ScissorCase (testCtx, renderCtx, name, desc, scissorArea)
|
|
, m_renderArea (renderArea)
|
|
, m_primitiveType (type)
|
|
, m_primitiveCount (primitiveCount)
|
|
{
|
|
}
|
|
|
|
bool ScissorPrimitiveCase::isPoint (void) const
|
|
{
|
|
return (m_primitiveType == POINT);
|
|
}
|
|
|
|
void ScissorPrimitiveCase::render (GLuint program, const IVec4&) const
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const Vec4 white (1.0f, 1.0f, 1.0f, 1.0);
|
|
const Vec4 primitiveArea (m_renderArea.x()*2.0f-1.0f,
|
|
m_renderArea.x()*2.0f-1.0f,
|
|
m_renderArea.z()*2.0f,
|
|
m_renderArea.w()*2.0f);
|
|
|
|
static const float quadPositions[] =
|
|
{
|
|
0.0f, 1.0f,
|
|
0.0f, 0.0f,
|
|
1.0f, 1.0f,
|
|
1.0f, 0.0f
|
|
};
|
|
static const float triPositions[] =
|
|
{
|
|
0.0f, 0.0f,
|
|
1.0f, 0.0f,
|
|
0.5f, 1.0f,
|
|
};
|
|
static const float linePositions[] =
|
|
{
|
|
0.0f, 0.0f,
|
|
1.0f, 1.0f
|
|
};
|
|
static const float pointPosition[] =
|
|
{
|
|
0.5f, 0.5f
|
|
};
|
|
|
|
const float* positionSet[] = { pointPosition, linePositions, triPositions, quadPositions };
|
|
const int vertexCountSet[]= { 1, 2, 3, 4 };
|
|
const int indexCountSet[] = { 1, 2, 3, 6 };
|
|
|
|
const deUint16 baseIndices[] = { 0, 1, 2, 2, 1, 3 };
|
|
const float* basePositions = positionSet[m_primitiveType];
|
|
const int vertexCount = vertexCountSet[m_primitiveType];
|
|
const int indexCount = indexCountSet[m_primitiveType];
|
|
|
|
const float scale = 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f); // Magic value to roughly fill the render area with primitives at a readable density
|
|
vector<float> positions (4*vertexCount*m_primitiveCount);
|
|
vector<deUint16> indices (indexCount*m_primitiveCount);
|
|
de::Random rng (1234);
|
|
|
|
for (int primNdx = 0; primNdx < m_primitiveCount; primNdx++)
|
|
{
|
|
const float dx = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
|
|
const float dy = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
|
|
|
|
for (int vertNdx = 0; vertNdx < vertexCount; vertNdx++)
|
|
{
|
|
const int ndx = primNdx*4*vertexCount + vertNdx*4;
|
|
positions[ndx+0] = (basePositions[vertNdx*2 + 0]*scale + dx)*primitiveArea.z() + primitiveArea.x();
|
|
positions[ndx+1] = (basePositions[vertNdx*2 + 1]*scale + dy)*primitiveArea.w() + primitiveArea.y();
|
|
positions[ndx+2] = 0.2f;
|
|
positions[ndx+3] = 1.0f;
|
|
}
|
|
|
|
for (int ndx = 0; ndx < indexCount; ndx++)
|
|
indices[primNdx*indexCount + ndx] = (deUint16)(baseIndices[ndx] + primNdx*vertexCount);
|
|
}
|
|
|
|
gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.m_data);
|
|
|
|
switch (m_primitiveType)
|
|
{
|
|
case TRIANGLE: drawPrimitives(gl, program, GL_TRIANGLES, positions, indices); break;
|
|
case LINE: drawPrimitives(gl, program, GL_LINES, positions, indices); break;
|
|
case POINT: drawPrimitives(gl, program, GL_POINTS, positions, indices); break;
|
|
default: DE_ASSERT(false); break;
|
|
}
|
|
}
|
|
|
|
// Test effect of scissor on default framebuffer clears
|
|
class ScissorClearCase : public ScissorCase
|
|
{
|
|
public:
|
|
ScissorClearCase (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea,
|
|
deUint32 clearMode);
|
|
virtual ~ScissorClearCase (void) {}
|
|
|
|
virtual void init (void);
|
|
|
|
protected:
|
|
virtual void render (GLuint program, const IVec4& viewport) const;
|
|
virtual bool isPoint (void) const;
|
|
|
|
private:
|
|
const deUint32 m_clearMode; //!< Combination of the flags accepted by glClear
|
|
};
|
|
|
|
ScissorClearCase::ScissorClearCase (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea,
|
|
deUint32 clearMode)
|
|
: ScissorCase (testCtx, renderCtx, name, desc, scissorArea)
|
|
, m_clearMode (clearMode)
|
|
{
|
|
}
|
|
|
|
void ScissorClearCase::init (void)
|
|
{
|
|
if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderCtx.getRenderTarget().getDepthBits() == 0)
|
|
throw tcu::NotSupportedError("Cannot clear depth; no depth buffer present", "", __FILE__, __LINE__);
|
|
else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderCtx.getRenderTarget().getStencilBits() == 0)
|
|
throw tcu::NotSupportedError("Cannot clear stencil; no stencil buffer present", "", __FILE__, __LINE__);
|
|
}
|
|
|
|
bool ScissorClearCase::isPoint (void) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void ScissorClearCase::render (GLuint program, const IVec4&) const
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const Vec4 white (1.0f, 1.0f, 1.0f, 1.0);
|
|
|
|
gl.clearColor(0.6f, 0.1f, 0.1f, 1.0);
|
|
gl.clearDepthf(0.0f);
|
|
|
|
if (m_clearMode & GL_DEPTH_BUFFER_BIT)
|
|
{
|
|
gl.enable(GL_DEPTH_TEST);
|
|
gl.depthFunc(GL_GREATER);
|
|
}
|
|
|
|
if (m_clearMode & GL_STENCIL_BUFFER_BIT)
|
|
{
|
|
gl.clearStencil(123);
|
|
gl.enable(GL_STENCIL_TEST);
|
|
gl.stencilFunc(GL_EQUAL, 123, ~0u);
|
|
}
|
|
|
|
if (m_clearMode & GL_COLOR_BUFFER_BIT)
|
|
gl.clearColor(0.1f, 0.6f, 0.1f, 1.0);
|
|
|
|
gl.clear(m_clearMode);
|
|
gl.disable(GL_SCISSOR_TEST);
|
|
|
|
gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.getPtr());
|
|
|
|
if (!(m_clearMode & GL_COLOR_BUFFER_BIT))
|
|
drawQuad(gl, program, Vec3(-1.0f, -1.0f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
|
|
|
|
gl.disable(GL_DEPTH_TEST);
|
|
gl.disable(GL_STENCIL_TEST);
|
|
}
|
|
|
|
class FramebufferBlitCase : public ScissorCase
|
|
{
|
|
public:
|
|
FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea);
|
|
virtual ~FramebufferBlitCase (void) {}
|
|
|
|
virtual void init (void);
|
|
virtual void deinit (void);
|
|
|
|
protected:
|
|
typedef de::MovePtr<glu::Framebuffer> FramebufferP;
|
|
|
|
enum {SIZE = 64};
|
|
|
|
virtual void render (GLuint program, const IVec4& viewport) const;
|
|
virtual bool isPoint (void) const;
|
|
|
|
FramebufferP m_fbo;
|
|
};
|
|
|
|
FramebufferBlitCase::FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea)
|
|
: ScissorCase(testCtx, renderCtx, name, desc, scissorArea)
|
|
{
|
|
}
|
|
|
|
void FramebufferBlitCase::init (void)
|
|
{
|
|
if (m_renderCtx.getRenderTarget().getNumSamples())
|
|
throw tcu::NotSupportedError("Cannot blit to multisampled framebuffer", "", __FILE__, __LINE__);
|
|
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const glu::Renderbuffer colorbuf (gl);
|
|
const tcu::Vec4 clearColor (1.0f, 0.5, 0.125f, 1.0f);
|
|
|
|
m_fbo = FramebufferP(new glu::Framebuffer(gl));
|
|
|
|
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
|
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
|
|
gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SIZE, SIZE);
|
|
gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
|
|
|
|
gl.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());
|
|
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_renderCtx.getDefaultFramebuffer());
|
|
}
|
|
|
|
void FramebufferBlitCase::deinit (void)
|
|
{
|
|
m_fbo.clear();
|
|
}
|
|
|
|
bool FramebufferBlitCase::isPoint (void) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void FramebufferBlitCase::render(GLuint program, const IVec4& viewport) const
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
const int width = viewport.z();
|
|
const int height = viewport.w();
|
|
const deInt32 defaultFramebuffer = m_renderCtx.getDefaultFramebuffer();
|
|
|
|
DE_UNREF(program);
|
|
|
|
// blit to default framebuffer
|
|
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
|
|
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
|
|
|
|
gl.blitFramebuffer(0, 0, SIZE, SIZE, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer);
|
|
}
|
|
|
|
struct BufferFmtDesc
|
|
{
|
|
tcu::TextureFormat texFmt;
|
|
GLenum colorFmt;
|
|
};
|
|
|
|
struct Color
|
|
{
|
|
enum Type {FLOAT, INT, UINT};
|
|
|
|
Type type;
|
|
|
|
union
|
|
{
|
|
float f[4];
|
|
deInt32 i[4];
|
|
deUint32 u[4];
|
|
};
|
|
|
|
Color(const float f_[4]) : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; }
|
|
Color(const deInt32 i_[4]) : type(INT) { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; }
|
|
Color(const deUint32 u_[4]) : type(UINT) { u[0] = u_[0]; u[1] = u_[1]; u[2] = u_[2]; u[3] = u_[3]; }
|
|
};
|
|
|
|
class FramebufferClearCase : public tcu::TestCase
|
|
{
|
|
public:
|
|
FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType);
|
|
virtual ~FramebufferClearCase (void) {}
|
|
|
|
virtual IterateResult iterate (void);
|
|
|
|
private:
|
|
static void clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil);
|
|
static Color getBaseColor (const BufferFmtDesc& bufferFmt);
|
|
static Color getMainColor (const BufferFmtDesc& bufferFmt);
|
|
static BufferFmtDesc getBufferFormat (ClearType type);
|
|
|
|
virtual void render (GLuint program) const;
|
|
virtual bool isPoint (void) const;
|
|
|
|
glu::RenderContext& m_renderCtx;
|
|
const ClearType m_clearType;
|
|
};
|
|
|
|
FramebufferClearCase::FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType)
|
|
: tcu::TestCase (testCtx, name, desc)
|
|
, m_renderCtx (renderCtx)
|
|
, m_clearType (clearType)
|
|
{
|
|
}
|
|
|
|
void FramebufferClearCase::clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil)
|
|
{
|
|
switch(color.type)
|
|
{
|
|
case Color::FLOAT: gl.clearBufferfv (GL_COLOR, 0, color.f); break;
|
|
case Color::INT: gl.clearBufferiv (GL_COLOR, 0, color.i); break;
|
|
case Color::UINT: gl.clearBufferuiv(GL_COLOR, 0, color.u); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
gl.clearBufferfv(GL_DEPTH, 0, &depth);
|
|
gl.clearBufferiv(GL_STENCIL, 0, &stencil);
|
|
}
|
|
|
|
FramebufferClearCase::IterateResult FramebufferClearCase::iterate (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
const glu::ShaderProgram shader (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType()), isPoint()));
|
|
|
|
const glu::Framebuffer fbo (gl);
|
|
const glu::Renderbuffer colorbuf (gl);
|
|
const glu::Renderbuffer depthbuf (gl);
|
|
|
|
const BufferFmtDesc bufferFmt = getBufferFormat(m_clearType);
|
|
const Color baseColor = getBaseColor(bufferFmt);
|
|
|
|
const int width = 64;
|
|
const int height = 64;
|
|
|
|
const IVec4 scissorArea (8, 8, 48, 48);
|
|
|
|
vector<deUint8> refData (width*height*bufferFmt.texFmt.getPixelSize());
|
|
vector<deUint8> resData (width*height*bufferFmt.texFmt.getPixelSize());
|
|
|
|
tcu::PixelBufferAccess refAccess (bufferFmt.texFmt, width, height, 1, &refData[0]);
|
|
tcu::PixelBufferAccess resAccess (bufferFmt.texFmt, width, height, 1, &resData[0]);
|
|
|
|
if (!shader.isOk())
|
|
{
|
|
log << shader;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
|
|
return STOP;
|
|
}
|
|
|
|
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
|
|
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *fbo);
|
|
|
|
// Color
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
|
|
gl.renderbufferStorage(GL_RENDERBUFFER, bufferFmt.colorFmt, width, height);
|
|
gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
|
|
|
|
// Depth/stencil
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuf);
|
|
gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
|
gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *depthbuf);
|
|
|
|
log << TestLog::Message << "Scissor area is " << scissorArea << TestLog::EndMessage;
|
|
|
|
// Render reference
|
|
{
|
|
log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
|
|
|
|
gl.useProgram(shader.getProgram());
|
|
gl.viewport(0, 0, width, height);
|
|
|
|
gl.disable(GL_DEPTH_TEST);
|
|
gl.disable(GL_STENCIL_TEST);
|
|
gl.disable(GL_SCISSOR_TEST);
|
|
|
|
clearBuffers(gl, baseColor, 1.0f, 0);
|
|
|
|
render(shader.getProgram());
|
|
|
|
glu::readPixels(m_renderCtx, 0, 0, refAccess);
|
|
GLU_CHECK_ERROR(gl.getError());
|
|
}
|
|
|
|
// Render result
|
|
{
|
|
log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
|
|
|
|
gl.useProgram(shader.getProgram());
|
|
gl.viewport(0, 0, width, height);
|
|
|
|
gl.disable(GL_DEPTH_TEST);
|
|
gl.disable(GL_STENCIL_TEST);
|
|
gl.disable(GL_SCISSOR_TEST);
|
|
|
|
clearBuffers(gl, baseColor, 1.0f, 0);
|
|
|
|
gl.enable(GL_SCISSOR_TEST);
|
|
gl.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
|
|
|
|
render(shader.getProgram());
|
|
|
|
glu::readPixels(m_renderCtx, 0, 0, resAccess);
|
|
GLU_CHECK_ERROR(gl.getError());
|
|
}
|
|
|
|
{
|
|
bool resultOk = false;
|
|
|
|
switch (baseColor.type)
|
|
{
|
|
case Color::FLOAT:
|
|
clearEdges(refAccess, Vec4(baseColor.f[0], baseColor.f[1], baseColor.f[2], baseColor.f[3]), scissorArea);
|
|
resultOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT);
|
|
break;
|
|
|
|
case Color::INT:
|
|
clearEdges(refAccess, IVec4(baseColor.i[0], baseColor.i[1], baseColor.i[2], baseColor.i[3]), scissorArea);
|
|
resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
|
|
break;
|
|
|
|
case Color::UINT:
|
|
clearEdges(refAccess, UVec4(baseColor.u[0], baseColor.u[1], baseColor.u[2], baseColor.u[3]), scissorArea);
|
|
resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
|
|
break;
|
|
}
|
|
|
|
if (resultOk)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
|
|
}
|
|
|
|
return STOP;
|
|
}
|
|
|
|
Color FramebufferClearCase::getBaseColor (const BufferFmtDesc& bufferFmt)
|
|
{
|
|
const float f[4] = {0.125f, 0.25f, 0.5f, 1.0f};
|
|
const deInt32 i[4] = {0, 0, 0, 0};
|
|
const deUint32 u[4] = {0, 0, 0, 0};
|
|
|
|
switch(bufferFmt.colorFmt)
|
|
{
|
|
case GL_RGBA8: return Color(f);
|
|
case GL_RGBA8I: return Color(i);
|
|
case GL_RGBA8UI: return Color(u);
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
return Color(f);
|
|
}
|
|
|
|
Color FramebufferClearCase::getMainColor (const BufferFmtDesc& bufferFmt)
|
|
{
|
|
const float f[4] = {1.0f, 1.0f, 0.5f, 1.0f};
|
|
const deInt32 i[4] = {127, -127, 0, 127};
|
|
const deUint32 u[4] = {255, 255, 0, 255};
|
|
|
|
switch(bufferFmt.colorFmt)
|
|
{
|
|
case GL_RGBA8: return Color(f);
|
|
case GL_RGBA8I: return Color(i);
|
|
case GL_RGBA8UI: return Color(u);
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
return Color(f);
|
|
}
|
|
|
|
BufferFmtDesc FramebufferClearCase::getBufferFormat (ClearType type)
|
|
{
|
|
BufferFmtDesc retval;
|
|
|
|
switch (type)
|
|
{
|
|
case CLEAR_COLOR_FLOAT:
|
|
retval.colorFmt = GL_RGBA16F;
|
|
retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT);
|
|
DE_FATAL("Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension...
|
|
break;
|
|
|
|
case CLEAR_COLOR_INT:
|
|
retval.colorFmt = GL_RGBA8I;
|
|
retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
|
|
break;
|
|
|
|
case CLEAR_COLOR_UINT:
|
|
retval.colorFmt = GL_RGBA8UI;
|
|
retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
|
|
break;
|
|
|
|
default:
|
|
retval.colorFmt = GL_RGBA8;
|
|
retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
|
|
break;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
void FramebufferClearCase::render (GLuint program) const
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
const BufferFmtDesc bufferFmt = getBufferFormat(m_clearType);
|
|
const Color clearColor = getMainColor(bufferFmt);
|
|
|
|
const int clearStencil = 123;
|
|
const float clearDepth = 0.5f;
|
|
|
|
switch (m_clearType)
|
|
{
|
|
case CLEAR_COLOR_FIXED: gl.clearBufferfv (GL_COLOR, 0, clearColor.f); break;
|
|
case CLEAR_COLOR_FLOAT: gl.clearBufferfv (GL_COLOR, 0, clearColor.f); break;
|
|
case CLEAR_COLOR_INT: gl.clearBufferiv (GL_COLOR, 0, clearColor.i); break;
|
|
case CLEAR_COLOR_UINT: gl.clearBufferuiv(GL_COLOR, 0, clearColor.u); break;
|
|
case CLEAR_DEPTH: gl.clearBufferfv (GL_DEPTH, 0, &clearDepth); break;
|
|
case CLEAR_STENCIL: gl.clearBufferiv (GL_STENCIL, 0, &clearStencil); break;
|
|
case CLEAR_DEPTH_STENCIL: gl.clearBufferfi (GL_DEPTH_STENCIL, 0, clearDepth, clearStencil); break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
const bool useDepth = (m_clearType == CLEAR_DEPTH || m_clearType == CLEAR_DEPTH_STENCIL);
|
|
const bool useStencil = (m_clearType == CLEAR_STENCIL || m_clearType == CLEAR_DEPTH_STENCIL);
|
|
|
|
// Render something to expose changes to depth/stencil buffer
|
|
if (useDepth || useStencil)
|
|
{
|
|
if (useDepth)
|
|
gl.enable(GL_DEPTH_TEST);
|
|
|
|
if (useStencil)
|
|
gl.enable(GL_STENCIL_TEST);
|
|
|
|
gl.stencilFunc(GL_EQUAL, clearStencil, ~0u);
|
|
gl.depthFunc(GL_GREATER);
|
|
gl.disable(GL_SCISSOR_TEST);
|
|
|
|
gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, clearColor.f);
|
|
drawQuad(gl, program, tcu::Vec3(-1.0f, -1.0f, 0.6f), tcu::Vec3(1.0f, 1.0f, 0.6f));
|
|
}
|
|
}
|
|
|
|
bool FramebufferClearCase::isPoint (void) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
} // Anonymous
|
|
|
|
namespace ScissorTestInternal
|
|
{
|
|
|
|
tcu::TestNode* createPrimitiveTest (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea,
|
|
const Vec4& renderArea,
|
|
PrimitiveType type,
|
|
int primitiveCount)
|
|
{
|
|
return new ScissorPrimitiveCase(testCtx, renderCtx, name, desc, scissorArea, renderArea, type, primitiveCount);
|
|
}
|
|
|
|
tcu::TestNode* createClearTest (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea,
|
|
deUint32 clearMode)
|
|
{
|
|
return new ScissorClearCase(testCtx, renderCtx, name, desc, scissorArea, clearMode);
|
|
}
|
|
|
|
tcu::TestNode* createFramebufferClearTest (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
ClearType clearType)
|
|
{
|
|
return new FramebufferClearCase(testCtx, renderCtx, name, desc, clearType);
|
|
}
|
|
|
|
tcu::TestNode* createFramebufferBlitTest (tcu::TestContext& testCtx,
|
|
glu::RenderContext& renderCtx,
|
|
const char* name,
|
|
const char* desc,
|
|
const Vec4& scissorArea)
|
|
{
|
|
return new FramebufferBlitCase(testCtx, renderCtx, name, desc, scissorArea);
|
|
}
|
|
|
|
} // ScissorTestInternal
|
|
} // Functional
|
|
} // gls
|
|
} // deqp
|