| /*------------------------------------------------------------------------- |
| * 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 |