blob: 90aa7a7bd1485d624b71e90b958caedc08648149 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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);