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.
714 lines
22 KiB
714 lines
22 KiB
/*------------------------------------------------------------------------- |
|
* drawElements Quality Program OpenGL ES 2.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 Shader built-in variable tests. |
|
*//*--------------------------------------------------------------------*/ |
|
|
|
#include "es2fShaderBuiltinVarTests.hpp" |
|
#include "glsShaderRenderCase.hpp" |
|
#include "deRandom.hpp" |
|
#include "deString.h" |
|
#include "deMath.h" |
|
#include "deStringUtil.hpp" |
|
#include "tcuTestLog.hpp" |
|
#include "tcuTestCase.hpp" |
|
#include "tcuTextureUtil.hpp" |
|
#include "tcuRenderTarget.hpp" |
|
#include "tcuImageCompare.hpp" |
|
#include "gluPixelTransfer.hpp" |
|
#include "gluDrawUtil.hpp" |
|
|
|
#include "glwEnums.hpp" |
|
#include "glwFunctions.hpp" |
|
|
|
using std::string; |
|
using std::vector; |
|
using tcu::TestLog; |
|
|
|
namespace deqp |
|
{ |
|
namespace gles2 |
|
{ |
|
namespace Functional |
|
{ |
|
|
|
const float builtinConstScale = 4.0f; |
|
|
|
void evalBuiltinConstant (gls::ShaderEvalContext& c) |
|
{ |
|
bool isOk = 0 == (int)(deFloatFloor(c.coords.x() * builtinConstScale) + 0.05f); |
|
c.color = isOk ? tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f) : tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f); |
|
} |
|
|
|
class ShaderBuiltinConstantCase : public gls::ShaderRenderCase |
|
{ |
|
public: |
|
ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, deUint32 paramName, bool isVertexCase); |
|
~ShaderBuiltinConstantCase (void); |
|
|
|
int getRefValue (void); |
|
void init (void); |
|
|
|
private: |
|
const std::string m_varName; |
|
const deUint32 m_paramName; |
|
}; |
|
|
|
ShaderBuiltinConstantCase::ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, deUint32 paramName, bool isVertexCase) |
|
: ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, evalBuiltinConstant) |
|
, m_varName (varName) |
|
, m_paramName (paramName) |
|
{ |
|
} |
|
|
|
ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void) |
|
{ |
|
} |
|
|
|
int ShaderBuiltinConstantCase::getRefValue (void) |
|
{ |
|
if (m_varName == "gl_MaxDrawBuffers") |
|
{ |
|
if (m_ctxInfo.isExtensionSupported("GL_EXT_draw_buffers")) |
|
return m_ctxInfo.getInt(GL_MAX_DRAW_BUFFERS); |
|
else |
|
return 1; |
|
} |
|
else |
|
{ |
|
DE_ASSERT(m_paramName != GL_NONE); |
|
return m_ctxInfo.getInt(m_paramName); |
|
} |
|
} |
|
|
|
void ShaderBuiltinConstantCase::init (void) |
|
{ |
|
const int refValue = getRefValue(); |
|
m_testCtx.getLog() << tcu::TestLog::Message << m_varName << " = " << refValue << tcu::TestLog::EndMessage; |
|
|
|
static const char* defaultVertSrc = |
|
"attribute highp vec4 a_position;\n" |
|
"attribute highp vec4 a_coords;\n" |
|
"varying mediump vec4 v_coords;\n\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" v_coords = a_coords;\n" |
|
" gl_Position = a_position;\n" |
|
"}\n"; |
|
static const char* defaultFragSrc = |
|
"varying mediump vec4 v_color;\n\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_FragColor = v_color;\n" |
|
"}\n"; |
|
|
|
// Construct shader. |
|
std::ostringstream src; |
|
if (m_isVertexCase) |
|
{ |
|
src << "attribute highp vec4 a_position;\n" |
|
<< "attribute highp vec4 a_coords;\n" |
|
<< "varying mediump vec4 v_color;\n"; |
|
} |
|
else |
|
src << "varying mediump vec4 v_coords;\n"; |
|
|
|
src << "void main (void)\n{\n"; |
|
|
|
src << "\tbool isOk = " << m_varName << " == (" << refValue << " + int(floor(" << (m_isVertexCase ? "a_coords" : "v_coords") << ".x * " << de::floatToString(builtinConstScale, 1) << ") + 0.05));\n"; |
|
src << "\t" << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = isOk ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);\n"; |
|
|
|
if (m_isVertexCase) |
|
src << "\tgl_Position = a_position;\n"; |
|
|
|
src << "}\n"; |
|
|
|
m_vertShaderSource = m_isVertexCase ? src.str() : defaultVertSrc; |
|
m_fragShaderSource = m_isVertexCase ? defaultFragSrc : src.str(); |
|
|
|
gls::ShaderRenderCase::init(); |
|
} |
|
|
|
namespace |
|
{ |
|
|
|
struct DepthRangeParams |
|
{ |
|
DepthRangeParams (void) |
|
: zNear (0.0f) |
|
, zFar (1.0f) |
|
{ |
|
} |
|
|
|
DepthRangeParams (float zNear_, float zFar_) |
|
: zNear (zNear_) |
|
, zFar (zFar_) |
|
{ |
|
} |
|
|
|
float zNear; |
|
float zFar; |
|
}; |
|
|
|
class DepthRangeEvaluator : public gls::ShaderEvaluator |
|
{ |
|
public: |
|
DepthRangeEvaluator (const DepthRangeParams& params) |
|
: m_params(params) |
|
{ |
|
} |
|
|
|
void evaluate (gls::ShaderEvalContext& c) |
|
{ |
|
float zNear = deFloatClamp(m_params.zNear, 0.0f, 1.0f); |
|
float zFar = deFloatClamp(m_params.zFar, 0.0f, 1.0f); |
|
float diff = zFar - zNear; |
|
c.color.xyz() = tcu::Vec3(zNear, zFar, diff*0.5f + 0.5f); |
|
} |
|
|
|
private: |
|
const DepthRangeParams& m_params; |
|
}; |
|
|
|
} // anonymous |
|
|
|
class ShaderDepthRangeTest : public gls::ShaderRenderCase |
|
{ |
|
public: |
|
ShaderDepthRangeTest (Context& context, const char* name, const char* desc, bool isVertexCase) |
|
: ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_evaluator) |
|
, m_evaluator (m_depthRange) |
|
, m_iterNdx (0) |
|
{ |
|
} |
|
|
|
void init (void) |
|
{ |
|
static const char* defaultVertSrc = |
|
"attribute highp vec4 a_position;\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_Position = a_position;\n" |
|
"}\n"; |
|
static const char* defaultFragSrc = |
|
"varying mediump vec4 v_color;\n\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_FragColor = v_color;\n" |
|
"}\n"; |
|
|
|
// Construct shader. |
|
std::ostringstream src; |
|
if (m_isVertexCase) |
|
src << "attribute highp vec4 a_position;\n" |
|
<< "varying mediump vec4 v_color;\n"; |
|
|
|
src << "void main (void)\n{\n"; |
|
src << "\t" << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff*0.5 + 0.5, 1.0);\n"; |
|
|
|
if (m_isVertexCase) |
|
src << "\tgl_Position = a_position;\n"; |
|
|
|
src << "}\n"; |
|
|
|
m_vertShaderSource = m_isVertexCase ? src.str() : defaultVertSrc; |
|
m_fragShaderSource = m_isVertexCase ? defaultFragSrc : src.str(); |
|
|
|
gls::ShaderRenderCase::init(); |
|
} |
|
|
|
IterateResult iterate (void) |
|
{ |
|
const glw::Functions& gl = m_renderCtx.getFunctions(); |
|
|
|
const DepthRangeParams cases[] = |
|
{ |
|
DepthRangeParams(0.0f, 1.0f), |
|
DepthRangeParams(1.5f, -1.0f), |
|
DepthRangeParams(0.7f, 0.3f) |
|
}; |
|
|
|
m_depthRange = cases[m_iterNdx]; |
|
m_testCtx.getLog() << tcu::TestLog::Message << "glDepthRangef(" << m_depthRange.zNear << ", " << m_depthRange.zFar << ")" << tcu::TestLog::EndMessage; |
|
gl.depthRangef(m_depthRange.zNear, m_depthRange.zFar); |
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDepthRangef()"); |
|
|
|
gls::ShaderRenderCase::iterate(); |
|
m_iterNdx += 1; |
|
|
|
if (m_iterNdx == DE_LENGTH_OF_ARRAY(cases) || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS) |
|
return STOP; |
|
else |
|
return CONTINUE; |
|
} |
|
|
|
private: |
|
DepthRangeParams m_depthRange; |
|
DepthRangeEvaluator m_evaluator; |
|
int m_iterNdx; |
|
}; |
|
|
|
class FragCoordXYZCase : public TestCase |
|
{ |
|
public: |
|
FragCoordXYZCase (Context& context) |
|
: TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test") |
|
{ |
|
} |
|
|
|
IterateResult iterate (void) |
|
{ |
|
TestLog& log = m_testCtx.getLog(); |
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
|
const int width = m_context.getRenderTarget().getWidth(); |
|
const int height = m_context.getRenderTarget().getHeight(); |
|
const tcu::RGBA threshold = tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold(); |
|
const tcu::Vec3 scale (1.f / float(width), 1.f / float(height), 1.0f); |
|
|
|
tcu::Surface testImg (width, height); |
|
tcu::Surface refImg (width, height); |
|
|
|
const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources( |
|
"attribute highp vec4 a_position;\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_Position = a_position;\n" |
|
"}\n", |
|
|
|
"uniform mediump vec3 u_scale;\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_FragColor = vec4(gl_FragCoord.xyz*u_scale, 1.0);\n" |
|
"}\n")); |
|
|
|
log << program; |
|
|
|
if (!program.isOk()) |
|
throw tcu::TestError("Compile failed"); |
|
|
|
// Draw with GL. |
|
{ |
|
const float positions[] = |
|
{ |
|
-1.0f, 1.0f, -1.0f, 1.0f, |
|
-1.0f, -1.0f, 0.0f, 1.0f, |
|
1.0f, 1.0f, 0.0f, 1.0f, |
|
1.0f, -1.0f, 1.0f, 1.0f |
|
}; |
|
const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; |
|
|
|
const int scaleLoc = gl.getUniformLocation(program.getProgram(), "u_scale"); |
|
glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]); |
|
|
|
gl.useProgram(program.getProgram()); |
|
gl.uniform3fv(scaleLoc, 1, scale.getPtr()); |
|
|
|
glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding, |
|
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); |
|
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess()); |
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw"); |
|
} |
|
|
|
// Draw reference |
|
for (int y = 0; y < refImg.getHeight(); y++) |
|
{ |
|
for (int x = 0; x < refImg.getWidth(); x++) |
|
{ |
|
const float xf = (float(x)+.5f) / float(refImg.getWidth()); |
|
const float yf = (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight()); |
|
const float z = (xf + yf) / 2.0f; |
|
const tcu::Vec3 fragCoord (float(x)+.5f, float(y)+.5f, z); |
|
const tcu::Vec3 scaledFC = fragCoord*scale; |
|
const tcu::Vec4 color (scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f); |
|
|
|
refImg.setPixel(x, y, tcu::RGBA(color)); |
|
} |
|
} |
|
|
|
// Compare |
|
{ |
|
bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT); |
|
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
isOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
}; |
|
|
|
static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny) |
|
{ |
|
return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]); |
|
} |
|
|
|
class FragCoordWCase : public TestCase |
|
{ |
|
public: |
|
FragCoordWCase (Context& context) |
|
: TestCase(context, "fragcoord_w", "gl_FragCoord.w Test") |
|
{ |
|
} |
|
|
|
IterateResult iterate (void) |
|
{ |
|
TestLog& log = m_testCtx.getLog(); |
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
|
const int width = m_context.getRenderTarget().getWidth(); |
|
const int height = m_context.getRenderTarget().getHeight(); |
|
const tcu::RGBA threshold = tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold(); |
|
|
|
tcu::Surface testImg (width, height); |
|
tcu::Surface refImg (width, height); |
|
|
|
const float w[4] = { 1.7f, 2.0f, 1.2f, 1.0f }; |
|
|
|
const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources( |
|
"attribute highp vec4 a_position;\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_Position = a_position;\n" |
|
"}\n", |
|
|
|
"void main (void)\n" |
|
"{\n" |
|
" gl_FragColor = vec4(0.0, 1.0/gl_FragCoord.w - 1.0, 0.0, 1.0);\n" |
|
"}\n")); |
|
|
|
log << program; |
|
|
|
if (!program.isOk()) |
|
throw tcu::TestError("Compile failed"); |
|
|
|
// Draw with GL. |
|
{ |
|
const float positions[] = |
|
{ |
|
-w[0], w[0], 0.0f, w[0], |
|
-w[1], -w[1], 0.0f, w[1], |
|
w[2], w[2], 0.0f, w[2], |
|
w[3], -w[3], 0.0f, w[3] |
|
}; |
|
const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; |
|
|
|
glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]); |
|
|
|
gl.useProgram(program.getProgram()); |
|
|
|
glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding, |
|
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); |
|
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess()); |
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw"); |
|
} |
|
|
|
// Draw reference |
|
for (int y = 0; y < refImg.getHeight(); y++) |
|
{ |
|
for (int x = 0; x < refImg.getWidth(); x++) |
|
{ |
|
const float xf = (float(x)+.5f) / float(refImg.getWidth()); |
|
const float yf = (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight()); |
|
const float oow = ((xf + yf) < 1.0f) |
|
? projectedTriInterpolate(tcu::Vec3(w[0], w[1], w[2]), tcu::Vec3(w[0], w[1], w[2]), xf, yf) |
|
: projectedTriInterpolate(tcu::Vec3(w[3], w[2], w[1]), tcu::Vec3(w[3], w[2], w[1]), 1.0f-xf, 1.0f-yf); |
|
const tcu::Vec4 color (0.0f, oow - 1.0f, 0.0f, 1.0f); |
|
|
|
refImg.setPixel(x, y, tcu::RGBA(color)); |
|
} |
|
} |
|
|
|
// Compare |
|
{ |
|
bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT); |
|
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
isOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
}; |
|
|
|
class PointCoordCase : public TestCase |
|
{ |
|
public: |
|
PointCoordCase (Context& context) |
|
: TestCase(context, "pointcoord", "gl_PointCoord Test") |
|
{ |
|
} |
|
|
|
IterateResult iterate (void) |
|
{ |
|
TestLog& log = m_testCtx.getLog(); |
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
|
const int width = de::min(256, m_context.getRenderTarget().getWidth()); |
|
const int height = de::min(256, m_context.getRenderTarget().getHeight()); |
|
const float threshold = 0.02f; |
|
|
|
const int numPoints = 8; |
|
|
|
vector<tcu::Vec3> coords (numPoints); |
|
float pointSizeRange[2] = { 0.0f, 0.0f }; |
|
|
|
de::Random rnd (0x145fa); |
|
tcu::Surface testImg (width, height); |
|
tcu::Surface refImg (width, height); |
|
|
|
gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, &pointSizeRange[0]); |
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE)"); |
|
|
|
if (pointSizeRange[0] <= 0.0f || pointSizeRange[1] <= 0.0f || pointSizeRange[1] < pointSizeRange[0]) |
|
throw tcu::TestError("Invalid GL_ALIASED_POINT_SIZE_RANGE"); |
|
|
|
// Compute coordinates. |
|
{ |
|
|
|
for (vector<tcu::Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord) |
|
{ |
|
coord->x() = rnd.getFloat(-0.9f, 0.9f); |
|
coord->y() = rnd.getFloat(-0.9f, 0.9f); |
|
coord->z() = rnd.getFloat(pointSizeRange[0], pointSizeRange[1]); |
|
} |
|
} |
|
|
|
const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources( |
|
"attribute highp vec3 a_positionSize;\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_Position = vec4(a_positionSize.xy, 0.0, 1.0);\n" |
|
" gl_PointSize = a_positionSize.z;\n" |
|
"}\n", |
|
|
|
"void main (void)\n" |
|
"{\n" |
|
" gl_FragColor = vec4(gl_PointCoord, 0.0, 1.0);\n" |
|
"}\n")); |
|
|
|
log << program; |
|
|
|
if (!program.isOk()) |
|
throw tcu::TestError("Compile failed"); |
|
|
|
// Draw with GL. |
|
{ |
|
glu::VertexArrayBinding posBinding = glu::va::Float("a_positionSize", 3, (int)coords.size(), 0, (const float*)&coords[0]); |
|
const int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth()-width); |
|
const int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight()-height); |
|
|
|
gl.viewport(viewportX, viewportY, width, height); |
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
|
gl.clear(GL_COLOR_BUFFER_BIT); |
|
|
|
gl.useProgram(program.getProgram()); |
|
|
|
glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding, |
|
glu::pr::Points((int)coords.size())); |
|
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess()); |
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw"); |
|
} |
|
|
|
// Draw reference |
|
tcu::clear(refImg.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); |
|
for (vector<tcu::Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter) |
|
{ |
|
const int x0 = deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) - pointIter->z()*0.5f); |
|
const int y0 = deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) - pointIter->z()*0.5f); |
|
const int x1 = deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) + pointIter->z()*0.5f); |
|
const int y1 = deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) + pointIter->z()*0.5f); |
|
const int w = x1-x0; |
|
const int h = y1-y0; |
|
|
|
for (int yo = 0; yo < h; yo++) |
|
{ |
|
for (int xo = 0; xo < w; xo++) |
|
{ |
|
const float xf = (float(xo)+0.5f) / float(w); |
|
const float yf = (float(h-yo-1)+0.5f) / float(h); |
|
const tcu::Vec4 color (xf, yf, 0.0f, 1.0f); |
|
const int dx = x0+xo; |
|
const int dy = y0+yo; |
|
|
|
if (de::inBounds(dx, 0, refImg.getWidth()) && de::inBounds(dy, 0, refImg.getHeight())) |
|
refImg.setPixel(dx, dy, tcu::RGBA(color)); |
|
} |
|
} |
|
} |
|
|
|
// Compare |
|
{ |
|
bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT); |
|
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
isOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
}; |
|
|
|
class FrontFacingCase : public TestCase |
|
{ |
|
public: |
|
FrontFacingCase (Context& context) |
|
: TestCase(context, "frontfacing", "gl_FrontFacing Test") |
|
{ |
|
} |
|
|
|
IterateResult iterate (void) |
|
{ |
|
// Test case renders two adjecent quads, where left is has front-facing |
|
// triagles and right back-facing. Color is selected based on gl_FrontFacing |
|
// value. |
|
|
|
TestLog& log = m_testCtx.getLog(); |
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
|
de::Random rnd (0x89f2c); |
|
const int width = de::min(64, m_context.getRenderTarget().getWidth()); |
|
const int height = de::min(64, m_context.getRenderTarget().getHeight()); |
|
const int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth()-width); |
|
const int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight()-height); |
|
const tcu::RGBA threshold = tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold(); |
|
|
|
tcu::Surface testImg (width, height); |
|
tcu::Surface refImg (width, height); |
|
|
|
const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources( |
|
"attribute highp vec4 a_position;\n" |
|
"void main (void)\n" |
|
"{\n" |
|
" gl_Position = a_position;\n" |
|
"}\n", |
|
|
|
"void main (void)\n" |
|
"{\n" |
|
" if (gl_FrontFacing)\n" |
|
" gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
|
" else\n" |
|
" gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n" |
|
"}\n")); |
|
|
|
log << program; |
|
|
|
if (!program.isOk()) |
|
throw tcu::TestError("Compile failed"); |
|
|
|
// Draw with GL. |
|
{ |
|
const float positions[] = |
|
{ |
|
-1.0f, 1.0f, 0.0f, 1.0f, |
|
-1.0f, -1.0f, 0.0f, 1.0f, |
|
1.0f, 1.0f, 0.0f, 1.0f, |
|
1.0f, -1.0f, 0.0f, 1.0f |
|
}; |
|
const deUint16 indicesCCW[] = { 0, 1, 2, 2, 1, 3 }; |
|
const deUint16 indicesCW[] = { 2, 1, 0, 3, 1, 2 }; |
|
|
|
glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]); |
|
|
|
gl.useProgram(program.getProgram()); |
|
|
|
gl.viewport(viewportX, viewportY, width/2, height); |
|
glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding, |
|
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0])); |
|
|
|
gl.viewport(viewportX + width/2, viewportY, width-width/2, height); |
|
glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding, |
|
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0])); |
|
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess()); |
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw"); |
|
} |
|
|
|
// Draw reference |
|
for (int y = 0; y < refImg.getHeight(); y++) |
|
{ |
|
for (int x = 0; x < refImg.getWidth()/2; x++) |
|
refImg.setPixel(x, y, tcu::RGBA::green()); |
|
|
|
for (int x = refImg.getWidth()/2; x < refImg.getWidth(); x++) |
|
refImg.setPixel(x, y, tcu::RGBA::blue()); |
|
} |
|
|
|
// Compare |
|
{ |
|
bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT); |
|
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
isOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
}; |
|
|
|
ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context) |
|
: TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests") |
|
{ |
|
} |
|
|
|
ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void) |
|
{ |
|
} |
|
|
|
void ShaderBuiltinVarTests::init (void) |
|
{ |
|
// Builtin constants. |
|
|
|
static const struct |
|
{ |
|
const char* caseName; |
|
const char* varName; |
|
deUint32 paramName; |
|
} builtinConstants[] = |
|
{ |
|
{ "max_vertex_attribs", "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, |
|
{ "max_vertex_uniform_vectors", "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS }, |
|
{ "max_fragment_uniform_vectors", "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS }, |
|
{ "max_varying_vectors", "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS }, |
|
{ "max_texture_image_units", "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, |
|
{ "max_vertex_texture_image_units", "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, |
|
{ "max_combined_texture_image_units", "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, |
|
{ "max_draw_buffers", "gl_MaxDrawBuffers", GL_NONE } |
|
}; |
|
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++) |
|
{ |
|
const char* caseName = builtinConstants[ndx].caseName; |
|
const char* varName = builtinConstants[ndx].varName; |
|
deUint32 paramName = builtinConstants[ndx].paramName; |
|
|
|
addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(), varName, varName, paramName, true)); |
|
addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(), varName, varName, paramName, false)); |
|
} |
|
|
|
addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex", "gl_DepthRange", true)); |
|
addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment", "gl_DepthRange", false)); |
|
|
|
// Fragment shader builtin variables. |
|
|
|
addChild(new FragCoordXYZCase (m_context)); |
|
addChild(new FragCoordWCase (m_context)); |
|
addChild(new PointCoordCase (m_context)); |
|
addChild(new FrontFacingCase (m_context)); |
|
} |
|
|
|
} // Functional |
|
} // gles2 |
|
} // deqp
|
|
|