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.
1615 lines
48 KiB
1615 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)); |
|
|
|
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
|
|
|