| /*------------------------------------------------------------------------- |
| * 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 Rbo state query tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es3fShaderStateQueryTests.hpp" |
| #include "glsStateQueryUtil.hpp" |
| #include "es3fApiCase.hpp" |
| #include "gluRenderContext.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "deRandom.hpp" |
| #include "deMath.h" |
| #include "deString.h" |
| |
| using namespace glw; // GLint and other GL types |
| using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard; |
| |
| namespace deqp |
| { |
| namespace gles3 |
| { |
| namespace Functional |
| { |
| namespace |
| { |
| |
| static const char* commonTestVertSource = "#version 300 es\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(0.0);\n" |
| "}\n\0"; |
| static const char* commonTestFragSource = "#version 300 es\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(0.0);\n" |
| "}\n\0"; |
| |
| static const char* brokenShader = "#version 300 es\n" |
| "broken, this should not compile!\n" |
| "\n\0"; |
| |
| // rounds x.1 to x+1 |
| template <typename T> |
| T roundGLfloatToNearestIntegerUp (GLfloat val) |
| { |
| return (T)(ceil(val)); |
| } |
| |
| // rounds x.9 to x |
| template <typename T> |
| T roundGLfloatToNearestIntegerDown (GLfloat val) |
| { |
| return (T)(floor(val)); |
| } |
| |
| bool checkIntEquals (tcu::TestContext& testCtx, GLint got, GLint expected) |
| { |
| using tcu::TestLog; |
| |
| if (got != expected) |
| { |
| testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage; |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value"); |
| return false; |
| } |
| return true; |
| } |
| |
| void checkPointerEquals (tcu::TestContext& testCtx, const void* got, const void* expected) |
| { |
| using tcu::TestLog; |
| |
| if (got != expected) |
| { |
| testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage; |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value"); |
| } |
| } |
| |
| void verifyShaderParam (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint shader, GLenum pname, GLenum reference) |
| { |
| StateQueryMemoryWriteGuard<GLint> state; |
| gl.glGetShaderiv(shader, pname, &state); |
| |
| if (state.verifyValidity(testCtx)) |
| checkIntEquals(testCtx, state, reference); |
| } |
| |
| bool verifyProgramParam (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLenum pname, GLenum reference) |
| { |
| StateQueryMemoryWriteGuard<GLint> state; |
| gl.glGetProgramiv(program, pname, &state); |
| |
| return state.verifyValidity(testCtx) && checkIntEquals(testCtx, state, reference); |
| } |
| |
| void verifyActiveUniformParam (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLuint index, GLenum pname, GLenum reference) |
| { |
| StateQueryMemoryWriteGuard<GLint> state; |
| gl.glGetActiveUniformsiv(program, 1, &index, pname, &state); |
| |
| if (state.verifyValidity(testCtx)) |
| checkIntEquals(testCtx, state, reference); |
| } |
| |
| void verifyActiveUniformBlockParam (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLuint blockIndex, GLenum pname, GLenum reference) |
| { |
| StateQueryMemoryWriteGuard<GLint> state; |
| gl.glGetActiveUniformBlockiv(program, blockIndex, pname, &state); |
| |
| if (state.verifyValidity(testCtx)) |
| checkIntEquals(testCtx, state, reference); |
| } |
| |
| void verifyCurrentVertexAttribf (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[4]> attribValue; |
| gl.glGetVertexAttribfv(index, GL_CURRENT_VERTEX_ATTRIB, attribValue); |
| |
| attribValue.verifyValidity(testCtx); |
| |
| if (attribValue[0] != x || attribValue[1] != y || attribValue[2] != z || attribValue[3] != w) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: Expected [" << x << "," << y << "," << z << "," << w << "];" |
| << "got [" << attribValue[0] << "," << attribValue[1] << "," << attribValue[2] << "," << attribValue[3] << "]" |
| << TestLog::EndMessage; |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid attribute value"); |
| } |
| } |
| |
| void verifyCurrentVertexAttribIi (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLint index, GLint x, GLint y, GLint z, GLint w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLint[4]> attribValue; |
| gl.glGetVertexAttribIiv(index, GL_CURRENT_VERTEX_ATTRIB, attribValue); |
| |
| attribValue.verifyValidity(testCtx); |
| |
| if (attribValue[0] != x || attribValue[1] != y || attribValue[2] != z || attribValue[3] != w) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: Expected [" << x << "," << y << "," << z << "," << w << "];" |
| << "got [" << attribValue[0] << "," << attribValue[1] << "," << attribValue[2] << "," << attribValue[3] << "]" |
| << TestLog::EndMessage; |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid attribute value"); |
| } |
| } |
| |
| void verifyCurrentVertexAttribIui (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLint index, GLuint x, GLuint y, GLuint z, GLuint w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLuint[4]> attribValue; |
| gl.glGetVertexAttribIuiv(index, GL_CURRENT_VERTEX_ATTRIB, attribValue); |
| |
| attribValue.verifyValidity(testCtx); |
| |
| if (attribValue[0] != x || attribValue[1] != y || attribValue[2] != z || attribValue[3] != w) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: Expected [" << x << "," << y << "," << z << "," << w << "];" |
| << "got [" << attribValue[0] << "," << attribValue[1] << "," << attribValue[2] << "," << attribValue[3] << "]" |
| << TestLog::EndMessage; |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid attribute value"); |
| } |
| } |
| |
| void verifyCurrentVertexAttribConversion (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLint[4]> attribValue; |
| gl.glGetVertexAttribiv(index, GL_CURRENT_VERTEX_ATTRIB, attribValue); |
| |
| attribValue.verifyValidity(testCtx); |
| |
| const GLint referenceAsGLintMin[] = |
| { |
| roundGLfloatToNearestIntegerDown<GLint>(x), |
| roundGLfloatToNearestIntegerDown<GLint>(y), |
| roundGLfloatToNearestIntegerDown<GLint>(z), |
| roundGLfloatToNearestIntegerDown<GLint>(w) |
| }; |
| const GLint referenceAsGLintMax[] = |
| { |
| roundGLfloatToNearestIntegerUp<GLint>(x), |
| roundGLfloatToNearestIntegerUp<GLint>(y), |
| roundGLfloatToNearestIntegerUp<GLint>(z), |
| roundGLfloatToNearestIntegerUp<GLint>(w) |
| }; |
| |
| if (attribValue[0] < referenceAsGLintMin[0] || attribValue[0] > referenceAsGLintMax[0] || |
| attribValue[1] < referenceAsGLintMin[1] || attribValue[1] > referenceAsGLintMax[1] || |
| attribValue[2] < referenceAsGLintMin[2] || attribValue[2] > referenceAsGLintMax[2] || |
| attribValue[3] < referenceAsGLintMin[3] || attribValue[3] > referenceAsGLintMax[3]) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected in range " |
| << "[" << referenceAsGLintMin[0] << " " << referenceAsGLintMax[0] << "], " |
| << "[" << referenceAsGLintMin[1] << " " << referenceAsGLintMax[1] << "], " |
| << "[" << referenceAsGLintMin[2] << " " << referenceAsGLintMax[2] << "], " |
| << "[" << referenceAsGLintMin[3] << " " << referenceAsGLintMax[3] << "]" |
| << "; got " |
| << attribValue[0] << ", " |
| << attribValue[1] << ", " |
| << attribValue[2] << ", " |
| << attribValue[3] << " " |
| << "; Input=" |
| << x << "; " |
| << y << "; " |
| << z << "; " |
| << w << " " << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid attribute value"); |
| } |
| } |
| |
| void verifyVertexAttrib (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLint index, GLenum pname, GLenum reference) |
| { |
| StateQueryMemoryWriteGuard<GLint> state; |
| gl.glGetVertexAttribIiv(index, pname, &state); |
| |
| if (state.verifyValidity(testCtx)) |
| checkIntEquals(testCtx, state, reference); |
| } |
| |
| void verifyUniformValue1f (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, float x) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[1]> state; |
| gl.glGetUniformfv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x |
| << "]; got [" |
| << state[0] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue2f (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, float x, float y) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[2]> state; |
| gl.glGetUniformfv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue3f (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, float x, float y, float z) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[3]> state; |
| gl.glGetUniformfv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y || |
| state[2] != z) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y << ", " |
| << z |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] << ", " |
| << state[2] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue4f (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, float x, float y, float z, float w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[4]> state; |
| gl.glGetUniformfv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y || |
| state[2] != z || |
| state[3] != w) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y << ", " |
| << z << ", " |
| << w |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] << ", " |
| << state[2] << ", " |
| << state[3] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue1i (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLint x) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLint[1]> state; |
| gl.glGetUniformiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x |
| << "]; got [" |
| << state[0] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue2i (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLint x, GLint y) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLint[2]> state; |
| gl.glGetUniformiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue3i (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLint x, GLint y, GLint z) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLint[3]> state; |
| gl.glGetUniformiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y || |
| state[2] != z) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y << ", " |
| << z |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] << ", " |
| << state[2] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue4i (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLint[4]> state; |
| gl.glGetUniformiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y || |
| state[2] != z || |
| state[3] != w) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y << ", " |
| << z << ", " |
| << w |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] << ", " |
| << state[2] << ", " |
| << state[3] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue1ui (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLuint x) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLuint[1]> state; |
| gl.glGetUniformuiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x |
| << "]; got [" |
| << state[0] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue2ui (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLuint x, GLuint y) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLuint[2]> state; |
| gl.glGetUniformuiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue3ui (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLuint x, GLuint y, GLuint z) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLuint[3]> state; |
| gl.glGetUniformuiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y || |
| state[2] != z) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y << ", " |
| << z |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] << ", " |
| << state[2] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| void verifyUniformValue4ui (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, GLuint x, GLuint y, GLuint z, GLuint w) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLuint[4]> state; |
| gl.glGetUniformuiv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| if (state[0] != x || |
| state[1] != y || |
| state[2] != z || |
| state[3] != w) |
| { |
| testCtx.getLog() << TestLog::Message |
| << "// ERROR: expected [" |
| << x << ", " |
| << y << ", " |
| << z << ", " |
| << w |
| << "]; got [" |
| << state[0] << ", " |
| << state[1] << ", " |
| << state[2] << ", " |
| << state[3] |
| << "]" |
| << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| |
| template <int Count> |
| void verifyUniformValues (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, const GLfloat* values) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[Count]> state; |
| gl.glGetUniformfv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| for (int ndx = 0; ndx < Count; ++ndx) |
| { |
| if (values[ndx] != state[ndx]) |
| { |
| testCtx.getLog() << TestLog::Message << "// ERROR: at index " << ndx << " expected " << values[ndx] << "; got " << state[ndx] << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| } |
| |
| template <int N> |
| void verifyUniformMatrixValues (tcu::TestContext& testCtx, glu::CallLogWrapper& gl, GLuint program, GLint location, const GLfloat* values, bool transpose) |
| { |
| using tcu::TestLog; |
| |
| StateQueryMemoryWriteGuard<GLfloat[N*N]> state; |
| gl.glGetUniformfv(program, location, state); |
| |
| if (!state.verifyValidity(testCtx)) |
| return; |
| |
| for (int y = 0; y < N; ++y) |
| for (int x = 0; x < N; ++x) |
| { |
| const int refIndex = y*N + x; |
| const int stateIndex = transpose ? (x*N + y) : (y*N + x); |
| |
| if (values[refIndex] != state[stateIndex]) |
| { |
| testCtx.getLog() << TestLog::Message << "// ERROR: at index [" << y << "][" << x << "] expected " << values[refIndex] << "; got " << state[stateIndex] << TestLog::EndMessage; |
| |
| if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid uniform value"); |
| } |
| } |
| } |
| |
| class ShaderTypeCase : public ApiCase |
| { |
| public: |
| ShaderTypeCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| const GLenum shaderTypes[] = {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}; |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(shaderTypes); ++ndx) |
| { |
| const GLuint shader = glCreateShader(shaderTypes[ndx]); |
| verifyShaderParam(m_testCtx, *this, shader, GL_SHADER_TYPE, shaderTypes[ndx]); |
| glDeleteShader(shader); |
| } |
| } |
| }; |
| |
| class ShaderCompileStatusCase : public ApiCase |
| { |
| public: |
| ShaderCompileStatusCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| verifyShaderParam(m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_FALSE); |
| verifyShaderParam(m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_FALSE); |
| |
| glShaderSource(shaderVert, 1, &commonTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &commonTestFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| verifyShaderParam(m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_TRUE); |
| verifyShaderParam(m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_TRUE); |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ShaderInfoLogCase : public ApiCase |
| { |
| public: |
| ShaderInfoLogCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| // INFO_LOG_LENGTH is 0 by default and it includes null-terminator |
| const GLuint shader = glCreateShader(GL_VERTEX_SHADER); |
| verifyShaderParam(m_testCtx, *this, shader, GL_INFO_LOG_LENGTH, 0); |
| |
| glShaderSource(shader, 1, &brokenShader, DE_NULL); |
| glCompileShader(shader); |
| expectError(GL_NO_ERROR); |
| |
| // check the log length |
| StateQueryMemoryWriteGuard<GLint> logLength; |
| glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); |
| if (!logLength.verifyValidity(m_testCtx)) |
| { |
| glDeleteShader(shader); |
| return; |
| } |
| if (logLength == 0) |
| { |
| glDeleteShader(shader); |
| return; |
| } |
| |
| // check normal case |
| { |
| char buffer[2048] = {'x'}; // non-zero initialization |
| |
| GLint written = 0; // written does not include null terminator |
| glGetShaderInfoLog(shader, DE_LENGTH_OF_ARRAY(buffer), &written, buffer); |
| |
| // check lengths are consistent |
| if (logLength <= DE_LENGTH_OF_ARRAY(buffer)) |
| { |
| if (written != logLength-1) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected length " << logLength-1 << "; got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log length"); |
| } |
| } |
| |
| // check null-terminator, either at end of buffer or at buffer[written] |
| const char* terminator = &buffer[DE_LENGTH_OF_ARRAY(buffer) - 1]; |
| if (logLength < DE_LENGTH_OF_ARRAY(buffer)) |
| terminator = &buffer[written]; |
| |
| if (*terminator != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator, got " << (int)*terminator << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log terminator"); |
| } |
| } |
| |
| // check with too small buffer |
| { |
| char buffer[2048] = {'x'}; // non-zero initialization |
| |
| // check string always ends with \0, even with small buffers |
| GLint written = 0; |
| glGetShaderInfoLog(shader, 1, &written, buffer); |
| if (written != 0) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected length 0; got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log length"); |
| } |
| if (buffer[0] != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator, got " << (int)buffer[0] << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log terminator"); |
| } |
| } |
| |
| glDeleteShader(shader); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ShaderSourceCase : public ApiCase |
| { |
| public: |
| ShaderSourceCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| // SHADER_SOURCE_LENGTH does include 0-terminator |
| const GLuint shader = glCreateShader(GL_VERTEX_SHADER); |
| verifyShaderParam(m_testCtx, *this, shader, GL_SHADER_SOURCE_LENGTH, 0); |
| |
| // check the SHADER_SOURCE_LENGTH |
| { |
| glShaderSource(shader, 1, &brokenShader, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| StateQueryMemoryWriteGuard<GLint> sourceLength; |
| glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLength); |
| |
| sourceLength.verifyValidity(m_testCtx); |
| |
| const GLint referenceLength = (GLint)std::string(brokenShader).length() + 1; // including the null terminator |
| if (sourceLength != referenceLength) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected length " << referenceLength << "; got " << sourceLength << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid source length"); |
| } |
| } |
| |
| // check the concat source SHADER_SOURCE_LENGTH |
| { |
| const char* shaders[] = {brokenShader, brokenShader}; |
| glShaderSource(shader, 2, shaders, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| StateQueryMemoryWriteGuard<GLint> sourceLength; |
| glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLength); |
| |
| sourceLength.verifyValidity(m_testCtx); |
| |
| const GLint referenceLength = 2 * (GLint)std::string(brokenShader).length() + 1; // including the null terminator |
| if (sourceLength != referenceLength) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected length " << referenceLength << "; got " << sourceLength << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid source length"); |
| } |
| } |
| |
| // check the string length |
| { |
| char buffer[2048] = {'x'}; |
| DE_ASSERT(DE_LENGTH_OF_ARRAY(buffer) > 2 * (int)std::string(brokenShader).length()); |
| |
| GLint written = 0; // not inluding null-terminator |
| glGetShaderSource(shader, DE_LENGTH_OF_ARRAY(buffer), &written, buffer); |
| |
| const GLint referenceLength = 2 * (GLint)std::string(brokenShader).length(); |
| if (written != referenceLength) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected write length " << referenceLength << "; got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid source length"); |
| } |
| // check null pointer at |
| else |
| { |
| if (buffer[referenceLength] != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator at " << referenceLength << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "did not get a null terminator"); |
| } |
| } |
| } |
| |
| // check with small buffer |
| { |
| char buffer[2048] = {'x'}; |
| |
| GLint written = 0; |
| glGetShaderSource(shader, 1, &written, buffer); |
| |
| if (written != 0) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected write length 0; got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid source length"); |
| } |
| if (buffer[0] != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator; got=" << int(buffer[0]) << ", char=" << buffer[0] << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid terminator"); |
| } |
| } |
| |
| glDeleteShader(shader); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class DeleteStatusCase : public ApiCase |
| { |
| public: |
| DeleteStatusCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &commonTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &commonTestFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| verifyShaderParam(m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_TRUE); |
| verifyShaderParam(m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_TRUE); |
| |
| GLuint shaderProg = glCreateProgram(); |
| glAttachShader(shaderProg, shaderVert); |
| glAttachShader(shaderProg, shaderFrag); |
| glLinkProgram(shaderProg); |
| expectError(GL_NO_ERROR); |
| |
| verifyProgramParam (m_testCtx, *this, shaderProg, GL_LINK_STATUS, GL_TRUE); |
| |
| verifyShaderParam (m_testCtx, *this, shaderVert, GL_DELETE_STATUS, GL_FALSE); |
| verifyShaderParam (m_testCtx, *this, shaderFrag, GL_DELETE_STATUS, GL_FALSE); |
| verifyProgramParam (m_testCtx, *this, shaderProg, GL_DELETE_STATUS, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| glUseProgram(shaderProg); |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(shaderProg); |
| expectError(GL_NO_ERROR); |
| |
| verifyShaderParam (m_testCtx, *this, shaderVert, GL_DELETE_STATUS, GL_TRUE); |
| verifyShaderParam (m_testCtx, *this, shaderFrag, GL_DELETE_STATUS, GL_TRUE); |
| verifyProgramParam (m_testCtx, *this, shaderProg, GL_DELETE_STATUS, GL_TRUE); |
| expectError(GL_NO_ERROR); |
| |
| glUseProgram(0); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class CurrentVertexAttribInitialCase : public ApiCase |
| { |
| public: |
| CurrentVertexAttribInitialCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| int attribute_count = 16; |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribute_count); |
| |
| // initial |
| |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| StateQueryMemoryWriteGuard<GLfloat[4]> attribValue; |
| glGetVertexAttribfv(index, GL_CURRENT_VERTEX_ATTRIB, attribValue); |
| attribValue.verifyValidity(m_testCtx); |
| |
| if (attribValue[0] != 0.0f || attribValue[1] != 0.0f || attribValue[2] != 0.0f || attribValue[3] != 1.0f) |
| { |
| m_testCtx.getLog() << TestLog::Message |
| << "// ERROR: Expected [0, 0, 0, 1];" |
| << "got [" << attribValue[0] << "," << attribValue[1] << "," << attribValue[2] << "," << attribValue[3] << "]" |
| << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid attribute value"); |
| } |
| } |
| } |
| }; |
| |
| class CurrentVertexAttribFloatCase : public ApiCase |
| { |
| public: |
| CurrentVertexAttribFloatCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| de::Random rnd(0xabcdef); |
| |
| int attribute_count = 16; |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribute_count); |
| |
| // test write float/read float |
| |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = rnd.getFloat(-64000, 64000); |
| const GLfloat z = rnd.getFloat(-64000, 64000); |
| const GLfloat w = rnd.getFloat(-64000, 64000); |
| |
| glVertexAttrib4f(index, x, y, z, w); |
| verifyCurrentVertexAttribf(m_testCtx, *this, index, x, y, z, w); |
| } |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = rnd.getFloat(-64000, 64000); |
| const GLfloat z = rnd.getFloat(-64000, 64000); |
| const GLfloat w = 1.0f; |
| |
| glVertexAttrib3f(index, x, y, z); |
| verifyCurrentVertexAttribf(m_testCtx, *this, index, x, y, z, w); |
| } |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = rnd.getFloat(-64000, 64000); |
| const GLfloat z = 0.0f; |
| const GLfloat w = 1.0f; |
| |
| glVertexAttrib2f(index, x, y); |
| verifyCurrentVertexAttribf(m_testCtx, *this, index, x, y, z, w); |
| } |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = 0.0f; |
| const GLfloat z = 0.0f; |
| const GLfloat w = 1.0f; |
| |
| glVertexAttrib1f(index, x); |
| verifyCurrentVertexAttribf(m_testCtx, *this, index, x, y, z, w); |
| } |
| } |
| }; |
| |
| class CurrentVertexAttribIntCase : public ApiCase |
| { |
| public: |
| CurrentVertexAttribIntCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| de::Random rnd(0xabcdef); |
| |
| int attribute_count = 16; |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribute_count); |
| |
| // test write float/read float |
| |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLint x = rnd.getInt(-64000, 64000); |
| const GLint y = rnd.getInt(-64000, 64000); |
| const GLint z = rnd.getInt(-64000, 64000); |
| const GLint w = rnd.getInt(-64000, 64000); |
| |
| glVertexAttribI4i(index, x, y, z, w); |
| verifyCurrentVertexAttribIi(m_testCtx, *this, index, x, y, z, w); |
| } |
| } |
| }; |
| |
| class CurrentVertexAttribUintCase : public ApiCase |
| { |
| public: |
| CurrentVertexAttribUintCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| de::Random rnd(0xabcdef); |
| |
| int attribute_count = 16; |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribute_count); |
| |
| // test write float/read float |
| |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLuint x = rnd.getInt(0, 64000); |
| const GLuint y = rnd.getInt(0, 64000); |
| const GLuint z = rnd.getInt(0, 64000); |
| const GLuint w = rnd.getInt(0, 64000); |
| |
| glVertexAttribI4ui(index, x, y, z, w); |
| verifyCurrentVertexAttribIui(m_testCtx, *this, index, x, y, z, w); |
| } |
| } |
| }; |
| |
| class CurrentVertexAttribConversionCase : public ApiCase |
| { |
| public: |
| CurrentVertexAttribConversionCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| de::Random rnd(0xabcdef); |
| |
| int attribute_count = 16; |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribute_count); |
| |
| // test write float/read float |
| |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = rnd.getFloat(-64000, 64000); |
| const GLfloat z = rnd.getFloat(-64000, 64000); |
| const GLfloat w = rnd.getFloat(-64000, 64000); |
| |
| glVertexAttrib4f(index, x, y, z, w); |
| verifyCurrentVertexAttribConversion(m_testCtx, *this, index, x, y, z, w); |
| } |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = rnd.getFloat(-64000, 64000); |
| const GLfloat z = rnd.getFloat(-64000, 64000); |
| const GLfloat w = 1.0f; |
| |
| glVertexAttrib3f(index, x, y, z); |
| verifyCurrentVertexAttribConversion(m_testCtx, *this, index, x, y, z, w); |
| } |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = rnd.getFloat(-64000, 64000); |
| const GLfloat z = 0.0f; |
| const GLfloat w = 1.0f; |
| |
| glVertexAttrib2f(index, x, y); |
| verifyCurrentVertexAttribConversion(m_testCtx, *this, index, x, y, z, w); |
| } |
| for (int index = 0; index < attribute_count; ++index) |
| { |
| const GLfloat x = rnd.getFloat(-64000, 64000); |
| const GLfloat y = 0.0f; |
| const GLfloat z = 0.0f; |
| const GLfloat w = 1.0f; |
| |
| glVertexAttrib1f(index, x); |
| verifyCurrentVertexAttribConversion(m_testCtx, *this, index, x, y, z, w); |
| } |
| } |
| }; |
| |
| class ProgramInfoLogCase : public ApiCase |
| { |
| public: |
| enum BuildErrorType |
| { |
| BUILDERROR_COMPILE = 0, |
| BUILDERROR_LINK |
| }; |
| |
| ProgramInfoLogCase (Context& context, const char* name, const char* description, BuildErrorType buildErrorType) |
| : ApiCase (context, name, description) |
| , m_buildErrorType (buildErrorType) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| enum |
| { |
| BUF_SIZE = 2048 |
| }; |
| |
| static const char* const linkErrorVtxSource = "#version 300 es\n" |
| "in highp vec4 a_pos;\n" |
| "uniform highp vec4 u_uniform;\n" |
| "void main ()\n" |
| "{\n" |
| " gl_Position = a_pos + u_uniform;\n" |
| "}\n"; |
| static const char* const linkErrorFrgSource = "#version 300 es\n" |
| "in highp vec4 v_missingVar;\n" |
| "uniform highp int u_uniform;\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main ()\n" |
| "{\n" |
| " fragColor = v_missingVar + vec4(float(u_uniform));\n" |
| "}\n"; |
| |
| const char* vtxSource = (m_buildErrorType == BUILDERROR_COMPILE) ? (brokenShader) : (linkErrorVtxSource); |
| const char* frgSource = (m_buildErrorType == BUILDERROR_COMPILE) ? (brokenShader) : (linkErrorFrgSource); |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &vtxSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &frgSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| |
| StateQueryMemoryWriteGuard<GLint> logLength; |
| glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); |
| logLength.verifyValidity(m_testCtx); |
| |
| // check INFO_LOG_LENGTH == GetProgramInfoLog len |
| { |
| const tcu::ScopedLogSection section (m_testCtx.getLog(), "QueryLarge", "Query to large buffer"); |
| char buffer[BUF_SIZE] = {'x'}; |
| GLint written = 0; |
| |
| glGetProgramInfoLog(program, BUF_SIZE, &written, buffer); |
| |
| if (logLength != 0 && written+1 != logLength) // INFO_LOG_LENGTH contains 0-terminator |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected INFO_LOG_LENGTH " << written+1 << "; got " << logLength << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log length"); |
| } |
| else if (logLength != 0 && buffer[written] != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator at index " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing null terminator"); |
| } |
| } |
| |
| // check query to just correct sized buffer |
| if (BUF_SIZE > logLength) |
| { |
| const tcu::ScopedLogSection section (m_testCtx.getLog(), "QueryAll", "Query all to exactly right sized buffer"); |
| char buffer[BUF_SIZE] = {'x'}; |
| GLint written = 0; |
| |
| glGetProgramInfoLog(program, logLength, &written, buffer); |
| |
| if (logLength != 0 && written+1 != logLength) // INFO_LOG_LENGTH contains 0-terminator |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected INFO_LOG_LENGTH " << written+1 << "; got " << logLength << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log length"); |
| } |
| else if (logLength != 0 && buffer[written] != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator at index " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing null terminator"); |
| } |
| } |
| |
| // check GetProgramInfoLog works with too small buffer |
| { |
| const tcu::ScopedLogSection section (m_testCtx.getLog(), "QueryNone", "Query none"); |
| char buffer[BUF_SIZE] = {'x'}; |
| GLint written = 0; |
| |
| glGetProgramInfoLog(program, 1, &written, buffer); |
| |
| if (written != 0) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected write length 0; got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid log length"); |
| } |
| } |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| |
| const BuildErrorType m_buildErrorType; |
| }; |
| |
| class ProgramValidateStatusCase : public ApiCase |
| { |
| public: |
| ProgramValidateStatusCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| // test validate ok |
| { |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &commonTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &commonTestFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| verifyShaderParam (m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_TRUE); |
| verifyShaderParam (m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_TRUE); |
| verifyProgramParam (m_testCtx, *this, program, GL_LINK_STATUS, GL_TRUE); |
| |
| glValidateProgram(program); |
| verifyProgramParam(m_testCtx, *this, program, GL_VALIDATE_STATUS, GL_TRUE); |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| |
| // test with broken shader |
| { |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &commonTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &brokenShader, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| verifyShaderParam (m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_TRUE); |
| verifyShaderParam (m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_FALSE); |
| verifyProgramParam (m_testCtx, *this, program, GL_LINK_STATUS, GL_FALSE); |
| |
| glValidateProgram(program); |
| verifyProgramParam(m_testCtx, *this, program, GL_VALIDATE_STATUS, GL_FALSE); |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class ProgramAttachedShadersCase : public ApiCase |
| { |
| public: |
| ProgramAttachedShadersCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &commonTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &commonTestFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| // check ATTACHED_SHADERS |
| |
| GLuint program = glCreateProgram(); |
| verifyProgramParam(m_testCtx, *this, program, GL_ATTACHED_SHADERS, 0); |
| expectError(GL_NO_ERROR); |
| |
| glAttachShader(program, shaderVert); |
| verifyProgramParam(m_testCtx, *this, program, GL_ATTACHED_SHADERS, 1); |
| expectError(GL_NO_ERROR); |
| |
| glAttachShader(program, shaderFrag); |
| verifyProgramParam(m_testCtx, *this, program, GL_ATTACHED_SHADERS, 2); |
| expectError(GL_NO_ERROR); |
| |
| // check GetAttachedShaders |
| { |
| GLuint shaders[2] = {0, 0}; |
| GLint count = 0; |
| glGetAttachedShaders(program, DE_LENGTH_OF_ARRAY(shaders), &count, shaders); |
| |
| if (count != 2) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected 2; got " << count << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong shader count"); |
| } |
| // shaders are the attached shaders? |
| if (!((shaders[0] == shaderVert && shaders[1] == shaderFrag) || |
| (shaders[0] == shaderFrag && shaders[1] == shaderVert))) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected {" << shaderVert << ", " << shaderFrag << "}; got {" << shaders[0] << ", " << shaders[1] << "}" << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong shader count"); |
| } |
| } |
| |
| // check GetAttachedShaders with too small buffer |
| { |
| GLuint shaders[2] = {0, 0}; |
| GLint count = 0; |
| |
| glGetAttachedShaders(program, 0, &count, shaders); |
| if (count != 0) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected 0; got " << count << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong shader count"); |
| } |
| |
| count = 0; |
| glGetAttachedShaders(program, 1, &count, shaders); |
| if (count != 1) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected 1; got " << count << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong shader count"); |
| } |
| } |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ProgramActiveUniformNameCase : public ApiCase |
| { |
| public: |
| ProgramActiveUniformNameCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform highp float uniformNameWithLength23;\n" |
| "uniform highp vec2 uniformVec2;\n" |
| "uniform highp mat4 uniformMat4;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(0.0) + vec4(uniformNameWithLength23) + vec4(uniformVec2.x) + vec4(uniformMat4[2][3]);\n" |
| "}\n\0"; |
| static const char* testFragSource = |
| "#version 300 es\n" |
| "layout(location = 0) out mediump vec4 fragColor;" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(0.0);\n" |
| "}\n\0"; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &testVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| verifyProgramParam(m_testCtx, *this, program, GL_ACTIVE_UNIFORMS, 3); |
| verifyProgramParam(m_testCtx, *this, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, (GLint)std::string("uniformNameWithLength23").length() + 1); // including a null terminator |
| expectError(GL_NO_ERROR); |
| |
| const char* uniformNames[] = |
| { |
| "uniformNameWithLength23", |
| "uniformVec2", |
| "uniformMat4" |
| }; |
| StateQueryMemoryWriteGuard<GLuint[DE_LENGTH_OF_ARRAY(uniformNames)]> uniformIndices; |
| glGetUniformIndices(program, DE_LENGTH_OF_ARRAY(uniformNames), uniformNames, uniformIndices); |
| uniformIndices.verifyValidity(m_testCtx); |
| |
| // check name lengths |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(uniformNames); ++ndx) |
| { |
| const GLuint uniformIndex = uniformIndices[ndx]; |
| |
| StateQueryMemoryWriteGuard<GLint> uniformNameLen; |
| glGetActiveUniformsiv(program, 1, &uniformIndex, GL_UNIFORM_NAME_LENGTH, &uniformNameLen); |
| |
| uniformNameLen.verifyValidity(m_testCtx); |
| |
| const GLint referenceLength = (GLint)std::string(uniformNames[ndx]).length() + 1; |
| if (referenceLength != uniformNameLen) // uniformNameLen is with null terminator |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << referenceLength << "got " << uniformNameLen << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong uniform name length"); |
| } |
| } |
| |
| // check names |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(uniformNames); ++ndx) |
| { |
| char buffer[2048] = {'x'}; |
| |
| const GLuint uniformIndex = uniformIndices[ndx]; |
| |
| GLint written = 0; // null terminator not included |
| GLint size = 0; |
| GLenum type = 0; |
| glGetActiveUniform(program, uniformIndex, DE_LENGTH_OF_ARRAY(buffer), &written, &size, &type, buffer); |
| |
| const GLint referenceLength = (GLint)std::string(uniformNames[ndx]).length(); |
| if (referenceLength != written) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << referenceLength << "got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong uniform name length"); |
| } |
| |
| // and with too small buffer |
| written = 0; |
| glGetActiveUniform(program, uniformIndex, 1, &written, &size, &type, buffer); |
| |
| if (written != 0) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected 0 got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong uniform name length"); |
| } |
| } |
| |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ProgramUniformCase : public ApiCase |
| { |
| public: |
| ProgramUniformCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| const struct UniformType |
| { |
| const char* declaration; |
| const char* postDeclaration; |
| const char* precision; |
| const char* layout; |
| const char* getter; |
| GLenum type; |
| GLint size; |
| GLint isRowMajor; |
| } uniformTypes[] = |
| { |
| { "float", "", "highp", "", "uniformValue", GL_FLOAT, 1, GL_FALSE }, |
| { "float[2]", "", "highp", "", "uniformValue[1]", GL_FLOAT, 2, GL_FALSE }, |
| { "vec2", "", "highp", "", "uniformValue.x", GL_FLOAT_VEC2, 1, GL_FALSE }, |
| { "vec3", "", "highp", "", "uniformValue.x", GL_FLOAT_VEC3, 1, GL_FALSE }, |
| { "vec4", "", "highp", "", "uniformValue.x", GL_FLOAT_VEC4, 1, GL_FALSE }, |
| { "int", "", "highp", "", "float(uniformValue)", GL_INT, 1, GL_FALSE }, |
| { "ivec2", "", "highp", "", "float(uniformValue.x)", GL_INT_VEC2, 1, GL_FALSE }, |
| { "ivec3", "", "highp", "", "float(uniformValue.x)", GL_INT_VEC3, 1, GL_FALSE }, |
| { "ivec4", "", "highp", "", "float(uniformValue.x)", GL_INT_VEC4, 1, GL_FALSE }, |
| { "uint", "", "highp", "", "float(uniformValue)", GL_UNSIGNED_INT, 1, GL_FALSE }, |
| { "uvec2", "", "highp", "", "float(uniformValue.x)", GL_UNSIGNED_INT_VEC2, 1, GL_FALSE }, |
| { "uvec3", "", "highp", "", "float(uniformValue.x)", GL_UNSIGNED_INT_VEC3, 1, GL_FALSE }, |
| { "uvec4", "", "highp", "", "float(uniformValue.x)", GL_UNSIGNED_INT_VEC4, 1, GL_FALSE }, |
| { "bool", "", "", "", "float(uniformValue)", GL_BOOL, 1, GL_FALSE }, |
| { "bvec2", "", "", "", "float(uniformValue.x)", GL_BOOL_VEC2, 1, GL_FALSE }, |
| { "bvec3", "", "", "", "float(uniformValue.x)", GL_BOOL_VEC3, 1, GL_FALSE }, |
| { "bvec4", "", "", "", "float(uniformValue.x)", GL_BOOL_VEC4, 1, GL_FALSE }, |
| { "mat2", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT2, 1, GL_FALSE }, |
| { "mat3", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT3, 1, GL_FALSE }, |
| { "mat4", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT4, 1, GL_FALSE }, |
| { "mat2x3", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT2x3, 1, GL_FALSE }, |
| { "mat2x4", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT2x4, 1, GL_FALSE }, |
| { "mat3x2", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT3x2, 1, GL_FALSE }, |
| { "mat3x4", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT3x4, 1, GL_FALSE }, |
| { "mat4x2", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT4x2, 1, GL_FALSE }, |
| { "mat4x3", "", "highp", "", "float(uniformValue[0][0])", GL_FLOAT_MAT4x3, 1, GL_FALSE }, |
| { "sampler2D", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_2D, 1, GL_FALSE }, |
| { "sampler3D", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_3D, 1, GL_FALSE }, |
| { "samplerCube", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_CUBE, 1, GL_FALSE }, |
| { "sampler2DShadow", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_2D_SHADOW, 1, GL_FALSE }, |
| { "sampler2DArray", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_2D_ARRAY, 1, GL_FALSE }, |
| { "sampler2DArrayShadow", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_2D_ARRAY_SHADOW, 1, GL_FALSE }, |
| { "samplerCubeShadow", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_SAMPLER_CUBE_SHADOW, 1, GL_FALSE }, |
| { "isampler2D", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_INT_SAMPLER_2D, 1, GL_FALSE }, |
| { "isampler3D", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_INT_SAMPLER_3D, 1, GL_FALSE }, |
| { "isamplerCube", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_INT_SAMPLER_CUBE, 1, GL_FALSE }, |
| { "isampler2DArray", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_INT_SAMPLER_2D_ARRAY, 1, GL_FALSE }, |
| { "usampler2D", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_UNSIGNED_INT_SAMPLER_2D, 1, GL_FALSE }, |
| { "usampler3D", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_UNSIGNED_INT_SAMPLER_3D, 1, GL_FALSE }, |
| { "usamplerCube", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_UNSIGNED_INT_SAMPLER_CUBE, 1, GL_FALSE }, |
| { "usampler2DArray", "", "highp", "", "float(textureSize(uniformValue,0).r)", GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, 1, GL_FALSE }, |
| }; |
| |
| static const char* vertSource = |
| "#version 300 es\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(0.0);\n" |
| "}\n\0"; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| GLuint program = glCreateProgram(); |
| |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| |
| glShaderSource(shaderVert, 1, &vertSource, DE_NULL); |
| glCompileShader(shaderVert); |
| expectError(GL_NO_ERROR); |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(uniformTypes); ++ndx) |
| { |
| tcu::ScopedLogSection(m_log, uniformTypes[ndx].declaration, std::string("Verify type of ") + uniformTypes[ndx].declaration + " variable" + uniformTypes[ndx].postDeclaration ); |
| |
| // gen fragment shader |
| |
| std::ostringstream frag; |
| frag << "#version 300 es\n"; |
| frag << uniformTypes[ndx].layout << "uniform " << uniformTypes[ndx].precision << " " << uniformTypes[ndx].declaration << " uniformValue" << uniformTypes[ndx].postDeclaration << ";\n"; |
| frag << "layout(location = 0) out mediump vec4 fragColor;\n"; |
| frag << "void main (void)\n"; |
| frag << "{\n"; |
| frag << " fragColor = vec4(" << uniformTypes[ndx].getter << ");\n"; |
| frag << "}\n"; |
| |
| { |
| std::string fragmentSource = frag.str(); |
| const char* fragmentSourceCStr = fragmentSource.c_str(); |
| glShaderSource(shaderFrag, 1, &fragmentSourceCStr, DE_NULL); |
| } |
| |
| // compile & link |
| |
| glCompileShader(shaderFrag); |
| glLinkProgram(program); |
| |
| // test |
| if (verifyProgramParam(m_testCtx, *this, program, GL_LINK_STATUS, GL_TRUE)) |
| { |
| const char* uniformNames[] = {"uniformValue"}; |
| StateQueryMemoryWriteGuard<GLuint> uniformIndex; |
| glGetUniformIndices(program, 1, uniformNames, &uniformIndex); |
| uniformIndex.verifyValidity(m_testCtx); |
| |
| verifyActiveUniformParam(m_testCtx, *this, program, uniformIndex, GL_UNIFORM_TYPE, uniformTypes[ndx].type); |
| verifyActiveUniformParam(m_testCtx, *this, program, uniformIndex, GL_UNIFORM_SIZE, uniformTypes[ndx].size); |
| verifyActiveUniformParam(m_testCtx, *this, program, uniformIndex, GL_UNIFORM_IS_ROW_MAJOR, uniformTypes[ndx].isRowMajor); |
| } |
| } |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ProgramActiveUniformBlocksCase : public ApiCase |
| { |
| public: |
| ProgramActiveUniformBlocksCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform longlongUniformBlockName {highp vec2 vector2;} longlongUniformInstanceName;\n" |
| "uniform shortUniformBlockName {highp vec2 vector2;highp vec4 vector4;} shortUniformInstanceName;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = shortUniformInstanceName.vector4 + vec4(longlongUniformInstanceName.vector2.x) + vec4(shortUniformInstanceName.vector2.x);\n" |
| "}\n\0"; |
| static const char* testFragSource = |
| "#version 300 es\n" |
| "uniform longlongUniformBlockName {highp vec2 vector2;} longlongUniformInstanceName;\n" |
| "layout(location = 0) out mediump vec4 fragColor;" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(longlongUniformInstanceName.vector2.y);\n" |
| "}\n\0"; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &testVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| verifyShaderParam (m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_TRUE); |
| verifyShaderParam (m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_TRUE); |
| verifyProgramParam (m_testCtx, *this, program, GL_LINK_STATUS, GL_TRUE); |
| |
| verifyProgramParam (m_testCtx, *this, program, GL_ACTIVE_UNIFORM_BLOCKS, 2); |
| verifyProgramParam (m_testCtx, *this, program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, (GLint)std::string("longlongUniformBlockName").length() + 1); // including a null terminator |
| expectError(GL_NO_ERROR); |
| |
| GLint longlongUniformBlockIndex = glGetUniformBlockIndex(program, "longlongUniformBlockName"); |
| GLint shortUniformBlockIndex = glGetUniformBlockIndex(program, "shortUniformBlockName"); |
| |
| const char* uniformNames[] = |
| { |
| "longlongUniformBlockName.vector2", |
| "shortUniformBlockName.vector2", |
| "shortUniformBlockName.vector4" |
| }; |
| |
| // test UNIFORM_BLOCK_INDEX |
| |
| DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(uniformNames) == 3); |
| |
| StateQueryMemoryWriteGuard<GLuint[DE_LENGTH_OF_ARRAY(uniformNames)]> uniformIndices; |
| StateQueryMemoryWriteGuard<GLint[DE_LENGTH_OF_ARRAY(uniformNames)]> uniformsBlockIndices; |
| |
| glGetUniformIndices(program, DE_LENGTH_OF_ARRAY(uniformNames), uniformNames, uniformIndices); |
| uniformIndices.verifyValidity(m_testCtx); |
| expectError(GL_NO_ERROR); |
| |
| glGetActiveUniformsiv(program, DE_LENGTH_OF_ARRAY(uniformNames), uniformIndices, GL_UNIFORM_BLOCK_INDEX, uniformsBlockIndices); |
| uniformsBlockIndices.verifyValidity(m_testCtx); |
| expectError(GL_NO_ERROR); |
| |
| if (uniformsBlockIndices[0] != longlongUniformBlockIndex || |
| uniformsBlockIndices[1] != shortUniformBlockIndex || |
| uniformsBlockIndices[2] != shortUniformBlockIndex) |
| { |
| m_testCtx.getLog() << TestLog::Message |
| << "// ERROR: Expected [" << longlongUniformBlockIndex << ", " << shortUniformBlockIndex << ", " << shortUniformBlockIndex << "];" |
| << "got [" << uniformsBlockIndices[0] << ", " << uniformsBlockIndices[1] << ", " << uniformsBlockIndices[2] << "]" << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong uniform block index"); |
| } |
| |
| // test UNIFORM_BLOCK_NAME_LENGTH |
| |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, longlongUniformBlockIndex, GL_UNIFORM_BLOCK_NAME_LENGTH, (GLint)std::string("longlongUniformBlockName").length() + 1); // including null-terminator |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, shortUniformBlockIndex, GL_UNIFORM_BLOCK_NAME_LENGTH, (GLint)std::string("shortUniformBlockName").length() + 1); // including null-terminator |
| expectError(GL_NO_ERROR); |
| |
| // test UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER & UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER |
| |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, longlongUniformBlockIndex, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, GL_TRUE); |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, longlongUniformBlockIndex, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, GL_TRUE); |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, shortUniformBlockIndex, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, GL_TRUE); |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, shortUniformBlockIndex, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| // test UNIFORM_BLOCK_ACTIVE_UNIFORMS |
| |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, longlongUniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, 1); |
| verifyActiveUniformBlockParam(m_testCtx, *this, program, shortUniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, 2); |
| expectError(GL_NO_ERROR); |
| |
| // test UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES |
| |
| { |
| StateQueryMemoryWriteGuard<GLint> longlongUniformBlockUniforms; |
| glGetActiveUniformBlockiv(program, longlongUniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &longlongUniformBlockUniforms); |
| longlongUniformBlockUniforms.verifyValidity(m_testCtx); |
| |
| if (longlongUniformBlockUniforms == 2) |
| { |
| StateQueryMemoryWriteGuard<GLint[2]> longlongUniformBlockUniformIndices; |
| glGetActiveUniformBlockiv(program, longlongUniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, longlongUniformBlockUniformIndices); |
| longlongUniformBlockUniformIndices.verifyValidity(m_testCtx); |
| |
| if ((GLuint(longlongUniformBlockUniformIndices[0]) != uniformIndices[0] || GLuint(longlongUniformBlockUniformIndices[1]) != uniformIndices[1]) && |
| (GLuint(longlongUniformBlockUniformIndices[1]) != uniformIndices[0] || GLuint(longlongUniformBlockUniformIndices[0]) != uniformIndices[1])) |
| { |
| m_testCtx.getLog() << TestLog::Message |
| << "// ERROR: Expected {" << uniformIndices[0] << ", " << uniformIndices[1] << "};" |
| << "got {" << longlongUniformBlockUniformIndices[0] << ", " << longlongUniformBlockUniformIndices[1] << "}" << TestLog::EndMessage; |
| |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong uniform indices"); |
| } |
| |
| } |
| } |
| |
| // check block names |
| |
| { |
| char buffer[2048] = {'x'}; |
| GLint written = 0; |
| glGetActiveUniformBlockName(program, longlongUniformBlockIndex, DE_LENGTH_OF_ARRAY(buffer), &written, buffer); |
| checkIntEquals(m_testCtx, written, (GLint)std::string("longlongUniformBlockName").length()); |
| |
| written = 0; |
| glGetActiveUniformBlockName(program, shortUniformBlockIndex, DE_LENGTH_OF_ARRAY(buffer), &written, buffer); |
| checkIntEquals(m_testCtx, written, (GLint)std::string("shortUniformBlockName").length()); |
| |
| // and one with too small buffer |
| written = 0; |
| glGetActiveUniformBlockName(program, longlongUniformBlockIndex, 1, &written, buffer); |
| checkIntEquals(m_testCtx, written, 0); |
| } |
| |
| expectError(GL_NO_ERROR); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ProgramBinaryCase : public ApiCase |
| { |
| public: |
| ProgramBinaryCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &commonTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &commonTestFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| // test PROGRAM_BINARY_RETRIEVABLE_HINT |
| verifyProgramParam(m_testCtx, *this, program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_FALSE); |
| |
| glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); |
| expectError(GL_NO_ERROR); |
| |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| verifyProgramParam(m_testCtx, *this, program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); |
| |
| // test PROGRAM_BINARY_LENGTH does something |
| |
| StateQueryMemoryWriteGuard<GLint> programLength; |
| glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength); |
| expectError(GL_NO_ERROR); |
| programLength.verifyValidity(m_testCtx); |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class TransformFeedbackCase : public ApiCase |
| { |
| public: |
| TransformFeedbackCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| static const char* transformFeedbackTestVertSource = |
| "#version 300 es\n" |
| "out highp vec4 tfOutput2withLongName;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(0.0);\n" |
| " tfOutput2withLongName = vec4(0.0);\n" |
| "}\n"; |
| static const char* transformFeedbackTestFragSource = |
| "#version 300 es\n" |
| "layout(location = 0) out highp vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(0.0);\n" |
| "}\n"; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| GLuint shaderProg = glCreateProgram(); |
| |
| verifyProgramParam(m_testCtx, *this, shaderProg, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, GL_INTERLEAVED_ATTRIBS); |
| |
| glShaderSource(shaderVert, 1, &transformFeedbackTestVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &transformFeedbackTestFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| |
| verifyShaderParam(m_testCtx, *this, shaderVert, GL_COMPILE_STATUS, GL_TRUE); |
| verifyShaderParam(m_testCtx, *this, shaderFrag, GL_COMPILE_STATUS, GL_TRUE); |
| |
| glAttachShader(shaderProg, shaderVert); |
| glAttachShader(shaderProg, shaderFrag); |
| |
| // check TRANSFORM_FEEDBACK_BUFFER_MODE |
| |
| const char* transform_feedback_outputs[] = {"gl_Position", "tfOutput2withLongName"}; |
| const char* longest_output = transform_feedback_outputs[1]; |
| const GLenum bufferModes[] = {GL_SEPARATE_ATTRIBS, GL_INTERLEAVED_ATTRIBS}; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bufferModes); ++ndx) |
| { |
| glTransformFeedbackVaryings(shaderProg, DE_LENGTH_OF_ARRAY(transform_feedback_outputs), transform_feedback_outputs, bufferModes[ndx]); |
| glLinkProgram(shaderProg); |
| expectError(GL_NO_ERROR); |
| |
| verifyProgramParam(m_testCtx, *this, shaderProg, GL_LINK_STATUS, GL_TRUE); |
| verifyProgramParam(m_testCtx, *this, shaderProg, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, bufferModes[ndx]); |
| } |
| |
| // TRANSFORM_FEEDBACK_VARYINGS |
| verifyProgramParam(m_testCtx, *this, shaderProg, GL_TRANSFORM_FEEDBACK_VARYINGS, 2); |
| |
| // TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH |
| { |
| StateQueryMemoryWriteGuard<GLint> maxOutputLen; |
| glGetProgramiv(shaderProg, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &maxOutputLen); |
| |
| maxOutputLen.verifyValidity(m_testCtx); |
| |
| const GLint referenceLength = (GLint)std::string(longest_output).length() + 1; |
| checkIntEquals(m_testCtx, maxOutputLen, referenceLength); |
| } |
| |
| // check varyings |
| { |
| StateQueryMemoryWriteGuard<GLint> varyings; |
| glGetProgramiv(shaderProg, GL_TRANSFORM_FEEDBACK_VARYINGS, &varyings); |
| |
| if (!varyings.isUndefined()) |
| for (int index = 0; index < varyings; ++index) |
| { |
| char buffer[2048] = {'x'}; |
| |
| GLint written = 0; |
| GLint size = 0; |
| GLenum type = 0; |
| glGetTransformFeedbackVarying(shaderProg, index, DE_LENGTH_OF_ARRAY(buffer), &written, &size, &type, buffer); |
| |
| if (written < DE_LENGTH_OF_ARRAY(buffer) && buffer[written] != '\0') |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected null terminator" << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid string terminator"); |
| } |
| |
| // check with too small buffer |
| written = 0; |
| glGetTransformFeedbackVarying(shaderProg, index, 1, &written, &size, &type, buffer); |
| if (written != 0) |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected 0; got " << written << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid write length"); |
| } |
| } |
| } |
| |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(shaderProg); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class ActiveAttributesCase : public ApiCase |
| { |
| public: |
| ActiveAttributesCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| using tcu::TestLog; |
| |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "in highp vec2 longInputAttributeName;\n" |
| "in highp vec2 shortName;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = longInputAttributeName.yxxy + shortName.xyxy;\n" |
| "}\n\0"; |
| static const char* testFragSource = |
| "#version 300 es\n" |
| "layout(location = 0) out mediump vec4 fragColor;" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(0.0);\n" |
| "}\n\0"; |
| |
| GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER); |
| GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER); |
| |
| glShaderSource(shaderVert, 1, &testVertSource, DE_NULL); |
| glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL); |
| |
| glCompileShader(shaderVert); |
| glCompileShader(shaderFrag); |
| expectError(GL_NO_ERROR); |
| |
| GLuint program = glCreateProgram(); |
| glAttachShader(program, shaderVert); |
| glAttachShader(program, shaderFrag); |
| glLinkProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| verifyProgramParam(m_testCtx, *this, program, GL_ACTIVE_ATTRIBUTES, 2); |
| verifyProgramParam(m_testCtx, *this, program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, (GLint)std::string("longInputAttributeName").length() + 1); // does include null-terminator |
| |
| // check names |
| for (int attributeNdx = 0; attributeNdx < 2; ++attributeNdx) |
| { |
| char buffer[2048] = {'x'}; |
| |
| GLint written = 0; |
| GLint size = 0; |
| GLenum type = 0; |
| glGetActiveAttrib(program, attributeNdx, DE_LENGTH_OF_ARRAY(buffer), &written, &size, &type, buffer); |
| expectError(GL_NO_ERROR); |
| |
| if (deStringBeginsWith(buffer, "longInputAttributeName")) |
| { |
| checkIntEquals(m_testCtx, written, (GLint)std::string("longInputAttributeName").length()); // does NOT include null-terminator |
| } |
| else if (deStringBeginsWith(buffer, "shortName")) |
| { |
| checkIntEquals(m_testCtx, written, (GLint)std::string("shortName").length()); // does NOT include null-terminator |
| } |
| else |
| { |
| m_testCtx.getLog() << TestLog::Message << "// ERROR: Got unexpected attribute name." << TestLog::EndMessage; |
| if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected name"); |
| } |
| } |
| |
| // and with too short buffer |
| { |
| char buffer[2048] = {'x'}; |
| |
| GLint written = 0; |
| GLint size = 0; |
| GLenum type = 0; |
| |
| glGetActiveAttrib(program, 0, 1, &written, &size, &type, buffer); |
| expectError(GL_NO_ERROR); |
| checkIntEquals(m_testCtx, written, 0); |
| } |
| |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| struct PointerData |
| { |
| GLint size; |
| GLenum type; |
| GLint stride; |
| GLboolean normalized; |
| const void* pointer; |
| }; |
| |
| class VertexAttributeSizeCase : public ApiCase |
| { |
| public: |
| VertexAttributeSizeCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| GLfloat vertexData[4] = {0.0f}; // never accessed |
| |
| const PointerData pointers[] = |
| { |
| // size test |
| { 4, GL_FLOAT, 0, GL_FALSE, vertexData }, |
| { 3, GL_FLOAT, 0, GL_FALSE, vertexData }, |
| { 2, GL_FLOAT, 0, GL_FALSE, vertexData }, |
| { 1, GL_FLOAT, 0, GL_FALSE, vertexData }, |
| { 4, GL_INT, 0, GL_FALSE, vertexData }, |
| { 3, GL_INT, 0, GL_FALSE, vertexData }, |
| { 2, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| }; |
| |
| // Test with default VAO |
| { |
| const tcu::ScopedLogSection section(m_log, "DefaultVAO", "Test with default VAO"); |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].normalized, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_SIZE, pointers[ndx].size); |
| } |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint buf = 0; |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
| glGenBuffers(1, &buf); |
| glBindBuffer(GL_ARRAY_BUFFER, buf); |
| expectError(GL_NO_ERROR); |
| |
| // initial |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_SIZE, 4); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glVertexAttribPointer(0, pointers[0].size, pointers[0].type, pointers[0].normalized, pointers[0].stride, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glVertexAttribPointer(0, pointers[1].size, pointers[1].type, pointers[1].normalized, pointers[1].stride, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_SIZE, pointers[1].size); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_SIZE, pointers[0].size); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(1, &buf); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeTypeCase : public ApiCase |
| { |
| public: |
| VertexAttributeTypeCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| // Test with default VAO |
| { |
| const tcu::ScopedLogSection section(m_log, "DefaultVAO", "Test with default VAO"); |
| |
| const GLfloat vertexData[4] = {0.0f}; // never accessed |
| |
| // test VertexAttribPointer |
| { |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_FIXED, 0, GL_FALSE, vertexData }, |
| { 1, GL_FLOAT, 0, GL_FALSE, vertexData }, |
| { 1, GL_HALF_FLOAT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_FALSE, vertexData }, |
| { 4, GL_INT_2_10_10_10_REV, 0, GL_FALSE, vertexData }, |
| { 4, GL_UNSIGNED_INT_2_10_10_10_REV, 0, GL_FALSE, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].normalized, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_TYPE, pointers[ndx].type); |
| } |
| } |
| |
| // test glVertexAttribIPointer |
| { |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_FALSE, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribIPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_TYPE, pointers[ndx].type); |
| } |
| } |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint buf = 0; |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
| glGenBuffers(1, &buf); |
| glBindBuffer(GL_ARRAY_BUFFER, buf); |
| expectError(GL_NO_ERROR); |
| |
| // initial |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_TYPE, GL_FLOAT); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glVertexAttribPointer(0, 1, GL_SHORT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_TYPE, GL_SHORT); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_TYPE, GL_FLOAT); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(1, &buf); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeStrideCase : public ApiCase |
| { |
| public: |
| VertexAttributeStrideCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| // Test with default VAO |
| { |
| const tcu::ScopedLogSection section(m_log, "DefaultVAO", "Test with default VAO"); |
| |
| const GLfloat vertexData[4] = {0.0f}; // never accessed |
| |
| struct StridePointerData |
| { |
| GLint size; |
| GLenum type; |
| GLint stride; |
| const void* pointer; |
| }; |
| |
| // test VertexAttribPointer |
| { |
| const StridePointerData pointers[] = |
| { |
| { 1, GL_FLOAT, 0, vertexData }, |
| { 1, GL_FLOAT, 1, vertexData }, |
| { 1, GL_FLOAT, 4, vertexData }, |
| { 1, GL_HALF_FLOAT, 0, vertexData }, |
| { 1, GL_HALF_FLOAT, 1, vertexData }, |
| { 1, GL_HALF_FLOAT, 4, vertexData }, |
| { 1, GL_FIXED, 0, vertexData }, |
| { 1, GL_FIXED, 1, vertexData }, |
| { 1, GL_FIXED, 4, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribPointer(0, pointers[ndx].size, pointers[ndx].type, GL_FALSE, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, pointers[ndx].stride); |
| } |
| } |
| |
| // test glVertexAttribIPointer |
| { |
| const StridePointerData pointers[] = |
| { |
| { 1, GL_INT, 0, vertexData }, |
| { 1, GL_INT, 1, vertexData }, |
| { 1, GL_INT, 4, vertexData }, |
| { 4, GL_UNSIGNED_BYTE, 0, vertexData }, |
| { 4, GL_UNSIGNED_BYTE, 1, vertexData }, |
| { 4, GL_UNSIGNED_BYTE, 4, vertexData }, |
| { 2, GL_SHORT, 0, vertexData }, |
| { 2, GL_SHORT, 1, vertexData }, |
| { 2, GL_SHORT, 4, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribIPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, pointers[ndx].stride); |
| } |
| } |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint buf = 0; |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
| glGenBuffers(1, &buf); |
| glBindBuffer(GL_ARRAY_BUFFER, buf); |
| expectError(GL_NO_ERROR); |
| |
| // initial |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, 0); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 4, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glVertexAttribPointer(0, 1, GL_SHORT, GL_FALSE, 8, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, 8); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, 4); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(1, &buf); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeNormalizedCase : public ApiCase |
| { |
| public: |
| VertexAttributeNormalizedCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| // Test with default VAO |
| { |
| const tcu::ScopedLogSection section(m_log, "DefaultVAO", "Test with default VAO"); |
| |
| const GLfloat vertexData[4] = {0.0f}; // never accessed |
| |
| // test VertexAttribPointer |
| { |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_FALSE, vertexData }, |
| { 4, GL_INT_2_10_10_10_REV, 0, GL_FALSE, vertexData }, |
| { 4, GL_UNSIGNED_INT_2_10_10_10_REV, 0, GL_FALSE, vertexData }, |
| { 1, GL_BYTE, 0, GL_TRUE, vertexData }, |
| { 1, GL_SHORT, 0, GL_TRUE, vertexData }, |
| { 1, GL_INT, 0, GL_TRUE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_TRUE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_TRUE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_TRUE, vertexData }, |
| { 4, GL_INT_2_10_10_10_REV, 0, GL_TRUE, vertexData }, |
| { 4, GL_UNSIGNED_INT_2_10_10_10_REV, 0, GL_TRUE, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].normalized, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, pointers[ndx].normalized); |
| } |
| } |
| |
| // test glVertexAttribIPointer |
| { |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_FALSE, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribIPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, GL_FALSE); |
| } |
| } |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint buf = 0; |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
| glGenBuffers(1, &buf); |
| glBindBuffer(GL_ARRAY_BUFFER, buf); |
| expectError(GL_NO_ERROR); |
| |
| // initial |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glVertexAttribPointer(0, 1, GL_INT, GL_TRUE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, GL_TRUE); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(1, &buf); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeIntegerCase : public ApiCase |
| { |
| public: |
| VertexAttributeIntegerCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| // Test with default VAO |
| { |
| const tcu::ScopedLogSection section(m_log, "DefaultVAO", "Test with default VAO"); |
| |
| const GLfloat vertexData[4] = {0.0f}; // never accessed |
| |
| // test VertexAttribPointer |
| { |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_FIXED, 0, GL_FALSE, vertexData }, |
| { 1, GL_FLOAT, 0, GL_FALSE, vertexData }, |
| { 1, GL_HALF_FLOAT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_FALSE, vertexData }, |
| { 4, GL_INT_2_10_10_10_REV, 0, GL_FALSE, vertexData }, |
| { 4, GL_UNSIGNED_INT_2_10_10_10_REV, 0, GL_FALSE, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].normalized, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_INTEGER, GL_FALSE); |
| } |
| } |
| |
| // test glVertexAttribIPointer |
| { |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_INT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_BYTE, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_SHORT, 0, GL_FALSE, vertexData }, |
| { 1, GL_UNSIGNED_INT, 0, GL_FALSE, vertexData }, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pointers); ++ndx) |
| { |
| glVertexAttribIPointer(0, pointers[ndx].size, pointers[ndx].type, pointers[ndx].stride, pointers[ndx].pointer); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_INTEGER, GL_TRUE); |
| } |
| } |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint buf = 0; |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
|