blob: 676e960e376fe6cba86d7201ba9439d81a3f0455 [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* 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::string;
using std::vector;
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)
{
}
} // namespace
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;
uint8_t *m_indices;
void logVertexArrayState(tcu::TestLog &log, const VertexArrayState &state, const std::string &msg);
uint8_t *createRandomBufferData(const BufferSpec &buffer);
uint8_t *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++)
{
uint8_t *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;
}
uint8_t *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);
}
uint8_t *indices = new uint8_t[m_spec.indexCount * typeSize];
for (int i = 0; i < m_spec.indexCount; i++)
{
uint8_t *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;
}
uint8_t *VertexArrayObjectTest::createRandomBufferData(const BufferSpec &buffer)
{
uint8_t *data = new uint8_t[buffer.size];
int stride;
if (buffer.stride != 0)
{
stride = buffer.stride;
}
else
{
switch (buffer.type)
{
case GL_FLOAT:
stride = buffer.componentCount * (int)sizeof(GLfloat);
break;
case GL_INT:
stride = buffer.componentCount * (int)sizeof(GLint);
break;
case GL_UNSIGNED_INT:
stride = buffer.componentCount * (int)sizeof(GLuint);
break;
case GL_SHORT:
stride = buffer.componentCount * (int)sizeof(GLshort);
break;
case GL_UNSIGNED_SHORT:
stride = buffer.componentCount * (int)sizeof(GLushort);
break;
case GL_BYTE:
stride = buffer.componentCount * (int)sizeof(GLbyte);
break;
case GL_UNSIGNED_BYTE:
stride = buffer.componentCount * (int)sizeof(GLubyte);
break;
default:
stride = 0;
DE_ASSERT(false);
}
}
uint8_t *itr = data;
for (int pos = 0; pos < buffer.count; pos++)
{
uint8_t *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 = (GLshort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort v = (GLushort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_BYTE:
{
GLbyte v = (GLbyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_BYTE:
{
GLubyte v = (GLubyte)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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (1.0f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (1.0f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (1.0f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (1.0f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (1.0f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (0.5f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (0.5f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (0.5f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (0.5f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (0.5f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (1.0f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (1.0f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (1.0f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (1.0f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (1.0f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (1.0f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (1.0f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (1.0f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (1.0f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (1.0f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(false);
}
scale *= 0.5f;
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));
for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
{
if (state.attributes[attribNdx].integer)
glVertexAttribI4i(attribNdx, 0, 0, 0, 1);
else
glVertexAttrib4f(attribNdx, 0.0f, 0.0f, 0.0f, 1.0f);
}
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;
uint8_t *m_indices;
void logVertexArrayState(tcu::TestLog &log, const VertexArrayState &state, const std::string &msg);
uint8_t *createRandomBufferData(const BufferSpec &buffer);
uint8_t *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++)
{
uint8_t *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;
}
uint8_t *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);
}
uint8_t *indices = new uint8_t[m_spec.indexCount * typeSize];
for (int i = 0; i < m_spec.indexCount; i++)
{
uint8_t *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;
}
uint8_t *MultiVertexArrayObjectTest::createRandomBufferData(const BufferSpec &buffer)
{
uint8_t *data = new uint8_t[buffer.size];
int stride;
if (buffer.stride != 0)
{
stride = buffer.stride;
}
else
{
switch (buffer.type)
{
case GL_FLOAT:
stride = buffer.componentCount * (int)sizeof(GLfloat);
break;
case GL_INT:
stride = buffer.componentCount * (int)sizeof(GLint);
break;
case GL_UNSIGNED_INT:
stride = buffer.componentCount * (int)sizeof(GLuint);
break;
case GL_SHORT:
stride = buffer.componentCount * (int)sizeof(GLshort);
break;
case GL_UNSIGNED_SHORT:
stride = buffer.componentCount * (int)sizeof(GLushort);
break;
case GL_BYTE:
stride = buffer.componentCount * (int)sizeof(GLbyte);
break;
case GL_UNSIGNED_BYTE:
stride = buffer.componentCount * (int)sizeof(GLubyte);
break;
default:
stride = 0;
DE_ASSERT(false);
}
}
uint8_t *itr = data;
for (int pos = 0; pos < buffer.count; pos++)
{
uint8_t *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 = (GLuint)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_SHORT:
{
GLshort v = (GLshort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_SHORT:
{
GLushort v = (GLushort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_BYTE:
{
GLbyte v = (GLbyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
deMemcpy(componentItr, &v, sizeof(v));
componentItr += sizeof(v);
break;
}
case GL_UNSIGNED_BYTE:
{
GLubyte v = (GLubyte)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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (1.0f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (1.0f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (1.0f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (1.0f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (1.0f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (0.5f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (0.5f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (0.5f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (0.5f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (0.5f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (1.0f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (1.0f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (1.0f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (1.0f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (1.0f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(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 / float((1u << 14) - 1u));
break;
case GL_UNSIGNED_SHORT:
scale = (1.0f / float((1u << 15) - 1u));
break;
case GL_INT:
scale = (1.0f / float((1u << 30) - 1u));
break;
case GL_UNSIGNED_INT:
scale = (1.0f / float((1u << 31) - 1u));
break;
case GL_BYTE:
scale = (1.0f / float((1u << 6) - 1u));
break;
case GL_UNSIGNED_BYTE:
scale = (1.0f / float((1u << 7) - 1u));
break;
default:
DE_ASSERT(false);
}
scale *= 0.5f;
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"));
}
} // namespace Functional
} // namespace gles3
} // namespace deqp