| /*------------------------------------------------------------------------- |
| * 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); |
| 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_INTEGER, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glVertexAttribIPointer(0, 1, GL_INT, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_INTEGER, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_INTEGER, GL_TRUE); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(1, &buf); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeEnabledCase : public ApiCase |
| { |
| public: |
| VertexAttributeEnabledCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| // VERTEX_ATTRIB_ARRAY_ENABLED |
| |
| // Test with default VAO |
| { |
| const tcu::ScopedLogSection section(m_log, "DefaultVAO", "Test with default VAO"); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, GL_FALSE); |
| glEnableVertexAttribArray(0); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, GL_TRUE); |
| glDisableVertexAttribArray(0); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, GL_FALSE); |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glBindVertexArray(vaos[0]); |
| glEnableVertexAttribArray(0); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glDisableVertexAttribArray(0); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, GL_FALSE); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, GL_TRUE); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeDivisorCase : public ApiCase |
| { |
| public: |
| VertexAttributeDivisorCase (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"); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 0); |
| glVertexAttribDivisor(0, 1); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 1); |
| glVertexAttribDivisor(0, 5); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 5); |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint vaos[2] = {0}; |
| |
| glGenVertexArrays(2, vaos); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glBindVertexArray(vaos[0]); |
| glVertexAttribDivisor(0, 1); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glVertexAttribDivisor(0, 5); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 5); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 1); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributeBufferBindingCase : public ApiCase |
| { |
| public: |
| VertexAttributeBufferBindingCase (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"); |
| |
| // initial |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, 0); |
| |
| GLuint bufferID; |
| glGenBuffers(1, &bufferID); |
| glBindBuffer(GL_ARRAY_BUFFER, bufferID); |
| expectError(GL_NO_ERROR); |
| |
| glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, bufferID); |
| |
| glDeleteBuffers(1, &bufferID); |
| expectError(GL_NO_ERROR); |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint vaos[2] = {0}; |
| GLuint bufs[2] = {0}; |
| |
| glGenBuffers(2, bufs); |
| expectError(GL_NO_ERROR); |
| |
| glGenVertexArrays(2, vaos); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glBindVertexArray(vaos[0]); |
| glBindBuffer(GL_ARRAY_BUFFER, bufs[0]); |
| glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glBindBuffer(GL_ARRAY_BUFFER, bufs[1]); |
| glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, bufs[1]); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| verifyVertexAttrib(m_testCtx, *this, 0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, bufs[0]); |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(2, bufs); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class VertexAttributePointerCase : public ApiCase |
| { |
| public: |
| VertexAttributePointerCase (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"); |
| |
| StateQueryMemoryWriteGuard<GLvoid*> initialState; |
| glGetVertexAttribPointerv(0, GL_VERTEX_ATTRIB_ARRAY_POINTER, &initialState); |
| initialState.verifyValidity(m_testCtx); |
| checkPointerEquals(m_testCtx, initialState, 0); |
| |
| const GLfloat vertexData[4] = {0.0f}; // never accessed |
| const PointerData pointers[] = |
| { |
| { 1, GL_BYTE, 0, GL_FALSE, &vertexData[2] }, |
| { 1, GL_SHORT, 0, GL_FALSE, &vertexData[1] }, |
| { 1, GL_INT, 0, GL_FALSE, &vertexData[2] }, |
| { 1, GL_FIXED, 0, GL_FALSE, &vertexData[2] }, |
| { 1, GL_FIXED, 0, GL_FALSE, &vertexData[1] }, |
| { 1, GL_FLOAT, 0, GL_FALSE, &vertexData[0] }, |
| { 1, GL_FLOAT, 0, GL_FALSE, &vertexData[3] }, |
| { 1, GL_FLOAT, 0, GL_FALSE, &vertexData[2] }, |
| { 1, GL_HALF_FLOAT, 0, GL_FALSE, &vertexData[0] }, |
| { 4, GL_HALF_FLOAT, 0, GL_FALSE, &vertexData[1] }, |
| { 4, GL_HALF_FLOAT, 0, GL_FALSE, &vertexData[2] }, |
| }; |
| |
| 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); |
| |
| StateQueryMemoryWriteGuard<GLvoid*> state; |
| glGetVertexAttribPointerv(0, GL_VERTEX_ATTRIB_ARRAY_POINTER, &state); |
| state.verifyValidity(m_testCtx); |
| checkPointerEquals(m_testCtx, state, pointers[ndx].pointer); |
| } |
| } |
| |
| // Test with multiple VAOs |
| { |
| const tcu::ScopedLogSection section(m_log, "WithVAO", "Test with VAO"); |
| |
| GLuint vaos[2] = {0}; |
| GLuint bufs[2] = {0}; |
| |
| glGenBuffers(2, bufs); |
| expectError(GL_NO_ERROR); |
| |
| glGenVertexArrays(2, vaos); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 0 to some value |
| glBindVertexArray(vaos[0]); |
| glBindBuffer(GL_ARRAY_BUFFER, bufs[0]); |
| glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, glu::BufferOffsetAsPointer(8)); |
| expectError(GL_NO_ERROR); |
| |
| // set vao 1 to some other value |
| glBindVertexArray(vaos[1]); |
| glBindBuffer(GL_ARRAY_BUFFER, bufs[1]); |
| glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, glu::BufferOffsetAsPointer(4)); |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 1 state |
| { |
| StateQueryMemoryWriteGuard<GLvoid*> state; |
| glGetVertexAttribPointerv(0, GL_VERTEX_ATTRIB_ARRAY_POINTER, &state); |
| state.verifyValidity(m_testCtx); |
| checkPointerEquals(m_testCtx, state, glu::BufferOffsetAsPointer(4)); |
| } |
| expectError(GL_NO_ERROR); |
| |
| // verify vao 0 state |
| glBindVertexArray(vaos[0]); |
| { |
| StateQueryMemoryWriteGuard<GLvoid*> state; |
| glGetVertexAttribPointerv(0, GL_VERTEX_ATTRIB_ARRAY_POINTER, &state); |
| state.verifyValidity(m_testCtx); |
| checkPointerEquals(m_testCtx, state, glu::BufferOffsetAsPointer(8)); |
| } |
| expectError(GL_NO_ERROR); |
| |
| glDeleteVertexArrays(2, vaos); |
| glDeleteBuffers(2, bufs); |
| expectError(GL_NO_ERROR); |
| } |
| } |
| }; |
| |
| class UniformValueFloatCase : public ApiCase |
| { |
| public: |
| UniformValueFloatCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform highp float floatUniform;\n" |
| "uniform highp vec2 float2Uniform;\n" |
| "uniform highp vec3 float3Uniform;\n" |
| "uniform highp vec4 float4Uniform;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(floatUniform + float2Uniform.x + float3Uniform.x + float4Uniform.x);\n" |
| "}\n"; |
| 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"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| location = glGetUniformLocation(program,"floatUniform"); |
| glUniform1f(location, 1.0f); |
| verifyUniformValue1f(m_testCtx, *this, program, location, 1.0f); |
| |
| location = glGetUniformLocation(program,"float2Uniform"); |
| glUniform2f(location, 1.0f, 2.0f); |
| verifyUniformValue2f(m_testCtx, *this, program, location, 1.0f, 2.0f); |
| |
| location = glGetUniformLocation(program,"float3Uniform"); |
| glUniform3f(location, 1.0f, 2.0f, 3.0f); |
| verifyUniformValue3f(m_testCtx, *this, program, location, 1.0f, 2.0f, 3.0f); |
| |
| location = glGetUniformLocation(program,"float4Uniform"); |
| glUniform4f(location, 1.0f, 2.0f, 3.0f, 4.0f); |
| verifyUniformValue4f(m_testCtx, *this, program, location, 1.0f, 2.0f, 3.0f, 4.0f); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class UniformValueIntCase : public ApiCase |
| { |
| public: |
| UniformValueIntCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform highp int intUniform;\n" |
| "uniform highp ivec2 int2Uniform;\n" |
| "uniform highp ivec3 int3Uniform;\n" |
| "uniform highp ivec4 int4Uniform;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(float(intUniform + int2Uniform.x + int3Uniform.x + int4Uniform.x));\n" |
| "}\n"; |
| 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"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| location = glGetUniformLocation(program,"intUniform"); |
| glUniform1i(location, 1); |
| verifyUniformValue1i(m_testCtx, *this, program, location, 1); |
| |
| location = glGetUniformLocation(program,"int2Uniform"); |
| glUniform2i(location, 1, 2); |
| verifyUniformValue2i(m_testCtx, *this, program, location, 1, 2); |
| |
| location = glGetUniformLocation(program,"int3Uniform"); |
| glUniform3i(location, 1, 2, 3); |
| verifyUniformValue3i(m_testCtx, *this, program, location, 1, 2, 3); |
| |
| location = glGetUniformLocation(program,"int4Uniform"); |
| glUniform4i(location, 1, 2, 3, 4); |
| verifyUniformValue4i(m_testCtx, *this, program, location, 1, 2, 3, 4); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class UniformValueUintCase : public ApiCase |
| { |
| public: |
| UniformValueUintCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform highp uint uintUniform;\n" |
| "uniform highp uvec2 uint2Uniform;\n" |
| "uniform highp uvec3 uint3Uniform;\n" |
| "uniform highp uvec4 uint4Uniform;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(float(uintUniform + uint2Uniform.x + uint3Uniform.x + uint4Uniform.x));\n" |
| "}\n"; |
| 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"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| location = glGetUniformLocation(program,"uintUniform"); |
| glUniform1ui(location, 1); |
| verifyUniformValue1ui(m_testCtx, *this, program, location, 1); |
| |
| location = glGetUniformLocation(program,"uint2Uniform"); |
| glUniform2ui(location, 1, 2); |
| verifyUniformValue2ui(m_testCtx, *this, program, location, 1, 2); |
| |
| location = glGetUniformLocation(program,"uint3Uniform"); |
| glUniform3ui(location, 1, 2, 3); |
| verifyUniformValue3ui(m_testCtx, *this, program, location, 1, 2, 3); |
| |
| location = glGetUniformLocation(program,"uint4Uniform"); |
| glUniform4ui(location, 1, 2, 3, 4); |
| verifyUniformValue4ui(m_testCtx, *this, program, location, 1, 2, 3, 4); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| |
| class UniformValueBooleanCase : public ApiCase |
| { |
| public: |
| UniformValueBooleanCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform bool boolUniform;\n" |
| "uniform bvec2 bool2Uniform;\n" |
| "uniform bvec3 bool3Uniform;\n" |
| "uniform bvec4 bool4Uniform;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(float(boolUniform) + float(bool2Uniform.x) + float(bool3Uniform.x) + float(bool4Uniform.x));\n" |
| "}\n"; |
| 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"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| // int conversion |
| |
| location = glGetUniformLocation(program,"boolUniform"); |
| glUniform1i(location, 1); |
| verifyUniformValue1i(m_testCtx, *this, program, location, 1); |
| |
| location = glGetUniformLocation(program,"bool2Uniform"); |
| glUniform2i(location, 1, 2); |
| verifyUniformValue2i(m_testCtx, *this, program, location, 1, 1); |
| |
| location = glGetUniformLocation(program,"bool3Uniform"); |
| glUniform3i(location, 0, 1, 2); |
| verifyUniformValue3i(m_testCtx, *this, program, location, 0, 1, 1); |
| |
| location = glGetUniformLocation(program,"bool4Uniform"); |
| glUniform4i(location, 1, 0, 1, -1); |
| verifyUniformValue4i(m_testCtx, *this, program, location, 1, 0, 1, 1); |
| |
| // float conversion |
| |
| location = glGetUniformLocation(program,"boolUniform"); |
| glUniform1f(location, 1.0f); |
| verifyUniformValue1i(m_testCtx, *this, program, location, 1); |
| |
| location = glGetUniformLocation(program,"bool2Uniform"); |
| glUniform2f(location, 1.0f, 0.1f); |
| verifyUniformValue2i(m_testCtx, *this, program, location, 1, 1); |
| |
| location = glGetUniformLocation(program,"bool3Uniform"); |
| glUniform3f(location, 0.0f, 0.1f, -0.1f); |
| verifyUniformValue3i(m_testCtx, *this, program, location, 0, 1, 1); |
| |
| location = glGetUniformLocation(program,"bool4Uniform"); |
| glUniform4f(location, 1.0f, 0.0f, 0.1f, -0.9f); |
| verifyUniformValue4i(m_testCtx, *this, program, location, 1, 0, 1, 1); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class UniformValueSamplerCase : public ApiCase |
| { |
| public: |
| UniformValueSamplerCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(0.0);\n" |
| "}\n"; |
| static const char* testFragSource = |
| "#version 300 es\n" |
| "uniform highp sampler2D uniformSampler;\n" |
| "layout(location = 0) out mediump vec4 fragColor;" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(textureSize(uniformSampler, 0).x);\n" |
| "}\n"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| location = glGetUniformLocation(program,"uniformSampler"); |
| glUniform1i(location, 1); |
| verifyUniformValue1i(m_testCtx, *this, program, location, 1); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class UniformValueArrayCase : public ApiCase |
| { |
| public: |
| UniformValueArrayCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform highp float arrayUniform[5];" |
| "uniform highp vec2 array2Uniform[5];" |
| "uniform highp vec3 array3Uniform[5];" |
| "uniform highp vec4 array4Uniform[5];" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = \n" |
| " + vec4(arrayUniform[0] + arrayUniform[1] + arrayUniform[2] + arrayUniform[3] + arrayUniform[4])\n" |
| " + vec4(array2Uniform[0].x + array2Uniform[1].x + array2Uniform[2].x + array2Uniform[3].x + array2Uniform[4].x)\n" |
| " + vec4(array3Uniform[0].x + array3Uniform[1].x + array3Uniform[2].x + array3Uniform[3].x + array3Uniform[4].x)\n" |
| " + vec4(array4Uniform[0].x + array4Uniform[1].x + array4Uniform[2].x + array4Uniform[3].x + array4Uniform[4].x);\n" |
| "}\n"; |
| 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"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| float uniformValue[5 * 4] = |
| { |
| -1.0f, 0.1f, 4.0f, 800.0f, |
| 13.0f, 55.0f, 12.0f, 91.0f, |
| -55.1f, 1.1f, 98.0f, 19.0f, |
| 41.0f, 65.0f, 4.0f, 12.2f, |
| 95.0f, 77.0f, 32.0f, 48.0f |
| }; |
| |
| location = glGetUniformLocation(program,"arrayUniform"); |
| glUniform1fv(location, 5, uniformValue); |
| expectError(GL_NO_ERROR); |
| |
| verifyUniformValue1f(m_testCtx, *this, program, glGetUniformLocation(program,"arrayUniform[0]"), uniformValue[0]); |
| verifyUniformValue1f(m_testCtx, *this, program, glGetUniformLocation(program,"arrayUniform[1]"), uniformValue[1]); |
| verifyUniformValue1f(m_testCtx, *this, program, glGetUniformLocation(program,"arrayUniform[2]"), uniformValue[2]); |
| verifyUniformValue1f(m_testCtx, *this, program, glGetUniformLocation(program,"arrayUniform[3]"), uniformValue[3]); |
| verifyUniformValue1f(m_testCtx, *this, program, glGetUniformLocation(program,"arrayUniform[4]"), uniformValue[4]); |
| expectError(GL_NO_ERROR); |
| |
| location = glGetUniformLocation(program,"array2Uniform"); |
| glUniform2fv(location, 5, uniformValue); |
| expectError(GL_NO_ERROR); |
| |
| verifyUniformValue2f(m_testCtx, *this, program, glGetUniformLocation(program,"array2Uniform[0]"), uniformValue[2 * 0], uniformValue[(2 * 0) + 1]); |
| verifyUniformValue2f(m_testCtx, *this, program, glGetUniformLocation(program,"array2Uniform[1]"), uniformValue[2 * 1], uniformValue[(2 * 1) + 1]); |
| verifyUniformValue2f(m_testCtx, *this, program, glGetUniformLocation(program,"array2Uniform[2]"), uniformValue[2 * 2], uniformValue[(2 * 2) + 1]); |
| verifyUniformValue2f(m_testCtx, *this, program, glGetUniformLocation(program,"array2Uniform[3]"), uniformValue[2 * 3], uniformValue[(2 * 3) + 1]); |
| verifyUniformValue2f(m_testCtx, *this, program, glGetUniformLocation(program,"array2Uniform[4]"), uniformValue[2 * 4], uniformValue[(2 * 4) + 1]); |
| expectError(GL_NO_ERROR); |
| |
| location = glGetUniformLocation(program,"array3Uniform"); |
| glUniform3fv(location, 5, uniformValue); |
| expectError(GL_NO_ERROR); |
| |
| verifyUniformValue3f(m_testCtx, *this, program, glGetUniformLocation(program,"array3Uniform[0]"), uniformValue[3 * 0], uniformValue[(3 * 0) + 1], uniformValue[(3 * 0) + 2]); |
| verifyUniformValue3f(m_testCtx, *this, program, glGetUniformLocation(program,"array3Uniform[1]"), uniformValue[3 * 1], uniformValue[(3 * 1) + 1], uniformValue[(3 * 1) + 2]); |
| verifyUniformValue3f(m_testCtx, *this, program, glGetUniformLocation(program,"array3Uniform[2]"), uniformValue[3 * 2], uniformValue[(3 * 2) + 1], uniformValue[(3 * 2) + 2]); |
| verifyUniformValue3f(m_testCtx, *this, program, glGetUniformLocation(program,"array3Uniform[3]"), uniformValue[3 * 3], uniformValue[(3 * 3) + 1], uniformValue[(3 * 3) + 2]); |
| verifyUniformValue3f(m_testCtx, *this, program, glGetUniformLocation(program,"array3Uniform[4]"), uniformValue[3 * 4], uniformValue[(3 * 4) + 1], uniformValue[(3 * 4) + 2]); |
| expectError(GL_NO_ERROR); |
| |
| location = glGetUniformLocation(program,"array4Uniform"); |
| glUniform4fv(location, 5, uniformValue); |
| expectError(GL_NO_ERROR); |
| |
| verifyUniformValue4f(m_testCtx, *this, program, glGetUniformLocation(program,"array4Uniform[0]"), uniformValue[4 * 0], uniformValue[(4 * 0) + 1], uniformValue[(4 * 0) + 2], uniformValue[(4 * 0) + 3]); |
| verifyUniformValue4f(m_testCtx, *this, program, glGetUniformLocation(program,"array4Uniform[1]"), uniformValue[4 * 1], uniformValue[(4 * 1) + 1], uniformValue[(4 * 1) + 2], uniformValue[(4 * 1) + 3]); |
| verifyUniformValue4f(m_testCtx, *this, program, glGetUniformLocation(program,"array4Uniform[2]"), uniformValue[4 * 2], uniformValue[(4 * 2) + 1], uniformValue[(4 * 2) + 2], uniformValue[(4 * 2) + 3]); |
| verifyUniformValue4f(m_testCtx, *this, program, glGetUniformLocation(program,"array4Uniform[3]"), uniformValue[4 * 3], uniformValue[(4 * 3) + 1], uniformValue[(4 * 3) + 2], uniformValue[(4 * 3) + 3]); |
| verifyUniformValue4f(m_testCtx, *this, program, glGetUniformLocation(program,"array4Uniform[4]"), uniformValue[4 * 4], uniformValue[(4 * 4) + 1], uniformValue[(4 * 4) + 2], uniformValue[(4 * 4) + 3]); |
| expectError(GL_NO_ERROR); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class UniformValueMatrixCase : public ApiCase |
| { |
| public: |
| UniformValueMatrixCase (Context& context, const char* name, const char* description) |
| : ApiCase(context, name, description) |
| { |
| } |
| |
| void test (void) |
| { |
| static const char* testVertSource = |
| "#version 300 es\n" |
| "uniform highp mat2 mat2Uniform;" |
| "uniform highp mat3 mat3Uniform;" |
| "uniform highp mat4 mat4Uniform;" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(mat2Uniform[0][0] + mat3Uniform[0][0] + mat4Uniform[0][0]);\n" |
| "}\n"; |
| 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"; |
| |
| 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); |
| glUseProgram(program); |
| expectError(GL_NO_ERROR); |
| |
| GLint location; |
| |
| float matrixValues[4 * 4] = |
| { |
| -1.0f, 0.1f, 4.0f, 800.0f, |
| 13.0f, 55.0f, 12.0f, 91.0f, |
| -55.1f, 1.1f, 98.0f, 19.0f, |
| 41.0f, 65.0f, 4.0f, 12.2f, |
| }; |
| |
| // the values of the matrix are returned in column major order but they can be given in either order |
| |
| location = glGetUniformLocation(program,"mat2Uniform"); |
| glUniformMatrix2fv(location, 1, GL_FALSE, matrixValues); |
| verifyUniformMatrixValues<2>(m_testCtx, *this, program, location, matrixValues, false); |
| glUniformMatrix2fv(location, 1, GL_TRUE, matrixValues); |
| verifyUniformMatrixValues<2>(m_testCtx, *this, program, location, matrixValues, true); |
| |
| location = glGetUniformLocation(program,"mat3Uniform"); |
| glUniformMatrix3fv(location, 1, GL_FALSE, matrixValues); |
| verifyUniformMatrixValues<3>(m_testCtx, *this, program, location, matrixValues, false); |
| glUniformMatrix3fv(location, 1, GL_TRUE, matrixValues); |
| verifyUniformMatrixValues<3>(m_testCtx, *this, program, location, matrixValues, true); |
| |
| location = glGetUniformLocation(program,"mat4Uniform"); |
| glUniformMatrix4fv(location, 1, GL_FALSE, matrixValues); |
| verifyUniformMatrixValues<4>(m_testCtx, *this, program, location, matrixValues, false); |
| glUniformMatrix4fv(location, 1, GL_TRUE, matrixValues); |
| verifyUniformMatrixValues<4>(m_testCtx, *this, program, location, matrixValues, true); |
| |
| glUseProgram(0); |
| glDeleteShader(shaderVert); |
| glDeleteShader(shaderFrag); |
| glDeleteProgram(program); |
| expectError(GL_NO_ERROR); |
| } |
| }; |
| |
| class PrecisionFormatCase : public ApiCase |
| { |
| public: |
| struct RequiredFormat |
| { |
| int negativeRange; |
| int positiveRange; |
| int precision; |
| }; |
| |
| PrecisionFormatCase (Context& context, const char* name, const char* description, glw::GLenum shaderType, glw::GLenum precisionType) |
| : ApiCase (context, name, description) |
| , m_shaderType (shaderType) |
| , m_precisionType (precisionType) |
| { |
| } |
| |
| private: |
| void test (void) |
| { |
| const RequiredFormat expected = getRequiredFormat(); |
| bool error = false; |
| gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLboolean> shaderCompiler; |
| gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint[2]> range; |
| gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> precision; |
| |
| // query values |
| glGetShaderPrecisionFormat(m_shaderType, m_precisionType, range, &precision); |
| expectError(GL_NO_ERROR); |
| |
| if (!range.verifyValidity(m_testCtx)) |
| return; |
| if (!precision.verifyValidity(m_testCtx)) |
| return; |
| |
| m_log |
| << tcu::TestLog::Message |
| << "range[0] = " << range[0] << "\n" |
| << "range[1] = " << range[1] << "\n" |
| << "precision = " << precision |
| << tcu::TestLog::EndMessage; |
| |
| // verify values |
| |
| if (m_precisionType == GL_HIGH_FLOAT) |
| { |
| // highp float must be IEEE 754 single |
| |
| if (range[0] != expected.negativeRange || |
| range[1] != expected.positiveRange || |
| precision != expected.precision) |
| { |
| m_log |
| << tcu::TestLog::Message |
| << "// ERROR: Invalid precision format, expected:\n" |
| << "\trange[0] = " << expected.negativeRange << "\n" |
| << "\trange[1] = " << expected.positiveRange << "\n" |
| << "\tprecision = " << expected.precision |
| << tcu::TestLog::EndMessage; |
| error = true; |
| } |
| } |
| else |
| { |
| if (range[0] < expected.negativeRange) |
| { |
| m_log << tcu::TestLog::Message << "// ERROR: Invalid range[0], expected greater or equal to " << expected.negativeRange << tcu::TestLog::EndMessage; |
| error = true; |
| } |
| |
| if (range[1] < expected.positiveRange) |
| { |
| m_log << tcu::TestLog::Message << "// ERROR: Invalid range[1], expected greater or equal to " << expected.positiveRange << tcu::TestLog::EndMessage; |
| error = true; |
| } |
| |
| if (precision < expected.precision) |
| { |
| m_log << tcu::TestLog::Message << "// ERROR: Invalid precision, expected greater or equal to " << expected.precision << tcu::TestLog::EndMessage; |
| error = true; |
| } |
| } |
| |
| if (error) |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid precision/range"); |
| } |
| |
| RequiredFormat getRequiredFormat (void) const |
| { |
| // Precisions for different types. |
| const RequiredFormat requirements[] = |
| { |
| { 0, 0, 8 }, //!< lowp float |
| { 13, 13, 10 }, //!< mediump float |
| { 127, 127, 23 }, //!< highp float |
| { 8, 7, 0 }, //!< lowp int |
| { 15, 14, 0 }, //!< mediump int |
| { 31, 30, 0 }, //!< highp int |
| }; |
| const int ndx = (int)m_precisionType - (int)GL_LOW_FLOAT; |
| |
| DE_ASSERT(ndx >= 0); |
| DE_ASSERT(ndx < DE_LENGTH_OF_ARRAY(requirements)); |
| return requirements[ndx]; |
| } |
| |
| const glw::GLenum m_shaderType; |
| const glw::GLenum m_precisionType; |
| }; |
| |
| } // anonymous |
| |
| |
| ShaderStateQueryTests::ShaderStateQueryTests (Context& context) |
| : TestCaseGroup(context, "shader", "Shader State Query tests") |
| { |
| } |
| |
| void ShaderStateQueryTests::init (void) |
| { |
| // shader |
| addChild(new ShaderTypeCase (m_context, "shader_type", "SHADER_TYPE")); |
| addChild(new ShaderCompileStatusCase (m_context, "shader_compile_status", "COMPILE_STATUS")); |
| addChild(new ShaderInfoLogCase (m_context, "shader_info_log_length", "INFO_LOG_LENGTH")); |
| addChild(new ShaderSourceCase (m_context, "shader_source_length", "SHADER_SOURCE_LENGTH")); |
| |
| // shader and program |
| addChild(new DeleteStatusCase (m_context, "delete_status", "DELETE_STATUS")); |
| |
| // vertex-attrib |
| addChild(new CurrentVertexAttribInitialCase (m_context, "current_vertex_attrib_initial", "CURRENT_VERTEX_ATTRIB")); |
| addChild(new CurrentVertexAttribFloatCase (m_context, "current_vertex_attrib_float", "CURRENT_VERTEX_ATTRIB")); |
| addChild(new CurrentVertexAttribIntCase (m_context, "current_vertex_attrib_int", "CURRENT_VERTEX_ATTRIB")); |
| addChild(new CurrentVertexAttribUintCase (m_context, "current_vertex_attrib_uint", "CURRENT_VERTEX_ATTRIB")); |
| addChild(new CurrentVertexAttribConversionCase (m_context, "current_vertex_attrib_float_to_int", "CURRENT_VERTEX_ATTRIB")); |
| |
| // program |
| addChild(new ProgramInfoLogCase (m_context, "program_info_log_length", "INFO_LOG_LENGTH", ProgramInfoLogCase::BUILDERROR_COMPILE)); |
| addChild(new ProgramInfoLogCase (m_context, "program_info_log_length_link_error", "INFO_LOG_LENGTH", ProgramInfoLogCase::BUILDERROR_LINK)); |
| addChild(new ProgramValidateStatusCase (m_context, "program_validate_status", "VALIDATE_STATUS")); |
| addChild(new ProgramAttachedShadersCase (m_context, "program_attached_shaders", "ATTACHED_SHADERS")); |
| |
| addChild(new ProgramActiveUniformNameCase (m_context, "program_active_uniform_name", "ACTIVE_UNIFORMS and ACTIVE_UNIFORM_MAX_LENGTH")); |
| addChild(new ProgramUniformCase (m_context, "program_active_uniform_types", "UNIFORM_TYPE, UNIFORM_SIZE, and UNIFORM_IS_ROW_MAJOR")); |
| addChild(new ProgramActiveUniformBlocksCase (m_context, "program_active_uniform_blocks", "ACTIVE_UNIFORM_BLOCK_x")); |
| addChild(new ProgramBinaryCase (m_context, "program_binary", "PROGRAM_BINARY_LENGTH and PROGRAM_BINARY_RETRIEVABLE_HINT")); |
| |
| // transform feedback |
| addChild(new TransformFeedbackCase (m_context, "transform_feedback", "TRANSFORM_FEEDBACK_BUFFER_MODE, TRANSFORM_FEEDBACK_VARYINGS, TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH")); |
| |
| // attribute related |
| addChild(new ActiveAttributesCase (m_context, "active_attributes", "ACTIVE_ATTRIBUTES and ACTIVE_ATTRIBUTE_MAX_LENGTH")); |
| addChild(new VertexAttributeSizeCase (m_context, "vertex_attrib_size", "VERTEX_ATTRIB_ARRAY_SIZE")); |
| addChild(new VertexAttributeTypeCase (m_context, "vertex_attrib_type", "VERTEX_ATTRIB_ARRAY_TYPE")); |
| addChild(new VertexAttributeStrideCase (m_context, "vertex_attrib_stride", "VERTEX_ATTRIB_ARRAY_STRIDE")); |
| addChild(new VertexAttributeNormalizedCase (m_context, "vertex_attrib_normalized", "VERTEX_ATTRIB_ARRAY_NORMALIZED")); |
| addChild(new VertexAttributeIntegerCase (m_context, "vertex_attrib_integer", "VERTEX_ATTRIB_ARRAY_INTEGER")); |
| addChild(new VertexAttributeEnabledCase (m_context, "vertex_attrib_array_enabled", "VERTEX_ATTRIB_ARRAY_ENABLED")); |
| addChild(new VertexAttributeDivisorCase (m_context, "vertex_attrib_array_divisor", "VERTEX_ATTRIB_ARRAY_DIVISOR")); |
| addChild(new VertexAttributeBufferBindingCase (m_context, "vertex_attrib_array_buffer_binding", "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING")); |
| addChild(new VertexAttributePointerCase (m_context, "vertex_attrib_pointerv", "GetVertexAttribPointerv")); |
| |
| // uniform values |
| addChild(new UniformValueFloatCase (m_context, "uniform_value_float", "GetUniform*")); |
| addChild(new UniformValueIntCase (m_context, "uniform_value_int", "GetUniform*")); |
| addChild(new UniformValueUintCase (m_context, "uniform_value_uint", "GetUniform*")); |
| addChild(new UniformValueBooleanCase (m_context, "uniform_value_boolean", "GetUniform*")); |
| addChild(new UniformValueSamplerCase (m_context, "uniform_value_sampler", "GetUniform*")); |
| addChild(new UniformValueArrayCase (m_context, "uniform_value_array", "GetUniform*")); |
| addChild(new UniformValueMatrixCase (m_context, "uniform_value_matrix", "GetUniform*")); |
| |
| // precision format query |
| addChild(new PrecisionFormatCase (m_context, "precision_vertex_lowp_float", "GetShaderPrecisionFormat", GL_VERTEX_SHADER, GL_LOW_FLOAT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_vertex_mediump_float", "GetShaderPrecisionFormat", GL_VERTEX_SHADER, GL_MEDIUM_FLOAT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_vertex_highp_float", "GetShaderPrecisionFormat", GL_VERTEX_SHADER, GL_HIGH_FLOAT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_vertex_lowp_int", "GetShaderPrecisionFormat", GL_VERTEX_SHADER, GL_LOW_INT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_vertex_mediump_int", "GetShaderPrecisionFormat", GL_VERTEX_SHADER, GL_MEDIUM_INT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_vertex_highp_int", "GetShaderPrecisionFormat", GL_VERTEX_SHADER, GL_HIGH_INT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_fragment_lowp_float", "GetShaderPrecisionFormat", GL_FRAGMENT_SHADER, GL_LOW_FLOAT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_fragment_mediump_float", "GetShaderPrecisionFormat", GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_fragment_highp_float", "GetShaderPrecisionFormat", GL_FRAGMENT_SHADER, GL_HIGH_FLOAT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_fragment_lowp_int", "GetShaderPrecisionFormat", GL_FRAGMENT_SHADER, GL_LOW_INT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_fragment_mediump_int", "GetShaderPrecisionFormat", GL_FRAGMENT_SHADER, GL_MEDIUM_INT)); |
| addChild(new PrecisionFormatCase (m_context, "precision_fragment_highp_int", "GetShaderPrecisionFormat", GL_FRAGMENT_SHADER, GL_HIGH_INT)); |
| } |
| |
| } // Functional |
| } // gles3 |
| } // deqp |