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.
1164 lines
38 KiB
1164 lines
38 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 Shader built-in variable tests.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es3fShaderBuiltinVarTests.hpp"
|
|
#include "glsShaderRenderCase.hpp"
|
|
#include "glsShaderExecUtil.hpp"
|
|
#include "deRandom.hpp"
|
|
#include "deString.h"
|
|
#include "deMath.h"
|
|
#include "deUniquePtr.hpp"
|
|
#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 "gluStrUtil.hpp"
|
|
#include "rrRenderer.hpp"
|
|
#include "rrFragmentOperations.hpp"
|
|
|
|
#include "glwEnums.hpp"
|
|
#include "glwFunctions.hpp"
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
using tcu::TestLog;
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles3
|
|
{
|
|
namespace Functional
|
|
{
|
|
|
|
static int getInteger (const glw::Functions& gl, deUint32 pname)
|
|
{
|
|
int value = -1;
|
|
gl.getIntegerv(pname, &value);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
|
|
return value;
|
|
}
|
|
|
|
template<deUint32 Pname>
|
|
static int getInteger (const glw::Functions& gl)
|
|
{
|
|
return getInteger(gl, Pname);
|
|
}
|
|
|
|
static int getVectorsFromComps (const glw::Functions& gl, deUint32 pname)
|
|
{
|
|
int value = -1;
|
|
gl.getIntegerv(pname, &value);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
|
|
// Accept truncated division. According to the spec, the number of vectors is number of components divided by four, plain and simple.
|
|
return value/4;
|
|
}
|
|
|
|
template<deUint32 Pname>
|
|
static int getVectorsFromComps (const glw::Functions& gl)
|
|
{
|
|
return getVectorsFromComps(gl, Pname);
|
|
}
|
|
|
|
class ShaderBuiltinConstantCase : public TestCase
|
|
{
|
|
public:
|
|
typedef int (*GetConstantValueFunc) (const glw::Functions& gl);
|
|
|
|
ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, GetConstantValueFunc getValue, glu::ShaderType shaderType);
|
|
~ShaderBuiltinConstantCase (void);
|
|
|
|
IterateResult iterate (void);
|
|
|
|
private:
|
|
const std::string m_varName;
|
|
const GetConstantValueFunc m_getValue;
|
|
const glu::ShaderType m_shaderType;
|
|
};
|
|
|
|
ShaderBuiltinConstantCase::ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, GetConstantValueFunc getValue, glu::ShaderType shaderType)
|
|
: TestCase (context, name, desc)
|
|
, m_varName (varName)
|
|
, m_getValue (getValue)
|
|
, m_shaderType (shaderType)
|
|
{
|
|
}
|
|
|
|
ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
|
|
{
|
|
}
|
|
|
|
static gls::ShaderExecUtil::ShaderExecutor* createGetConstantExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, const std::string& varName)
|
|
{
|
|
using namespace gls::ShaderExecUtil;
|
|
|
|
ShaderSpec shaderSpec;
|
|
|
|
shaderSpec.version = glu::GLSL_VERSION_300_ES;
|
|
shaderSpec.source = string("result = ") + varName + ";\n";
|
|
shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
|
|
|
|
return createExecutor(renderCtx, shaderType, shaderSpec);
|
|
}
|
|
|
|
ShaderBuiltinConstantCase::IterateResult ShaderBuiltinConstantCase::iterate (void)
|
|
{
|
|
using namespace gls::ShaderExecUtil;
|
|
|
|
const de::UniquePtr<ShaderExecutor> shaderExecutor (createGetConstantExecutor(m_context.getRenderContext(), m_shaderType, m_varName));
|
|
const int reference = m_getValue(m_context.getRenderContext().getFunctions());
|
|
int result = -1;
|
|
void* const outputs = &result;
|
|
|
|
if (!shaderExecutor->isOk())
|
|
{
|
|
shaderExecutor->log(m_testCtx.getLog());
|
|
TCU_FAIL("Compile failed");
|
|
}
|
|
|
|
shaderExecutor->useProgram();
|
|
shaderExecutor->execute(1, DE_NULL, &outputs);
|
|
|
|
m_testCtx.getLog() << TestLog::Integer(m_varName, m_varName, "", QP_KEY_TAG_NONE, result);
|
|
|
|
if (result != reference)
|
|
{
|
|
m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << m_varName << " = " << reference << TestLog::EndMessage
|
|
<< TestLog::Message << "Test shader:" << TestLog::EndMessage;
|
|
shaderExecutor->log(m_testCtx.getLog());
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid builtin constant value");
|
|
}
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
|
|
return STOP;
|
|
}
|
|
|
|
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 =
|
|
"#version 300 es\n"
|
|
"in highp vec4 a_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
"}\n";
|
|
static const char* defaultFragSrc =
|
|
"#version 300 es\n"
|
|
"in mediump vec4 v_color;\n"
|
|
"layout(location = 0) out mediump vec4 o_color;\n\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" o_color = v_color;\n"
|
|
"}\n";
|
|
|
|
// Construct shader.
|
|
std::ostringstream src;
|
|
src << "#version 300 es\n";
|
|
if (m_isVertexCase)
|
|
src << "in highp vec4 a_position;\n"
|
|
<< "out mediump vec4 v_color;\n";
|
|
else
|
|
src << "layout(location = 0) out mediump vec4 o_color;\n";
|
|
|
|
src << "void main (void)\n{\n";
|
|
src << "\t" << (m_isVertexCase ? "v_color" : "o_color") << " = 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(
|
|
"#version 300 es\n"
|
|
"in highp vec4 a_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
"}\n",
|
|
|
|
"#version 300 es\n"
|
|
"uniform highp vec3 u_scale;\n"
|
|
"layout(location = 0) out mediump vec4 o_color;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" o_color = 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(
|
|
"#version 300 es\n"
|
|
"in highp vec4 a_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
"}\n",
|
|
|
|
"#version 300 es\n"
|
|
"layout(location = 0) out mediump vec4 o_color;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" o_color = 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(
|
|
"#version 300 es\n"
|
|
"in 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",
|
|
|
|
"#version 300 es\n"
|
|
"layout(location = 0) out mediump vec4 o_color;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" o_color = 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(
|
|
"#version 300 es\n"
|
|
"in highp vec4 a_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
"}\n",
|
|
|
|
"#version 300 es\n"
|
|
"layout(location = 0) out mediump vec4 o_color;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" if (gl_FrontFacing)\n"
|
|
" o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" o_color = 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.frontFace(GL_CCW);
|
|
|
|
gl.viewport(viewportX, viewportY, width/2, height/2);
|
|
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/2);
|
|
glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
|
|
glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
|
|
|
|
gl.frontFace(GL_CW);
|
|
|
|
gl.viewport(viewportX, viewportY + height/2, width/2, height-height/2);
|
|
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 + height/2, width-width/2, height-height/2);
|
|
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() / 2; y++)
|
|
for(int x = 0; x < refImg.getWidth() / 2; x++)
|
|
refImg.setPixel(x, y, tcu::RGBA::green());
|
|
|
|
for(int y = 0; y < refImg.getHeight() / 2; y++)
|
|
for(int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
|
|
refImg.setPixel(x, y, tcu::RGBA::blue());
|
|
|
|
for(int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
|
|
for(int x = 0; x < refImg.getWidth() / 2; x++)
|
|
refImg.setPixel(x, y, tcu::RGBA::blue());
|
|
|
|
for(int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
|
|
for(int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
|
|
refImg.setPixel(x, y, tcu::RGBA::green());
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
};
|
|
|
|
// VertexIDCase
|
|
|
|
class VertexIDCase : public TestCase
|
|
{
|
|
public:
|
|
VertexIDCase (Context& context);
|
|
~VertexIDCase (void);
|
|
|
|
void init (void);
|
|
void deinit (void);
|
|
IterateResult iterate (void);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
MAX_VERTICES = 8*3 //!< 8 triangles, totals 24 vertices
|
|
};
|
|
|
|
void renderReference (const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors, const int subpixelBits);
|
|
|
|
glu::ShaderProgram* m_program;
|
|
deUint32 m_positionBuffer;
|
|
deUint32 m_elementBuffer;
|
|
|
|
vector<tcu::Vec4> m_positions;
|
|
vector<tcu::Vec4> m_colors;
|
|
int m_viewportW;
|
|
int m_viewportH;
|
|
|
|
int m_iterNdx;
|
|
};
|
|
|
|
VertexIDCase::VertexIDCase (Context& context)
|
|
: TestCase (context, "vertex_id", "gl_VertexID Test")
|
|
, m_program (DE_NULL)
|
|
, m_positionBuffer (0)
|
|
, m_elementBuffer (0)
|
|
, m_viewportW (0)
|
|
, m_viewportH (0)
|
|
, m_iterNdx (0)
|
|
{
|
|
}
|
|
|
|
VertexIDCase::~VertexIDCase (void)
|
|
{
|
|
VertexIDCase::deinit();
|
|
}
|
|
|
|
void VertexIDCase::init (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const int width = m_context.getRenderTarget().getWidth();
|
|
const int height = m_context.getRenderTarget().getHeight();
|
|
|
|
const int quadWidth = 32;
|
|
const int quadHeight = 32;
|
|
|
|
if (width < quadWidth)
|
|
throw tcu::NotSupportedError("Too small render target");
|
|
|
|
const int maxQuadsX = width/quadWidth;
|
|
const int numVertices = MAX_VERTICES;
|
|
|
|
const int numQuads = numVertices/6 + (numVertices%6 != 0 ? 1 : 0);
|
|
const int viewportW = de::min(numQuads, maxQuadsX)*quadWidth;
|
|
const int viewportH = (numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0))*quadHeight;
|
|
|
|
if (viewportH > height)
|
|
throw tcu::NotSupportedError("Too small render target");
|
|
|
|
DE_ASSERT(viewportW <= width && viewportH <= height);
|
|
|
|
DE_ASSERT(!m_program);
|
|
m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
|
|
"#version 300 es\n"
|
|
"in highp vec4 a_position;\n"
|
|
"out mediump vec4 v_color;\n"
|
|
"uniform highp vec4 u_colors[24];\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
" v_color = u_colors[gl_VertexID];\n"
|
|
"}\n",
|
|
|
|
"#version 300 es\n"
|
|
"in mediump vec4 v_color;\n"
|
|
"layout(location = 0) out mediump vec4 o_color;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" o_color = v_color;\n"
|
|
"}\n"));
|
|
|
|
m_testCtx.getLog() << *m_program;
|
|
|
|
if (!m_program->isOk())
|
|
{
|
|
delete m_program;
|
|
m_program = DE_NULL;
|
|
throw tcu::TestError("Compile failed");
|
|
}
|
|
|
|
gl.genBuffers(1, &m_positionBuffer);
|
|
gl.genBuffers(1, &m_elementBuffer);
|
|
|
|
// Set colors (in dynamic memory to save static data space).
|
|
m_colors.resize(numVertices);
|
|
m_colors[ 0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
|
m_colors[ 1] = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f);
|
|
m_colors[ 2] = tcu::Vec4(0.0f, 0.5f, 1.0f, 1.0f);
|
|
m_colors[ 3] = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
|
|
m_colors[ 4] = tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f);
|
|
m_colors[ 5] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
|
|
m_colors[ 6] = tcu::Vec4(0.5f, 0.0f, 1.0f, 1.0f);
|
|
m_colors[ 7] = tcu::Vec4(0.5f, 0.0f, 0.5f, 1.0f);
|
|
m_colors[ 8] = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
|
m_colors[ 9] = tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f);
|
|
m_colors[10] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
|
|
m_colors[11] = tcu::Vec4(0.5f, 1.0f, 1.0f, 1.0f);
|
|
m_colors[12] = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
|
|
m_colors[13] = tcu::Vec4(1.0f, 0.0f, 0.5f, 1.0f);
|
|
m_colors[14] = tcu::Vec4(0.0f, 0.5f, 0.5f, 1.0f);
|
|
m_colors[15] = tcu::Vec4(1.0f, 1.0f, 0.5f, 1.0f);
|
|
m_colors[16] = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
|
|
m_colors[17] = tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f);
|
|
m_colors[18] = tcu::Vec4(0.0f, 1.0f, 0.5f, 1.0f);
|
|
m_colors[19] = tcu::Vec4(1.0f, 0.5f, 1.0f, 1.0f);
|
|
m_colors[20] = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
|
|
m_colors[21] = tcu::Vec4(1.0f, 0.5f, 0.5f, 1.0f);
|
|
m_colors[22] = tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f);
|
|
m_colors[23] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
// Compute positions.
|
|
m_positions.resize(numVertices);
|
|
DE_ASSERT(numVertices%3 == 0);
|
|
for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx += 3)
|
|
{
|
|
const float h = 2.0f * float(quadHeight)/float(viewportH);
|
|
const float w = 2.0f * float(quadWidth)/float(viewportW);
|
|
|
|
const int triNdx = vtxNdx/3;
|
|
const int quadNdx = triNdx/2;
|
|
const int quadY = quadNdx/maxQuadsX;
|
|
const int quadX = quadNdx%maxQuadsX;
|
|
|
|
const float x0 = -1.0f + float(quadX)*w;
|
|
const float y0 = -1.0f + float(quadY)*h;
|
|
|
|
if (triNdx%2 == 0)
|
|
{
|
|
m_positions[vtxNdx+0] = tcu::Vec4(x0, y0, 0.0f, 1.0f);
|
|
m_positions[vtxNdx+1] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
|
|
m_positions[vtxNdx+2] = tcu::Vec4(x0, y0+h, 0.0f, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
m_positions[vtxNdx+0] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
|
|
m_positions[vtxNdx+1] = tcu::Vec4(x0, y0, 0.0f, 1.0f);
|
|
m_positions[vtxNdx+2] = tcu::Vec4(x0+w, y0, 0.0f, 1.0f);
|
|
}
|
|
}
|
|
|
|
m_viewportW = viewportW;
|
|
m_viewportH = viewportH;
|
|
m_iterNdx = 0;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
}
|
|
|
|
void VertexIDCase::deinit (void)
|
|
{
|
|
delete m_program;
|
|
m_program = DE_NULL;
|
|
|
|
if (m_positionBuffer)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_positionBuffer);
|
|
m_positionBuffer = 0;
|
|
}
|
|
|
|
if (m_elementBuffer)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuffer);
|
|
m_elementBuffer = 0;
|
|
}
|
|
|
|
m_positions.clear();
|
|
m_colors.clear();
|
|
}
|
|
|
|
class VertexIDReferenceShader : public rr::VertexShader, public rr::FragmentShader
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
VARYINGLOC_COLOR = 0
|
|
};
|
|
|
|
VertexIDReferenceShader ()
|
|
: rr::VertexShader (2, 1) // color and pos in => color out
|
|
, rr::FragmentShader(1, 1) // color in => color out
|
|
{
|
|
this->rr::VertexShader::m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
|
|
this->rr::VertexShader::m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
|
|
|
|
this->rr::VertexShader::m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
|
|
this->rr::VertexShader::m_outputs[0].flatshade = false;
|
|
|
|
this->rr::FragmentShader::m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
|
|
this->rr::FragmentShader::m_inputs[0].flatshade = false;
|
|
|
|
this->rr::FragmentShader::m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
|
|
}
|
|
|
|
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
|
|
{
|
|
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
|
|
{
|
|
const int positionAttrLoc = 0;
|
|
const int colorAttrLoc = 1;
|
|
|
|
rr::VertexPacket& packet = *packets[packetNdx];
|
|
|
|
// Transform to position
|
|
packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
|
|
|
|
// Pass color to FS
|
|
packet.outputs[VARYINGLOC_COLOR] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
|
|
}
|
|
}
|
|
|
|
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
|
|
{
|
|
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
|
|
{
|
|
rr::FragmentPacket& packet = packets[packetNdx];
|
|
|
|
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
|
|
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
|
|
}
|
|
}
|
|
};
|
|
|
|
void VertexIDCase::renderReference (const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors, const int subpixelBits)
|
|
{
|
|
const rr::Renderer referenceRenderer;
|
|
const rr::RenderState referenceState ((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst)), subpixelBits);
|
|
const rr::RenderTarget referenceTarget (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst));
|
|
const VertexIDReferenceShader referenceShader;
|
|
rr::VertexAttrib attribs[2];
|
|
|
|
attribs[0].type = rr::VERTEXATTRIBTYPE_FLOAT;
|
|
attribs[0].size = 4;
|
|
attribs[0].stride = 0;
|
|
attribs[0].instanceDivisor = 0;
|
|
attribs[0].pointer = positions;
|
|
|
|
attribs[1].type = rr::VERTEXATTRIBTYPE_FLOAT;
|
|
attribs[1].size = 4;
|
|
attribs[1].stride = 0;
|
|
attribs[1].instanceDivisor = 0;
|
|
attribs[1].pointer = colors;
|
|
|
|
referenceRenderer.draw(
|
|
rr::DrawCommand(
|
|
referenceState,
|
|
referenceTarget,
|
|
rr::Program(&referenceShader, &referenceShader),
|
|
2,
|
|
attribs,
|
|
rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, numVertices, rr::DrawIndices(indices))));
|
|
}
|
|
|
|
VertexIDCase::IterateResult VertexIDCase::iterate (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const int width = m_context.getRenderTarget().getWidth();
|
|
const int height = m_context.getRenderTarget().getHeight();
|
|
const int viewportW = m_viewportW;
|
|
const int viewportH = m_viewportH;
|
|
|
|
const float threshold = 0.02f;
|
|
|
|
de::Random rnd (0xcf23ab1 ^ deInt32Hash(m_iterNdx));
|
|
tcu::Surface refImg (viewportW, viewportH);
|
|
tcu::Surface testImg (viewportW, viewportH);
|
|
|
|
const int viewportX = rnd.getInt(0, width-viewportW);
|
|
const int viewportY = rnd.getInt(0, height-viewportH);
|
|
|
|
const int posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position");
|
|
const int colorsLoc = gl.getUniformLocation(m_program->getProgram(), "u_colors[0]");
|
|
const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
// Setup common state.
|
|
gl.viewport (viewportX, viewportY, viewportW, viewportH);
|
|
gl.useProgram (m_program->getProgram());
|
|
gl.bindBuffer (GL_ARRAY_BUFFER, m_positionBuffer);
|
|
gl.enableVertexAttribArray (posLoc);
|
|
gl.vertexAttribPointer (posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
|
|
gl.uniform4fv (colorsLoc, (int)m_colors.size(), (const float*)&m_colors[0]);
|
|
|
|
// Clear render target to black.
|
|
gl.clearColor (clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
|
|
gl.clear (GL_COLOR_BUFFER_BIT);
|
|
|
|
tcu::clear(refImg.getAccess(), clearColor);
|
|
|
|
int subpixelBits= 0;
|
|
gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
|
|
|
|
if (m_iterNdx == 0)
|
|
{
|
|
tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter0", "glDrawArrays()");
|
|
vector<deUint16> indices (m_positions.size());
|
|
|
|
gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &m_positions[0], GL_DYNAMIC_DRAW);
|
|
gl.drawArrays(GL_TRIANGLES, 0, (int)m_positions.size());
|
|
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
|
|
|
|
// Reference indices
|
|
for (int ndx = 0; ndx < (int)indices.size(); ndx++)
|
|
indices[ndx] = (deUint16)ndx;
|
|
|
|
renderReference(refImg.getAccess(), (int)m_positions.size(), &indices[0], &m_positions[0], &m_colors[0], subpixelBits);
|
|
}
|
|
else if (m_iterNdx == 1)
|
|
{
|
|
tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter1", "glDrawElements(), indices in client-side array");
|
|
vector<deUint16> indices (m_positions.size());
|
|
vector<tcu::Vec4> mappedPos (m_positions.size());
|
|
|
|
// Compute initial indices and suffle
|
|
for (int ndx = 0; ndx < (int)indices.size(); ndx++)
|
|
indices[ndx] = (deUint16)ndx;
|
|
rnd.shuffle(indices.begin(), indices.end());
|
|
|
|
// Use indices to re-map positions.
|
|
for (int ndx = 0; ndx < (int)indices.size(); ndx++)
|
|
mappedPos[indices[ndx]] = m_positions[ndx];
|
|
|
|
gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
|
|
gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
|
|
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
|
|
|
|
renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0], subpixelBits);
|
|
}
|
|
else if (m_iterNdx == 2)
|
|
{
|
|
tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter2", "glDrawElements(), indices in buffer");
|
|
vector<deUint16> indices (m_positions.size());
|
|
vector<tcu::Vec4> mappedPos (m_positions.size());
|
|
|
|
// Compute initial indices and suffle
|
|
for (int ndx = 0; ndx < (int)indices.size(); ndx++)
|
|
indices[ndx] = (deUint16)ndx;
|
|
rnd.shuffle(indices.begin(), indices.end());
|
|
|
|
// Use indices to re-map positions.
|
|
for (int ndx = 0; ndx < (int)indices.size(); ndx++)
|
|
mappedPos[indices[ndx]] = m_positions[ndx];
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer);
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indices.size()*sizeof(deUint16)), &indices[0], GL_DYNAMIC_DRAW);
|
|
|
|
gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
|
|
gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, DE_NULL);
|
|
|
|
glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
|
|
|
|
tcu::clear(refImg.getAccess(), clearColor);
|
|
renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0], subpixelBits);
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
if (!tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT))
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
|
|
|
|
m_iterNdx += 1;
|
|
return (m_iterNdx < 3) ? CONTINUE : 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;
|
|
ShaderBuiltinConstantCase::GetConstantValueFunc getValue;
|
|
} builtinConstants[] =
|
|
{
|
|
// GLES 2.
|
|
|
|
{ "max_vertex_attribs", "gl_MaxVertexAttribs", getInteger<GL_MAX_VERTEX_ATTRIBS> },
|
|
{ "max_vertex_uniform_vectors", "gl_MaxVertexUniformVectors", getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS> },
|
|
{ "max_fragment_uniform_vectors", "gl_MaxFragmentUniformVectors", getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS> },
|
|
{ "max_texture_image_units", "gl_MaxTextureImageUnits", getInteger<GL_MAX_TEXTURE_IMAGE_UNITS> },
|
|
{ "max_vertex_texture_image_units", "gl_MaxVertexTextureImageUnits", getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS> },
|
|
{ "max_combined_texture_image_units", "gl_MaxCombinedTextureImageUnits", getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS> },
|
|
{ "max_draw_buffers", "gl_MaxDrawBuffers", getInteger<GL_MAX_DRAW_BUFFERS> },
|
|
|
|
// GLES 3.
|
|
|
|
{ "max_vertex_output_vectors", "gl_MaxVertexOutputVectors", getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS> },
|
|
{ "max_fragment_input_vectors", "gl_MaxFragmentInputVectors", getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS> },
|
|
{ "min_program_texel_offset", "gl_MinProgramTexelOffset", getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET> },
|
|
{ "max_program_texel_offset", "gl_MaxProgramTexelOffset", getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET> }
|
|
};
|
|
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++)
|
|
{
|
|
const char* const caseName = builtinConstants[ndx].caseName;
|
|
const char* const varName = builtinConstants[ndx].varName;
|
|
const ShaderBuiltinConstantCase::GetConstantValueFunc getValue = builtinConstants[ndx].getValue;
|
|
|
|
addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(), varName, varName, getValue, glu::SHADERTYPE_VERTEX));
|
|
addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(), varName, varName, getValue, glu::SHADERTYPE_FRAGMENT));
|
|
}
|
|
|
|
addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex", "gl_DepthRange", true));
|
|
addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment", "gl_DepthRange", false));
|
|
|
|
// Vertex shader builtin variables.
|
|
addChild(new VertexIDCase (m_context));
|
|
// \todo [2013-03-20 pyry] gl_InstanceID -- tested in instancing tests quite thoroughly.
|
|
|
|
// 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
|
|
} // gles3
|
|
} // deqp
|