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.
885 lines
27 KiB
885 lines
27 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) |
|
{ |
|
const string 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; |
|
|
|
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()))); |
|
|
|
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; |
|
|
|
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) |
|
{ |
|
} |
|
|
|
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; |
|
|
|
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__); |
|
} |
|
|
|
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; |
|
|
|
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(); |
|
} |
|
|
|
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; |
|
|
|
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()))); |
|
|
|
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)); |
|
} |
|
} |
|
|
|
} // 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
|
|
|