/*-------------------------------------------------------------------------
* 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 Vertex array object tests
*//*--------------------------------------------------------------------*/
#include "es3fVertexArrayObjectTests.hpp"
#include "gluShaderProgram.hpp"
#include "gluPixelTransfer.hpp"
#include "gluRenderContext.hpp"
#include "tcuTestLog.hpp"
#include "tcuImageCompare.hpp"
#include "tcuSurface.hpp"
#include "tcuRenderTarget.hpp"
#include "deRandom.hpp"
#include "deString.h"
#include "deMemory.h"
#include <vector>
#include <string>
#include <memory>
#include "glw.h"
using std::vector;
using std::string;
namespace deqp
{
namespace gles3
{
namespace Functional
{
namespace
{
struct Attribute
{
Attribute (void);
GLboolean enabled;
GLint size;
GLint stride;
GLenum type;
GLboolean integer;
GLint divisor;
GLint offset;
GLboolean normalized;
int bufferNdx;
};
struct VertexArrayState
{
VertexArrayState (void);
vector<Attribute> attributes;
int elementArrayBuffer;
};
VertexArrayState::VertexArrayState (void)
: elementArrayBuffer(-1)
{
}
Attribute::Attribute (void)
: enabled (GL_FALSE)
, size (1)
, stride (0)
, type (GL_FLOAT)
, integer (GL_FALSE)
, divisor (0)
, offset (0)
, normalized (GL_FALSE)
, bufferNdx (0)
{
}
struct BufferSpec
{
int count;
int size;
int componentCount;
int stride;
int offset;
GLenum type;
int intRangeMin;
int intRangeMax;
float floatRangeMin;
float floatRangeMax;
};
struct Spec
{
Spec (void);
int count;
int instances;
bool useDrawElements;
GLenum indexType;
int indexOffset;
int indexRangeMin;
int indexRangeMax;
int indexCount;
VertexArrayState state;
VertexArrayState vao;
vector<BufferSpec> buffers;
};
Spec::Spec (void)
: count (-1)
, instances (-1)
, useDrawElements (false)
, indexType (GL_NONE)
, indexOffset (-1)
, indexRangeMin (-1)
, indexRangeMax (-1)
, indexCount (-1)
{
}
} // anonymous
class VertexArrayObjectTest : public TestCase
{
public:
VertexArrayObjectTest (Context& context, const Spec& spec, const char* name, const char* description);
~VertexArrayObjectTest (void);
virtual void init (void);
virtual void deinit (void);
virtual IterateResult iterate (void);
private:
Spec m_spec;
tcu::TestLog& m_log;
vector<GLuint> m_buffers;
glu::ShaderProgram* m_vaoProgram;
glu::ShaderProgram* m_stateProgram;
de::Random m_random;
deUint8* m_indices;
void logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg);
deUint8* createRandomBufferData (const BufferSpec& buffer);
deUint8* generateIndices (void);
glu::ShaderProgram* createProgram (const VertexArrayState& state);
void setState (const VertexArrayState& state);
void render (tcu::Surface& vaoResult, tcu::Surface& defaultResult);
void makeDrawCall (const VertexArrayState& state);
void genReferences (tcu::Surface& vaoRef, tcu::Surface& defaultRef);
VertexArrayObjectTest (const VertexArrayObjectTest&);
VertexArrayObjectTest& operator= (const VertexArrayObjectTest&);
};
VertexArrayObjectTest::VertexArrayObjectTest (Context& context, const Spec& spec, const char* name, const char* description)
: TestCase (context, name, description)
, m_spec (spec)
, m_log (context.getTestContext().getLog())
, m_vaoProgram (NULL)
, m_stateProgram (NULL)
, m_random (deStringHash(name))
, m_indices (NULL)
{
// Makes zero to zero mapping for buffers
m_buffers.push_back(0);
}
VertexArrayObjectTest::~VertexArrayObjectTest (void)
{
}
void VertexArrayObjectTest::logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg)
{
std::stringstream message;
message << msg << "\n";
message << "GL_ELEMENT_ARRAY_BUFFER : " << state.elementArrayBuffer << "\n";
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
message
<< "attribute : " << attribNdx << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_ENABLED : " << (state.attributes[attribNdx].enabled ? "GL_TRUE" : "GL_FALSE") << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_SIZE : " << state.attributes[attribNdx].size << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_STRIDE : " << state.attributes[attribNdx].stride << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_TYPE : " << state.attributes[attribNdx].type << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_NORMALIZED : " << (state.attributes[attribNdx].normalized ? "GL_TRUE" : "GL_FALSE") << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_INTEGER : " << (state.attributes[attribNdx].integer ? "GL_TRUE" : "GL_FALSE") << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_DIVISOR : " << state.attributes[attribNdx].divisor << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_POINTER : " << state.attributes[attribNdx].offset << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : " << m_buffers[state.attributes[attribNdx].bufferNdx] << "\n";
}
log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
}
void VertexArrayObjectTest::init (void)
{
// \note [mika] Index 0 is reserved for 0 buffer
for (int bufferNdx = 0; bufferNdx < (int)m_spec.buffers.size(); bufferNdx++)
{
deUint8* data = createRandomBufferData(m_spec.buffers[bufferNdx]);
try
{
GLuint buffer;
GLU_CHECK_CALL(glGenBuffers(1, &buffer));
m_buffers.push_back(buffer);
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, m_spec.buffers[bufferNdx].size, data, GL_DYNAMIC_DRAW));
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
} catch (...) {
delete[] data;
throw;
}
delete[] data;
}
m_vaoProgram = createProgram(m_spec.vao);
m_log << tcu::TestLog::Message << "Program used with Vertex Array Object" << tcu::TestLog::EndMessage;
m_log << *m_vaoProgram;
m_stateProgram = createProgram(m_spec.state);
m_log << tcu::TestLog::Message << "Program used with Vertex Array State" << tcu::TestLog::EndMessage;
m_log << *m_stateProgram;
if (!m_vaoProgram->isOk() || !m_stateProgram->isOk())
TCU_FAIL("Failed to compile shaders");
if (m_spec.useDrawElements && (m_spec.vao.elementArrayBuffer == 0 || m_spec.state.elementArrayBuffer == 0))
m_indices = generateIndices();
}
void VertexArrayObjectTest::deinit (void)
{
GLU_CHECK_CALL(glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])));
m_buffers.clear();
delete m_vaoProgram;
delete m_stateProgram;
delete[] m_indices;
}
deUint8* VertexArrayObjectTest::generateIndices (void)
{
int typeSize = 0;
switch (m_spec.indexType)
{
case GL_UNSIGNED_INT: typeSize = sizeof(GLuint); break;
case GL_UNSIGNED_SHORT: typeSize = sizeof(GLushort); break;
case GL_UNSIGNED_BYTE: typeSize = sizeof(GLubyte); break;
default:
DE_ASSERT(false);
}
deUint8* indices = new deUint8[m_spec.indexCount * typeSize];
for (int i = 0; i < m_spec.indexCount; i++)
{
deUint8* pos = indices + typeSize * i;
switch (m_spec.indexType)
{
case GL_UNSIGNED_INT:
{
GLuint v = (GLuint)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
deMemcpy(pos, &v, sizeof(v));
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort v = (GLushort)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
deMemcpy(pos, &v, sizeof(v));
break;
}
case GL_UNSIGNED_BYTE:
{
GLubyte v = (GLubyte)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
deMemcpy(pos, &v, sizeof(v));
break;
}
default:
DE_ASSERT(false);
}
}
return indices;
}
deUint8* VertexArrayObjectTest::createRandomBufferData (const BufferSpec& buffer)
{
deUint8* data = new deUint8[buffer.size];
int stride;
if (buffer.stride != 0)
{
stride = buffer.stride;
}
else
{
switch (buffer.type)
{
case GL_FLOAT: stride = buffer.componentCount * sizeof(GLfloat); break;
case GL_INT: stride = buffer.componentCount * sizeof(GLint); break;
case GL_UNSIGNED_INT: stride = buffer.componentCount * sizeof(GLuint); break;
case GL_SHORT: stride = buffer.componentCount * sizeof(GLshort); break;
case GL_UNSIGNED_SHORT: stride = buffer.componentCount * sizeof(GLushort); break;
case GL_BYTE: stride = buffer.componentCount * sizeof(GLbyte); break;
case GL_UNSIGNED_BYTE: stride = buffer.componentCount * sizeof(GLubyte); break;
default:
stride = 0;
DE_ASSERT(DE_FALSE);
}
}
deUint8* itr = data;
for (int pos = 0; pos < buffer.count; pos++)
{
deUint8* componentItr = itr;
for (int componentNdx = 0; componentNdx < buffer.componentCount; componentNdx++)
{
switch (buffer.type)
{
case GL_FLOAT:
{
float v = buffer.floatRangeMin + (buffer.floatRangeMax - buffer.floatRangeMin) * m_random.getFloat();
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_INT:
{
GLint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_INT:
{
GLuint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_SHORT:
{
GLshort v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_BYTE:
{
GLbyte v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_BYTE:
{
GLubyte v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
default:
DE_ASSERT(false);
};
}
itr += stride;
}
return data;
}
glu::ShaderProgram* VertexArrayObjectTest::createProgram (const VertexArrayState& state)
{
std::stringstream vertexShaderStream;
std::stringstream value;
vertexShaderStream << "#version 300 es\n";
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
if (state.attributes[attribNdx].integer)
vertexShaderStream << "layout(location = " << attribNdx << ") in mediump ivec4 a_attrib" << attribNdx << ";\n";
else
vertexShaderStream << "layout(location = " << attribNdx << ") in mediump vec4 a_attrib" << attribNdx << ";\n";
if (state.attributes[attribNdx].integer)
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (1.0f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (1.0f/((1u<<15)-1)); break;
case GL_INT: scale = (1.0f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (1.0f/((1u<<31)-1)); break;
case GL_BYTE: scale = (1.0f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (1.0f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
value << (attribNdx != 0 ? " + " : "" ) << scale << " * vec4(a_attrib" << attribNdx << ")";
}
else if (state.attributes[attribNdx].type != GL_FLOAT && !state.attributes[attribNdx].normalized)
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (0.5f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (0.5f/((1u<<15)-1)); break;
case GL_INT: scale = (0.5f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (0.5f/((1u<<31)-1)); break;
case GL_BYTE: scale = (0.5f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (0.5f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
value << (attribNdx != 0 ? " + " : "" ) << scale << " * a_attrib" << attribNdx;
}
else
value << (attribNdx != 0 ? " + " : "" ) << "a_attrib" << attribNdx;
}
vertexShaderStream
<< "out mediump vec4 v_value;\n"
<< "void main (void)\n"
<< "{\n"
<< "\tv_value = " << value.str() << ";\n";
if (state.attributes[0].integer)
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (1.0f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (1.0f/((1u<<15)-1)); break;
case GL_INT: scale = (1.0f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (1.0f/((1u<<31)-1)); break;
case GL_BYTE: scale = (1.0f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (1.0f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
vertexShaderStream
<< "\tgl_Position = vec4(" << scale << " * " << "vec3(a_attrib0.xyz), 1.0);\n"
<< "}";
}
else
{
if (state.attributes[0].normalized || state.attributes[0].type == GL_FLOAT)
{
vertexShaderStream
<< "\tgl_Position = vec4(a_attrib0.xyz, 1.0);\n"
<< "}";
}
else
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (1.0f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (1.0f/((1u<<15)-1)); break;
case GL_INT: scale = (1.0f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (1.0f/((1u<<31)-1)); break;
case GL_BYTE: scale = (1.0f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (1.0f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
scale *= 0.5;
vertexShaderStream
<< "\tgl_Position = vec4(" << scale << " * " << "a_attrib0.xyz, 1.0);\n"
<< "}";
}
}
const char* fragmentShader =
"#version 300 es\n"
"in mediump vec4 v_value;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main (void)\n"
"{\n"
"\tfragColor = vec4(v_value.xyz, 1.0);\n"
"}";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderStream.str(), fragmentShader));
}
void VertexArrayObjectTest::setState (const VertexArrayState& state)
{
GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[state.elementArrayBuffer]));
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_buffers[state.attributes[attribNdx].bufferNdx]));
if (state.attributes[attribNdx].enabled)
GLU_CHECK_CALL(glEnableVertexAttribArray(attribNdx));
else
GLU_CHECK_CALL(glDisableVertexAttribArray(attribNdx));
if (state.attributes[attribNdx].integer)
GLU_CHECK_CALL(glVertexAttribIPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
else
GLU_CHECK_CALL(glVertexAttribPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].normalized, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
GLU_CHECK_CALL(glVertexAttribDivisor(attribNdx, state.attributes[attribNdx].divisor));
}
}
void VertexArrayObjectTest::makeDrawCall (const VertexArrayState& state)
{
GLU_CHECK_CALL(glClearColor(0.7f, 0.7f, 0.7f, 1.0f));
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
if (m_spec.useDrawElements)
{
if (state.elementArrayBuffer == 0)
{
if (m_spec.instances == 0)
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices));
else
GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices, m_spec.instances));
}
else
{
if (m_spec.instances == 0)
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset)));
else
GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset), m_spec.instances));
}
}
else
{
if (m_spec.instances == 0)
GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, m_spec.count));
else
GLU_CHECK_CALL(glDrawArraysInstanced(GL_TRIANGLES, 0, m_spec.count, m_spec.instances));
}
}
void VertexArrayObjectTest::render (tcu::Surface& vaoResult, tcu::Surface& defaultResult)
{
GLuint vao = 0;
GLU_CHECK_CALL(glGenVertexArrays(1, &vao));
GLU_CHECK_CALL(glBindVertexArray(vao));
setState(m_spec.vao);
GLU_CHECK_CALL(glBindVertexArray(0));
setState(m_spec.state);
GLU_CHECK_CALL(glBindVertexArray(vao));
GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
makeDrawCall(m_spec.vao);
glu::readPixels(m_context.getRenderContext(), 0, 0, vaoResult.getAccess());
setState(m_spec.vao);
GLU_CHECK_CALL(glBindVertexArray(0));
GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
makeDrawCall(m_spec.state);
glu::readPixels(m_context.getRenderContext(), 0, 0, defaultResult.getAccess());
}
void VertexArrayObjectTest::genReferences (tcu::Surface& vaoRef, tcu::Surface& defaultRef)
{
setState(m_spec.vao);
GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
makeDrawCall(m_spec.vao);
glu::readPixels(m_context.getRenderContext(), 0, 0, vaoRef.getAccess());
setState(m_spec.state);
GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
makeDrawCall(m_spec.state);
glu::readPixels(m_context.getRenderContext(), 0, 0, defaultRef.getAccess());
}
TestCase::IterateResult VertexArrayObjectTest::iterate (void)
{
tcu::Surface vaoReference (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
tcu::Surface stateReference (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
tcu::Surface vaoResult (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
tcu::Surface stateResult (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
bool isOk;
logVertexArrayState(m_log, m_spec.vao, "Vertex Array Object State");
logVertexArrayState(m_log, m_spec.state, "OpenGL Vertex Array State");
genReferences(stateReference, vaoReference);
render(stateResult, vaoResult);
isOk = tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array State", stateReference, stateResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
isOk = isOk && tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array Object", vaoReference, vaoResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
if (isOk)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
}
class MultiVertexArrayObjectTest : public TestCase
{
public:
MultiVertexArrayObjectTest (Context& context, const char* name, const char* description);
~MultiVertexArrayObjectTest (void);
virtual void init (void);
virtual void deinit (void);
virtual IterateResult iterate (void);
private:
Spec m_spec;
tcu::TestLog& m_log;
vector<GLuint> m_buffers;
glu::ShaderProgram* m_vaoProgram;
glu::ShaderProgram* m_stateProgram;
de::Random m_random;
deUint8* m_indices;
void logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg);
deUint8* createRandomBufferData (const BufferSpec& buffer);
deUint8* generateIndices (void);
glu::ShaderProgram* createProgram (const VertexArrayState& state);
void setState (const VertexArrayState& state);
void render (tcu::Surface& vaoResult, tcu::Surface& defaultResult);
void makeDrawCall (const VertexArrayState& state);
void genReferences (tcu::Surface& vaoRef, tcu::Surface& defaultRef);
MultiVertexArrayObjectTest (const MultiVertexArrayObjectTest&);
MultiVertexArrayObjectTest& operator= (const MultiVertexArrayObjectTest&);
};
MultiVertexArrayObjectTest::MultiVertexArrayObjectTest (Context& context, const char* name, const char* description)
: TestCase (context, name, description)
, m_log (context.getTestContext().getLog())
, m_vaoProgram (NULL)
, m_stateProgram (NULL)
, m_random (deStringHash(name))
, m_indices (NULL)
{
// Makes zero to zero mapping for buffers
m_buffers.push_back(0);
}
MultiVertexArrayObjectTest::~MultiVertexArrayObjectTest (void)
{
}
void MultiVertexArrayObjectTest::logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg)
{
std::stringstream message;
message << msg << "\n";
message << "GL_ELEMENT_ARRAY_BUFFER : " << state.elementArrayBuffer << "\n";
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
message
<< "attribute : " << attribNdx << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_ENABLED : " << (state.attributes[attribNdx].enabled ? "GL_TRUE" : "GL_FALSE") << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_SIZE : " << state.attributes[attribNdx].size << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_STRIDE : " << state.attributes[attribNdx].stride << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_TYPE : " << state.attributes[attribNdx].type << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_NORMALIZED : " << (state.attributes[attribNdx].normalized ? "GL_TRUE" : "GL_FALSE") << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_INTEGER : " << (state.attributes[attribNdx].integer ? "GL_TRUE" : "GL_FALSE") << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_DIVISOR : " << state.attributes[attribNdx].divisor << "\n"
<< "\tGL_VERTEX_ATTRIB_ARRAY_POINTER : " << state.attributes[attribNdx].offset << "\n"
<< "\t GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : " << m_buffers[state.attributes[attribNdx].bufferNdx] << "\n";
}
log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
}
void MultiVertexArrayObjectTest::init (void)
{
GLint attribCount;
GLU_CHECK_CALL(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribCount));
m_spec.useDrawElements = false;
m_spec.instances = 0;
m_spec.count = 24;
m_spec.indexOffset = 0;
m_spec.indexRangeMin = 0;
m_spec.indexRangeMax = 0;
m_spec.indexType = GL_NONE;
m_spec.indexCount = 0;
m_spec.vao.elementArrayBuffer = 0;
m_spec.state.elementArrayBuffer = 0;
for (int attribNdx = 0; attribNdx < attribCount; attribNdx++)
{
BufferSpec shortCoordBuffer48 = { 48, 2*384, 4, 0, 0, GL_SHORT, -32768, 32768, 0.0f, 0.0f };
m_spec.buffers.push_back(shortCoordBuffer48);
m_spec.state.attributes.push_back(Attribute());
m_spec.state.attributes[attribNdx].enabled = (m_random.getInt(0, 4) == 0) ? GL_FALSE : GL_TRUE;
m_spec.state.attributes[attribNdx].size = m_random.getInt(2,4);
m_spec.state.attributes[attribNdx].stride = 2*m_random.getInt(1, 3);
m_spec.state.attributes[attribNdx].type = GL_SHORT;
m_spec.state.attributes[attribNdx].integer = m_random.getBool();
m_spec.state.attributes[attribNdx].divisor = m_random.getInt(0, 1);
m_spec.state.attributes[attribNdx].offset = 2*m_random.getInt(0, 2);
m_spec.state.attributes[attribNdx].normalized = m_random.getBool();
m_spec.state.attributes[attribNdx].bufferNdx = attribNdx+1;
if (attribNdx == 0)
{
m_spec.state.attributes[attribNdx].divisor = 0;
m_spec.state.attributes[attribNdx].enabled = GL_TRUE;
m_spec.state.attributes[attribNdx].size = 2;
}
m_spec.vao.attributes.push_back(Attribute());
m_spec.vao.attributes[attribNdx].enabled = (m_random.getInt(0, 4) == 0) ? GL_FALSE : GL_TRUE;
m_spec.vao.attributes[attribNdx].size = m_random.getInt(2,4);
m_spec.vao.attributes[attribNdx].stride = 2*m_random.getInt(1, 3);
m_spec.vao.attributes[attribNdx].type = GL_SHORT;
m_spec.vao.attributes[attribNdx].integer = m_random.getBool();
m_spec.vao.attributes[attribNdx].divisor = m_random.getInt(0, 1);
m_spec.vao.attributes[attribNdx].offset = 2*m_random.getInt(0, 2);
m_spec.vao.attributes[attribNdx].normalized = m_random.getBool();
m_spec.vao.attributes[attribNdx].bufferNdx = attribCount - attribNdx;
if (attribNdx == 0)
{
m_spec.vao.attributes[attribNdx].divisor = 0;
m_spec.vao.attributes[attribNdx].enabled = GL_TRUE;
m_spec.vao.attributes[attribNdx].size = 2;
}
}
// \note [mika] Index 0 is reserved for 0 buffer
for (int bufferNdx = 0; bufferNdx < (int)m_spec.buffers.size(); bufferNdx++)
{
deUint8* data = createRandomBufferData(m_spec.buffers[bufferNdx]);
try
{
GLuint buffer;
GLU_CHECK_CALL(glGenBuffers(1, &buffer));
m_buffers.push_back(buffer);
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, m_spec.buffers[bufferNdx].size, data, GL_DYNAMIC_DRAW));
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
} catch (...) {
delete[] data;
throw;
}
delete[] data;
}
m_vaoProgram = createProgram(m_spec.vao);
m_log << tcu::TestLog::Message << "Program used with Vertex Array Object" << tcu::TestLog::EndMessage;
m_log << *m_vaoProgram;
m_stateProgram = createProgram(m_spec.state);
m_log << tcu::TestLog::Message << "Program used with Vertex Array State" << tcu::TestLog::EndMessage;
m_log << *m_stateProgram;
if (!m_vaoProgram->isOk() || !m_stateProgram->isOk())
TCU_FAIL("Failed to compile shaders");
if (m_spec.useDrawElements && (m_spec.vao.elementArrayBuffer == 0 || m_spec.state.elementArrayBuffer == 0))
m_indices = generateIndices();
}
void MultiVertexArrayObjectTest::deinit (void)
{
GLU_CHECK_CALL(glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])));
m_buffers.clear();
delete m_vaoProgram;
delete m_stateProgram;
delete[] m_indices;
}
deUint8* MultiVertexArrayObjectTest::generateIndices (void)
{
int typeSize = 0;
switch (m_spec.indexType)
{
case GL_UNSIGNED_INT: typeSize = sizeof(GLuint); break;
case GL_UNSIGNED_SHORT: typeSize = sizeof(GLushort); break;
case GL_UNSIGNED_BYTE: typeSize = sizeof(GLubyte); break;
default:
DE_ASSERT(false);
}
deUint8* indices = new deUint8[m_spec.indexCount * typeSize];
for (int i = 0; i < m_spec.indexCount; i++)
{
deUint8* pos = indices + typeSize * i;
switch (m_spec.indexType)
{
case GL_UNSIGNED_INT:
{
GLuint v = (GLuint)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
deMemcpy(pos, &v, sizeof(v));
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort v = (GLushort)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
deMemcpy(pos, &v, sizeof(v));
break;
}
case GL_UNSIGNED_BYTE:
{
GLubyte v = (GLubyte)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
deMemcpy(pos, &v, sizeof(v));
break;
}
default:
DE_ASSERT(false);
}
}
return indices;
}
deUint8* MultiVertexArrayObjectTest::createRandomBufferData (const BufferSpec& buffer)
{
deUint8* data = new deUint8[buffer.size];
int stride;
if (buffer.stride != 0)
{
stride = buffer.stride;
}
else
{
switch (buffer.type)
{
case GL_FLOAT: stride = buffer.componentCount * sizeof(GLfloat); break;
case GL_INT: stride = buffer.componentCount * sizeof(GLint); break;
case GL_UNSIGNED_INT: stride = buffer.componentCount * sizeof(GLuint); break;
case GL_SHORT: stride = buffer.componentCount * sizeof(GLshort); break;
case GL_UNSIGNED_SHORT: stride = buffer.componentCount * sizeof(GLushort); break;
case GL_BYTE: stride = buffer.componentCount * sizeof(GLbyte); break;
case GL_UNSIGNED_BYTE: stride = buffer.componentCount * sizeof(GLubyte); break;
default:
stride = 0;
DE_ASSERT(DE_FALSE);
}
}
deUint8* itr = data;
for (int pos = 0; pos < buffer.count; pos++)
{
deUint8* componentItr = itr;
for (int componentNdx = 0; componentNdx < buffer.componentCount; componentNdx++)
{
switch (buffer.type)
{
case GL_FLOAT:
{
float v = buffer.floatRangeMin + (buffer.floatRangeMax - buffer.floatRangeMin) * m_random.getFloat();
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_INT:
{
GLint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_INT:
{
GLuint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_SHORT:
{
GLshort v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_BYTE:
{
GLbyte v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_BYTE:
{
GLubyte v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
default:
DE_ASSERT(false);
};
}
itr += stride;
}
return data;
}
glu::ShaderProgram* MultiVertexArrayObjectTest::createProgram (const VertexArrayState& state)
{
std::stringstream vertexShaderStream;
std::stringstream value;
vertexShaderStream << "#version 300 es\n";
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
if (state.attributes[attribNdx].integer)
vertexShaderStream << "layout(location = " << attribNdx << ") in mediump ivec4 a_attrib" << attribNdx << ";\n";
else
vertexShaderStream << "layout(location = " << attribNdx << ") in mediump vec4 a_attrib" << attribNdx << ";\n";
if (state.attributes[attribNdx].integer)
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (1.0f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (1.0f/((1u<<15)-1)); break;
case GL_INT: scale = (1.0f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (1.0f/((1u<<31)-1)); break;
case GL_BYTE: scale = (1.0f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (1.0f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
value << (attribNdx != 0 ? " + " : "" ) << scale << " * vec4(a_attrib" << attribNdx << ")";
}
else if (state.attributes[attribNdx].type != GL_FLOAT && !state.attributes[attribNdx].normalized)
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (0.5f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (0.5f/((1u<<15)-1)); break;
case GL_INT: scale = (0.5f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (0.5f/((1u<<31)-1)); break;
case GL_BYTE: scale = (0.5f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (0.5f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
value << (attribNdx != 0 ? " + " : "" ) << scale << " * a_attrib" << attribNdx;
}
else
value << (attribNdx != 0 ? " + " : "" ) << "a_attrib" << attribNdx;
}
vertexShaderStream
<< "out mediump vec4 v_value;\n"
<< "void main (void)\n"
<< "{\n"
<< "\tv_value = " << value.str() << ";\n";
if (state.attributes[0].integer)
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (1.0f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (1.0f/((1u<<15)-1)); break;
case GL_INT: scale = (1.0f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (1.0f/((1u<<31)-1)); break;
case GL_BYTE: scale = (1.0f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (1.0f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
vertexShaderStream
<< "\tgl_Position = vec4(" << scale << " * " << "a_attrib0.xyz, 1.0);\n"
<< "}";
}
else
{
if (state.attributes[0].normalized || state.attributes[0].type == GL_FLOAT)
{
vertexShaderStream
<< "\tgl_Position = vec4(a_attrib0.xyz, 1.0);\n"
<< "}";
}
else
{
float scale = 0.0f;
switch (state.attributes[0].type)
{
case GL_SHORT: scale = (1.0f/((1u<<14)-1)); break;
case GL_UNSIGNED_SHORT: scale = (1.0f/((1u<<15)-1)); break;
case GL_INT: scale = (1.0f/((1u<<30)-1)); break;
case GL_UNSIGNED_INT: scale = (1.0f/((1u<<31)-1)); break;
case GL_BYTE: scale = (1.0f/((1u<<6)-1)); break;
case GL_UNSIGNED_BYTE: scale = (1.0f/((1u<<7)-1)); break;
default:
DE_ASSERT(DE_FALSE);
}
scale *= 0.5;
vertexShaderStream
<< "\tgl_Position = vec4(" << scale << " * " << "vec3(a_attrib0.xyz), 1.0);\n"
<< "}";
}
}
const char* fragmentShader =
"#version 300 es\n"
"in mediump vec4 v_value;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main (void)\n"
"{\n"
"\tfragColor = vec4(v_value.xyz, 1.0);\n"
"}";
return new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderStream.str(), fragmentShader));
}
void MultiVertexArrayObjectTest::setState (const VertexArrayState& state)
{
GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[state.elementArrayBuffer]));
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_buffers[state.attributes[attribNdx].bufferNdx]));
if (state.attributes[attribNdx].enabled)
GLU_CHECK_CALL(glEnableVertexAttribArray(attribNdx));
else
GLU_CHECK_CALL(glDisableVertexAttribArray(attribNdx));
if (state.attributes[attribNdx].integer)
GLU_CHECK_CALL(glVertexAttribIPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
else
GLU_CHECK_CALL(glVertexAttribPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].normalized, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
GLU_CHECK_CALL(glVertexAttribDivisor(attribNdx, state.attributes[attribNdx].divisor));
}
}
void MultiVertexArrayObjectTest::makeDrawCall (const VertexArrayState& state)
{
GLU_CHECK_CALL(glClearColor(0.7f, 0.7f, 0.7f, 1.0f));
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
if (m_spec.useDrawElements)
{
if (state.elementArrayBuffer == 0)
{
if (m_spec.instances == 0)
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices));
else
GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices, m_spec.instances));
}
else
{
if (m_spec.instances == 0)
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset)));
else
GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset), m_spec.instances));
}
}
else
{
if (m_spec.instances == 0)
GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, m_spec.count));
else
GLU_CHECK_CALL(glDrawArraysInstanced(GL_TRIANGLES, 0, m_spec.count, m_spec.instances));
}
}
void MultiVertexArrayObjectTest::render (tcu::Surface& vaoResult, tcu::Surface& defaultResult)
{
GLuint vao = 0;
GLU_CHECK_CALL(glGenVertexArrays(1, &vao));
GLU_CHECK_CALL(glBindVertexArray(vao));
setState(m_spec.vao);
GLU_CHECK_CALL(glBindVertexArray(0));
setState(m_spec.state);
GLU_CHECK_CALL(glBindVertexArray(vao));
GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
makeDrawCall(m_spec.vao);
glu::readPixels(m_context.getRenderContext(), 0, 0, vaoResult.getAccess());
setState(m_spec.vao);
GLU_CHECK_CALL(glBindVertexArray(0));
GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
makeDrawCall(m_spec.state);
glu::readPixels(m_context.getRenderContext(), 0, 0, defaultResult.getAccess());
}
void MultiVertexArrayObjectTest::genReferences (tcu::Surface& vaoRef, tcu::Surface& defaultRef)
{
setState(m_spec.vao);
GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
makeDrawCall(m_spec.vao);
glu::readPixels(m_context.getRenderContext(), 0, 0, vaoRef.getAccess());
setState(m_spec.state);
GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
makeDrawCall(m_spec.state);
glu::readPixels(m_context.getRenderContext(), 0, 0, defaultRef.getAccess());
}
TestCase::IterateResult MultiVertexArrayObjectTest::iterate (void)
{
tcu::Surface vaoReference (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
tcu::Surface stateReference (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
tcu::Surface vaoResult (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
tcu::Surface stateResult (m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
bool isOk;
logVertexArrayState(m_log, m_spec.vao, "Vertex Array Object State");
logVertexArrayState(m_log, m_spec.state, "OpenGL Vertex Array State");
genReferences(stateReference, vaoReference);
render(stateResult, vaoResult);
isOk = tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array State", stateReference, stateResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
isOk = isOk && tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array Object", vaoReference, vaoResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
if (isOk)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
}
VertexArrayObjectTestGroup::VertexArrayObjectTestGroup (Context& context)
: TestCaseGroup(context, "vertex_array_objects", "Vertex array object test cases")
{
}
VertexArrayObjectTestGroup::~VertexArrayObjectTestGroup (void)
{
}
void VertexArrayObjectTestGroup::init (void)
{
BufferSpec floatCoordBuffer48_1 = { 48, 384, 2, 0, 0, GL_FLOAT, 0, 0, -1.0f, 1.0f };
BufferSpec floatCoordBuffer48_2 = { 48, 384, 2, 0, 0, GL_FLOAT, 0, 0, -1.0f, 1.0f };
BufferSpec shortCoordBuffer48 = { 48, 192, 2, 0, 0, GL_SHORT, -32768, 32768, 0.0f, 0.0f };
// Different buffer
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_FLOAT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_FALSE;
state.elementArrayBuffer = 0;
spec.buffers.push_back(floatCoordBuffer48_1);
spec.buffers.push_back(floatCoordBuffer48_2);
spec.useDrawElements = false;
spec.instances = 0;
spec.count = 48;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.state.attributes[0].bufferNdx = 1;
spec.vao.attributes[0].bufferNdx = 2;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_buffer", "diff_buffer"));
}
// Different size
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_FLOAT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_FALSE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(floatCoordBuffer48_1);
spec.useDrawElements = false;
spec.instances = 0;
spec.count = 24;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.state.attributes[0].size = 2;
spec.vao.attributes[0].size = 3;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_size", "diff_size"));
}
// Different stride
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_SHORT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_TRUE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(shortCoordBuffer48);
spec.useDrawElements = false;
spec.instances = 0;
spec.count = 24;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.vao.attributes[0].stride = 2;
spec.state.attributes[0].stride = 4;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_stride", "diff_stride"));
}
// Different types
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_SHORT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_TRUE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(shortCoordBuffer48);
spec.useDrawElements = false;
spec.instances = 0;
spec.count = 24;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.vao.attributes[0].type = GL_SHORT;
spec.state.attributes[0].type = GL_BYTE;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_type", "diff_type"));
}
// Different "integer"
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_BYTE;
state.attributes[0].integer = GL_TRUE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_FALSE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(shortCoordBuffer48);
spec.useDrawElements = false;
spec.count = 24;
spec.vao = state;
spec.state = state;
spec.instances = 0;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.state.attributes[0].integer = GL_FALSE;
spec.vao.attributes[0].integer = GL_TRUE;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_integer", "diff_integer"));
}
// Different divisor
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_SHORT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_TRUE;
state.attributes[0].bufferNdx = 1;
state.attributes[1].enabled = true;
state.attributes[1].size = 4;
state.attributes[1].stride = 0;
state.attributes[1].type = GL_FLOAT;
state.attributes[1].integer = GL_FALSE;
state.attributes[1].divisor = 0;
state.attributes[1].offset = 0;
state.attributes[1].normalized = GL_FALSE;
state.attributes[1].bufferNdx = 2;
state.elementArrayBuffer = 0;
spec.buffers.push_back(shortCoordBuffer48);
spec.buffers.push_back(floatCoordBuffer48_1);
spec.useDrawElements = false;
spec.instances = 10;
spec.count = 12;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.vao.attributes[1].divisor = 3;
spec.state.attributes[1].divisor = 2;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_divisor", "diff_divisor"));
}
// Different offset
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_SHORT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_TRUE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(shortCoordBuffer48);
spec.useDrawElements = false;
spec.instances = 0;
spec.count = 24;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.vao.attributes[0].offset = 2;
spec.state.attributes[0].offset = 4;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_offset", "diff_offset"));
}
// Different normalize
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_SHORT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_TRUE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(shortCoordBuffer48);
spec.useDrawElements = false;
spec.instances = 0;
spec.count = 48;
spec.vao = state;
spec.state = state;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 0;
spec.indexType = GL_NONE;
spec.indexCount = 0;
spec.vao.attributes[0].normalized = GL_TRUE;
spec.state.attributes[0].normalized = GL_FALSE;;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_normalize", "diff_normalize"));
}
// DrawElements with buffer / Pointer
{
Spec spec;
VertexArrayState state;
state.attributes.push_back(Attribute());
state.attributes[0].enabled = true;
state.attributes[0].size = 2;
state.attributes[0].stride = 0;
state.attributes[0].type = GL_FLOAT;
state.attributes[0].integer = GL_FALSE;
state.attributes[0].divisor = 0;
state.attributes[0].offset = 0;
state.attributes[0].normalized = GL_TRUE;
state.attributes[0].bufferNdx = 1;
state.elementArrayBuffer = 0;
spec.buffers.push_back(floatCoordBuffer48_1);
BufferSpec indexBuffer = { 24, 192, 1, 0, 0, GL_UNSIGNED_SHORT, 0, 48, 0.0f, 0.0f };
spec.buffers.push_back(indexBuffer);
spec.useDrawElements = true;
spec.count = 24;
spec.vao = state;
spec.state = state;
spec.instances = 0;
spec.indexOffset = 0;
spec.indexRangeMin = 0;
spec.indexRangeMax = 48;
spec.indexType = GL_UNSIGNED_SHORT;
spec.indexCount = 24;
spec.state.elementArrayBuffer = 0;
spec.vao.elementArrayBuffer = 2;
addChild(new VertexArrayObjectTest(m_context, spec, "diff_indices", "diff_indices"));
}
// Use all attributes
addChild(new MultiVertexArrayObjectTest(m_context, "all_attributes", "all_attributes"));
}
} // Functional
} // gles3
} // deqp