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.
372 lines
11 KiB
372 lines
11 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 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 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 deUint8 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(); |
|
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( |
|
"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 deUint8 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 < 2; ndx++) |
|
{ |
|
const deUint32 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 deUint32 drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; |
|
gl.drawBuffers(DE_LENGTH_OF_ARRAY(drawBuffers), &drawBuffers[0]); |
|
} |
|
|
|
gl.clearBufferfv(GL_COLOR, 0, tcu::RGBA::red().toVec().getPtr()); |
|
gl.clearBufferfv(GL_COLOR, 1, tcu::RGBA::red().toVec().getPtr()); |
|
|
|
gl.viewport (0, 0, width, height); |
|
gl.useProgram (program.getProgram()); |
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); |
|
|
|
m_testCtx.getLog() << TestLog::Message << "Drawing to attachments 0 and 1, expecting only attachment 0 to change." << TestLog::EndMessage; |
|
|
|
for (int ndx = 0; ndx < 2; ndx++) |
|
{ |
|
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); |
|
const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1); |
|
bool allOk = true; |
|
|
|
for (int ndx = 0; ndx < 2; ndx++) |
|
{ |
|
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, ndx == 0 ? tcu::RGBA::green() : tcu::RGBA::red(), threshold)) |
|
allOk = false; |
|
} |
|
|
|
m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
allOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
}; |
|
|
|
} // anonymous |
|
|
|
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); |
|
} |
|
} |
|
|
|
} // Functional |
|
} // gles3 |
|
} // deqp
|
|
|