blob: 5ca33539abe1117fcd9e6260b5570ba53efeddda [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* 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 GLSL ES 1.0 gl_FragData[] tests.
*//*--------------------------------------------------------------------*/
#include "es3fShaderFragDataTests.hpp"
#include "glsShaderLibrary.hpp"
#include "gluRenderContext.hpp"
#include "gluShaderProgram.hpp"
#include "gluDrawUtil.hpp"
#include "gluPixelTransfer.hpp"
#include "gluObjectWrapper.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuTestLog.hpp"
#include "tcuSurface.hpp"
#include "glwFunctions.hpp"
#include "glwEnums.hpp"
namespace deqp
{
namespace gles3
{
namespace Functional
{
using std::string;
using tcu::TestLog;
namespace
{
enum IndexExprType
{
INDEX_EXPR_STATIC = 0,
INDEX_EXPR_UNIFORM,
INDEX_EXPR_DYNAMIC,
INDEX_EXPR_TYPE_LAST
};
static bool isExtensionSupported(const glu::RenderContext &renderCtx, const std::string &extension)
{
const glw::Functions &gl = renderCtx.getFunctions();
int numExts = 0;
gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts);
for (int ndx = 0; ndx < numExts; ndx++)
{
const char *curExt = (const char *)gl.getStringi(GL_EXTENSIONS, ndx);
if (extension == curExt)
return true;
}
return false;
}
static bool compareSingleColor(tcu::TestLog &log, const tcu::Surface &surface, tcu::RGBA expectedColor,
tcu::RGBA threshold)
{
const int maxPrints = 10;
int numFailedPixels = 0;
log << TestLog::Message << "Expecting " << expectedColor << " with threshold " << threshold << TestLog::EndMessage;
for (int y = 0; y < surface.getHeight(); y++)
{
for (int x = 0; x < surface.getWidth(); x++)
{
const tcu::RGBA resultColor = surface.getPixel(x, y);
const bool isOk = compareThreshold(resultColor, expectedColor, threshold);
if (!isOk)
{
if (numFailedPixels < maxPrints)
log << TestLog::Message << "ERROR: Got " << resultColor << " at (" << x << ", " << y << ")!"
<< TestLog::EndMessage;
else if (numFailedPixels == maxPrints)
log << TestLog::Message << "..." << TestLog::EndMessage;
numFailedPixels += 1;
}
}
}
if (numFailedPixels > 0)
{
log << TestLog::Message << "Found " << numFailedPixels << " invalid pixels, comparison FAILED!"
<< TestLog::EndMessage;
log << TestLog::Image("ResultImage", "Result Image", surface);
return false;
}
else
{
log << TestLog::Message << "Image comparison passed." << TestLog::EndMessage;
return true;
}
}
class FragDataIndexingCase : public TestCase
{
public:
FragDataIndexingCase(Context &context, const char *name, const char *description, IndexExprType indexExprType)
: TestCase(context, name, description)
, m_indexExprType(indexExprType)
{
}
static glu::ProgramSources genSources(const IndexExprType indexExprType)
{
const char *const fragIndexExpr = indexExprType == INDEX_EXPR_STATIC ? "0" :
indexExprType == INDEX_EXPR_UNIFORM ? "u_index" :
indexExprType == INDEX_EXPR_DYNAMIC ? "int(v_index)" :
DE_NULL;
glu::ProgramSources sources;
DE_ASSERT(fragIndexExpr);
sources << glu::VertexSource("attribute highp vec4 a_position;\n"
"attribute highp float a_index;\n"
"attribute highp vec4 a_color;\n"
"varying mediump float v_index;\n"
"varying mediump vec4 v_color;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
" v_color = a_color;\n"
" v_index = a_index;\n"
"}\n");
sources << glu::FragmentSource(string("varying mediump vec4 v_color;\n"
"varying mediump float v_index;\n"
"uniform mediump int u_index;\n"
"void main (void)\n"
"{\n"
" gl_FragData[") +
fragIndexExpr +
"] = v_color;\n"
"}\n");
return sources;
}
IterateResult iterate(void)
{
const glu::RenderContext &renderCtx = m_context.getRenderContext();
const glw::Functions &gl = renderCtx.getFunctions();
const glu::ShaderProgram program(renderCtx, genSources(m_indexExprType));
const int viewportW = de::min(renderCtx.getRenderTarget().getWidth(), 128);
const int viewportH = de::min(renderCtx.getRenderTarget().getHeight(), 128);
const float positions[] = {-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f};
const float colors[] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
const float indexValues[] = {0.0f, 0.0f, 0.0f, 0.0f};
const uint8_t indices[] = {0, 1, 2, 2, 1, 3};
const glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("a_position", 2, 4, 0, &positions[0]),
glu::va::Float("a_color", 4, 4, 0, &colors[0]),
glu::va::Float("a_index", 1, 4, 0, &indexValues[0])};
m_testCtx.getLog() << program;
if (!program.isOk())
{
if (m_indexExprType == INDEX_EXPR_STATIC)
TCU_FAIL("Compile failed");
else
throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
}
gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
gl.viewport(0, 0, viewportW, viewportH);
gl.useProgram(program.getProgram());
gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_index"), 0);
glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
{
tcu::Surface result(viewportW, viewportH);
const tcu::RGBA threshold =
renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
bool isOk;
glu::readPixels(renderCtx, 0, 0, result.getAccess());
GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
isOk = compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold);
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
isOk ? "Pass" : "Image comparison failed");
}
return STOP;
}
private:
const IndexExprType m_indexExprType;
};
class FragDataDrawBuffersCase : public TestCase
{
public:
FragDataDrawBuffersCase(Context &context)
: TestCase(context, "draw_buffers", "gl_FragData[] and glDrawBuffers() interaction")
{
}
IterateResult iterate(void)
{
const glu::RenderContext &renderCtx = m_context.getRenderContext();
int num_test_attachment = 2;
if (!isExtensionSupported(renderCtx, "GL_EXT_draw_buffers") &&
!isExtensionSupported(renderCtx, "GL_NV_draw_buffers"))
num_test_attachment = 1;
std::string extensionString;
if (isExtensionSupported(renderCtx, "GL_EXT_draw_buffers"))
extensionString = "#extension GL_EXT_draw_buffers : require\n";
else if (isExtensionSupported(renderCtx, "GL_NV_draw_buffers"))
extensionString = "#extension GL_NV_draw_buffers : require\n";
const glu::ShaderProgram program(renderCtx, glu::ProgramSources()
<< glu::VertexSource("attribute highp vec4 a_position;\n"
"attribute highp vec4 a_color;\n"
"varying mediump vec4 v_color;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
" v_color = a_color;\n"
"}\n")
<< glu::FragmentSource(extensionString +
"varying mediump vec4 v_color;\n"
"uniform mediump int u_index;\n"
"void main (void)\n"
"{\n"
" gl_FragData[u_index] = v_color;\n"
"}\n"));
const glw::Functions &gl = renderCtx.getFunctions();
const int width = 128;
const int height = 128;
const int indexLoc = program.isOk() ? gl.getUniformLocation(program.getProgram(), "u_index") : -1;
const glu::Framebuffer fbo(renderCtx);
const glu::Renderbuffer colorBuf0(renderCtx);
const glu::Renderbuffer colorBuf1(renderCtx);
const float positions[] = {-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f};
const float colors[] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
const uint8_t indices[] = {0, 1, 2, 2, 1, 3};
const glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("a_position", 2, 4, 0, &positions[0]),
glu::va::Float("a_color", 4, 4, 0, &colors[0])};
m_testCtx.getLog() << program;
if (!program.isOk())
throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
for (int ndx = 0; ndx < num_test_attachment; ndx++)
{
const uint32_t rbo = ndx == 0 ? *colorBuf0 : *colorBuf1;
gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ndx, GL_RENDERBUFFER, rbo);
}
TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
{
const uint32_t drawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
gl.drawBuffers(DE_LENGTH_OF_ARRAY(drawBuffers), &drawBuffers[0]);
}
gl.viewport(0, 0, width, height);
gl.useProgram(program.getProgram());
GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
bool allOk = true;
const tcu::RGBA threshold =
renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
for (int ndx = 0; ndx < num_test_attachment; ndx++)
{
gl.clearBufferfv(GL_COLOR, 0, tcu::RGBA::red().toVec().getPtr());
gl.clearBufferfv(GL_COLOR, 1, tcu::RGBA::red().toVec().getPtr());
m_testCtx.getLog() << TestLog::Message << "Drawing to attachments " << ndx << TestLog::EndMessage;
gl.uniform1i(indexLoc, ndx);
glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
{
tcu::Surface result(width, height);
m_testCtx.getLog() << TestLog::Message << "Verifying attachment " << ndx << "..."
<< TestLog::EndMessage;
gl.readBuffer(GL_COLOR_ATTACHMENT0 + ndx);
glu::readPixels(renderCtx, 0, 0, result.getAccess());
GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
if (!compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold))
allOk = false;
}
}
m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
allOk ? "Pass" : "Image comparison failed");
return STOP;
}
};
} // namespace
ShaderFragDataTests::ShaderFragDataTests(Context &context) : TestCaseGroup(context, "fragdata", "gl_FragData[] Tests")
{
}
ShaderFragDataTests::~ShaderFragDataTests(void)
{
}
void ShaderFragDataTests::init(void)
{
addChild(new FragDataIndexingCase(m_context, "valid_static_index",
"Valid gl_FragData[] assignment using static index", INDEX_EXPR_STATIC));
addChild(new FragDataIndexingCase(m_context, "valid_uniform_index",
"Valid gl_FragData[] assignment using uniform index", INDEX_EXPR_UNIFORM));
addChild(new FragDataIndexingCase(m_context, "valid_dynamic_index",
"Valid gl_FragData[] assignment using dynamic index", INDEX_EXPR_DYNAMIC));
addChild(new FragDataDrawBuffersCase(m_context));
// Negative cases.
{
gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
std::vector<tcu::TestNode *> negativeCases = library.loadShaderFile("shaders/fragdata.test");
for (std::vector<tcu::TestNode *>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
addChild(*i);
}
}
} // namespace Functional
} // namespace gles3
} // namespace deqp