| /*------------------------------------------------------------------------- |
| * 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 |