You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1624 lines
48 KiB
1624 lines
48 KiB
/*-------------------------------------------------------------------------
|
|
* 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 * (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(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 = (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(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/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(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/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(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/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(DE_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;
|
|
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 * (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(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 = (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(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/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(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/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(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/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(DE_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"));
|
|
}
|
|
|
|
} // Functional
|
|
} // gles3
|
|
} // deqp
|