/*-------------------------------------------------------------------------
* 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, ((deUint8*)DE_NULL) + 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, ((deUint8*)DE_NULL) + 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, ((deUint8*)DE_NULL) + 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, ((deUint8*)DE_NULL) + 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