/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.1 Module * ------------------------------------------------- * * Copyright 2017 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 GL_EXT_draw_elements_base_vertex tests. *//*--------------------------------------------------------------------*/ #include "es31fDrawElementsBaseVertexTests.hpp" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "tcuRenderTarget.hpp" #include "tcuVectorUtil.hpp" #include "sglrGLContext.hpp" #include "glsDrawTest.hpp" #include "gluStrUtil.hpp" #include "gluPixelTransfer.hpp" #include "gluContextInfo.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include #include using std::vector; using std::string; using tcu::TestLog; using namespace glw; namespace deqp { namespace gles31 { namespace Functional { namespace { enum TestIterationType { TYPE_DRAW_COUNT, // !< test with 1, 5, and 25 primitives TYPE_INSTANCE_COUNT, // !< test with 1, 4, and 11 instances TYPE_LAST }; static size_t getElementCount (gls::DrawTestSpec::Primitive primitive, size_t primitiveCount) { switch (primitive) { case gls::DrawTestSpec::PRIMITIVE_POINTS: return primitiveCount; case gls::DrawTestSpec::PRIMITIVE_TRIANGLES: return primitiveCount * 3; case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: return primitiveCount + 2; case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: return primitiveCount + 2; case gls::DrawTestSpec::PRIMITIVE_LINES: return primitiveCount * 2; case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP: return primitiveCount + 1; case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP: return (primitiveCount==1) ? (2) : (primitiveCount); case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: return primitiveCount * 4; case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: return primitiveCount + 3; case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: return primitiveCount * 6; case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: return primitiveCount * 2 + 4; default: DE_ASSERT(false); return 0; } } static void addRangeElementsToSpec (gls::DrawTestSpec& spec) { if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) { spec.indexMin = 0; spec.indexMax = (int)getElementCount(spec.primitive, spec.primitiveCount); } } static void addTestIterations (gls::DrawTest* test, gls::DrawTestSpec& spec, TestIterationType type) { if (type == TYPE_DRAW_COUNT) { spec.primitiveCount = 1; addRangeElementsToSpec(spec); test->addIteration(spec, "draw count = 1"); spec.primitiveCount = 5; addRangeElementsToSpec(spec); test->addIteration(spec, "draw count = 5"); spec.primitiveCount = 25; addRangeElementsToSpec(spec); test->addIteration(spec, "draw count = 25"); } else if (type == TYPE_INSTANCE_COUNT) { spec.instanceCount = 1; addRangeElementsToSpec(spec); test->addIteration(spec, "instance count = 1"); spec.instanceCount = 4; addRangeElementsToSpec(spec); test->addIteration(spec, "instance count = 4"); spec.instanceCount = 11; addRangeElementsToSpec(spec); test->addIteration(spec, "instance count = 11"); } else DE_ASSERT(false); } static void genBasicSpec (gls::DrawTestSpec& spec, glu::ContextType& contextType, gls::DrawTestSpec::DrawMethod method) { spec.apiType = glu::isContextTypeES(contextType) ? glu::ApiType::es(3,1) : contextType.getAPI(); spec.primitive = gls::DrawTestSpec::PRIMITIVE_TRIANGLES; spec.primitiveCount = 5; spec.drawMethod = method; spec.indexType = gls::DrawTestSpec::INDEXTYPE_LAST; spec.indexPointerOffset = 0; spec.indexStorage = gls::DrawTestSpec::STORAGE_LAST; spec.first = 0; spec.indexMin = 0; spec.indexMax = 0; spec.instanceCount = 1; spec.indirectOffset = 0; spec.attribs.resize(2); spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[0].componentCount = 4; spec.attribs[0].offset = 0; spec.attribs[0].stride = 0; spec.attribs[0].normalize = false; spec.attribs[0].instanceDivisor = 0; spec.attribs[0].useDefaultAttribute = false; spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[1].componentCount = 2; spec.attribs[1].offset = 0; spec.attribs[1].stride = 0; spec.attribs[1].normalize = false; spec.attribs[1].instanceDivisor = 0; spec.attribs[1].useDefaultAttribute = false; addRangeElementsToSpec(spec); } class VertexIDCase : public TestCase { public: VertexIDCase (Context& context, gls::DrawTestSpec::DrawMethod drawMethod); ~VertexIDCase (void); void init (void); void deinit (void); IterateResult iterate (void); void draw (GLenum mode, GLsizei count, GLenum type, GLvoid* indices, GLint baseVertex); void verifyImage (const tcu::Surface& image); private: const glw::Functions& m_gl; glu::ShaderProgram* m_program; GLuint m_vao; GLuint m_coordinatesBuffer; GLuint m_elementsBuffer; int m_iterNdx; gls::DrawTestSpec::DrawMethod m_method; enum { VIEWPORT_WIDTH = 64, VIEWPORT_HEIGHT = 64 }; enum { MAX_VERTICES = 2*3 //!< 2 triangles, totals 6 vertices }; }; VertexIDCase::VertexIDCase (Context& context, gls::DrawTestSpec::DrawMethod drawMethod) : TestCase (context, "vertex_id", "gl_VertexID Test") , m_gl (m_context.getRenderContext().getFunctions()) , m_program (DE_NULL) , m_vao (0) , m_coordinatesBuffer (0) , m_elementsBuffer (0) , m_iterNdx (0) , m_method (drawMethod) { } VertexIDCase::~VertexIDCase (void) { VertexIDCase::deinit(); } void VertexIDCase::init (void) { auto ctxType = m_context.getRenderContext().getType(); if (m_method == deqp::gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX || m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX || m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX) { const bool supportsES32orGL45 = contextSupports(ctxType, glu::ApiType::es(3, 2)) || contextSupports(ctxType, glu::ApiType::core(4, 5)); TCU_CHECK_AND_THROW(NotSupportedError, supportsES32orGL45 || m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_elements_base_vertex"), "GL_EXT_draw_elements_base_vertex is not supported."); } m_testCtx.getLog() << TestLog::Message << "gl_VertexID should be the index of the vertex that is being passed to the shader. i.e. indices[i] + basevertex" << TestLog::EndMessage; DE_ASSERT(!m_program); m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources( "#version 310 es\n" "in highp vec4 a_position;\n" "out mediump vec4 v_color;\n" "uniform highp vec4 u_colors[8];\n" "void main (void)\n" "{\n" " gl_Position = a_position;\n" " v_color = u_colors[gl_VertexID];\n" "}\n", "#version 310 es\n" "in mediump vec4 v_color;\n" "layout(location = 0) out mediump vec4 o_color;\n" "void main (void)\n" "{\n" " o_color = v_color;\n" "}\n")); m_testCtx.getLog() << *m_program; if (!m_program->isOk()) { delete m_program; m_program = DE_NULL; TCU_FAIL("Failed to compile shader program"); } GLU_CHECK_GLW_CALL(m_gl, useProgram(m_program->getProgram())); GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_coordinatesBuffer)); GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_elementsBuffer)); if (!glu::isContextTypeES(ctxType)) GLU_CHECK_GLW_CALL(m_gl, genVertexArrays(1, &m_vao)); } void VertexIDCase::deinit (void) { delete m_program; m_program = DE_NULL; if (m_elementsBuffer) { GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_elementsBuffer)); m_elementsBuffer = 0; } if (m_coordinatesBuffer) { GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_coordinatesBuffer)); m_coordinatesBuffer = 0; } if (m_vao) { GLU_CHECK_GLW_CALL(m_gl, deleteVertexArrays(1, &m_vao)); m_vao = 0; } } void VertexIDCase::draw (GLenum mode, GLsizei count, GLenum type, GLvoid* indices, GLint baseVertex) { switch (m_method) { case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX: GLU_CHECK_GLW_CALL(m_gl, drawElementsBaseVertex(mode, count, type, indices, baseVertex)); break; case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX: { GLint maxElementsVertices = 0; GLU_CHECK_GLW_CALL(m_gl, getIntegerv(GL_MAX_ELEMENTS_VERTICES, &maxElementsVertices)); GLU_CHECK_GLW_CALL(m_gl, drawRangeElementsBaseVertex(mode, 0, maxElementsVertices, count, type, indices, baseVertex)); break; } case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX: GLU_CHECK_GLW_CALL(m_gl, drawElementsInstancedBaseVertex(mode, count, type, indices, 1, baseVertex)); break; default: DE_FATAL("Draw method not supported"); } } void VertexIDCase::verifyImage (const tcu::Surface& image) { tcu::TestLog& log = m_testCtx.getLog(); bool isOk = true; const int colorThreshold = 0; // expect perfect match tcu::Surface error (image.getWidth(), image.getHeight()); for (int y = 0; y < image.getHeight(); y++) for (int x = 0; x < image.getWidth(); x++) { const tcu::RGBA pixel = image.getPixel(x, y); bool pixelOk = true; // Ignore pixels not drawn with basevertex if ((x < image.getWidth()* 1/4) || (x > image.getWidth() * 3/4) || (y < image.getHeight() * 1/4) || (y > image.getHeight() * 3/4)) continue; // Any pixel with !(B ~= 255) is faulty if (de::abs(pixel.getBlue() - 255) > colorThreshold) pixelOk = false; error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255))); isOk = isOk && pixelOk; } if (!isOk) { log << TestLog::Message << "Image verification failed." << TestLog::EndMessage; log << TestLog::ImageSet("Verification result", "Result of rendering") << TestLog::Image("Result", "Result", image) << TestLog::Image("Error Mask", "Error mask", error) << TestLog::EndImageSet; } else { log << TestLog::ImageSet("Verification result", "Result of rendering") << TestLog::Image("Result", "Result", image) << TestLog::EndImageSet; } if (isOk) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid"); } VertexIDCase::IterateResult VertexIDCase::iterate (void) { const GLuint drawCount = 6; const GLuint baseVertex = 4; const GLuint coordLocation = m_gl.getAttribLocation(m_program->getProgram(), "a_position"); const GLuint colorLocation = m_gl.getUniformLocation(m_program->getProgram(), "u_colors[0]"); tcu::Surface surface(VIEWPORT_WIDTH, VIEWPORT_HEIGHT); const GLfloat coords[] = { // full viewport quad -1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, // half viewport quad centred -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, }; const GLushort indices[] = { 0, 1, 2, 2, 3, 0, }; const GLfloat colors[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f, 0.5f, 1.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // blue 0.0f, 0.0f, 1.0f, 1.0f, // blue 0.0f, 0.0f, 1.0f, 1.0f, // blue 0.0f, 0.0f, 1.0f, 1.0f, // blue }; GLU_CHECK_GLW_CALL(m_gl, viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT)); GLU_CHECK_GLW_CALL(m_gl, clearColor(1.0f, 1.0f, 1.0f, 1.0f)); // white GLU_CHECK_GLW_CALL(m_gl, clear(GL_COLOR_BUFFER_BIT)); GLU_CHECK_GLW_CALL(m_gl, uniform4fv(colorLocation, DE_LENGTH_OF_ARRAY(colors), &colors[0])); GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ARRAY_BUFFER, m_coordinatesBuffer)); GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW)); if (m_vao) GLU_CHECK_GLW_CALL(m_gl, bindVertexArray(m_vao)); GLU_CHECK_GLW_CALL(m_gl, enableVertexAttribArray(coordLocation)); GLU_CHECK_GLW_CALL(m_gl, vertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL)); if (m_iterNdx == 0) { tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter0", "Indices in client-side array"); draw(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, (GLvoid*)indices, baseVertex); } if (m_iterNdx == 1) { tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter1", "Indices in element array buffer"); GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementsBuffer)); GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)sizeof(indices), &indices[0], GL_STATIC_DRAW)); draw(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, DE_NULL, baseVertex); } glu::readPixels(m_context.getRenderContext(), 0, 0, surface.getAccess()); verifyImage(surface); m_iterNdx += 1; return (m_iterNdx < 2) ? CONTINUE : STOP; } class BuiltInVariableGroup : public TestCaseGroup { public: BuiltInVariableGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); ~BuiltInVariableGroup (void); void init (void); private: gls::DrawTestSpec::DrawMethod m_method; }; BuiltInVariableGroup::BuiltInVariableGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) : TestCaseGroup (context, name, descr) , m_method (drawMethod) { } BuiltInVariableGroup::~BuiltInVariableGroup (void) { } void BuiltInVariableGroup::init (void) { addChild(new VertexIDCase(m_context, m_method)); } class IndexGroup : public TestCaseGroup { public: IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); ~IndexGroup (void); void init (void); private: gls::DrawTestSpec::DrawMethod m_method; }; IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) : TestCaseGroup (context, name, descr) , m_method (drawMethod) { } IndexGroup::~IndexGroup (void) { } void IndexGroup::init (void) { struct IndexTest { gls::DrawTestSpec::IndexType type; int offsets[3]; }; const IndexTest tests[] = { { gls::DrawTestSpec::INDEXTYPE_BYTE, { 0, 1, -1 } }, { gls::DrawTestSpec::INDEXTYPE_SHORT, { 0, 2, -1 } }, { gls::DrawTestSpec::INDEXTYPE_INT, { 0, 4, -1 } }, }; gls::DrawTestSpec spec; glu::ContextType contextType = m_context.getRenderContext().getType(); genBasicSpec(spec, contextType, m_method); spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER; for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx) { const IndexTest& indexTest = tests[testNdx]; const std::string name = std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type); const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type); gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()); spec.indexType = indexTest.type; for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx) { const std::string iterationDesc = std::string("first vertex ") + de::toString(indexTest.offsets[iterationNdx] / gls::DrawTestSpec::indexTypeSize(indexTest.type)); spec.indexPointerOffset = indexTest.offsets[iterationNdx]; test->addIteration(spec, iterationDesc.c_str()); } addChild(test); } } class BaseVertexGroup : public TestCaseGroup { public: BaseVertexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); ~BaseVertexGroup (void); void init (void); private: gls::DrawTestSpec::DrawMethod m_method; }; BaseVertexGroup::BaseVertexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) : TestCaseGroup (context, name, descr) , m_method (drawMethod) { } BaseVertexGroup::~BaseVertexGroup (void) { } void BaseVertexGroup::init (void) { struct IndexTest { bool positiveBase; gls::DrawTestSpec::IndexType type; int baseVertex[2]; }; const IndexTest tests[] = { { true, gls::DrawTestSpec::INDEXTYPE_BYTE, { 1, 2 } }, { true, gls::DrawTestSpec::INDEXTYPE_SHORT, { 1, 2 } }, { true, gls::DrawTestSpec::INDEXTYPE_INT, { 1, 2 } }, { false, gls::DrawTestSpec::INDEXTYPE_BYTE, { -1, -2 } }, { false, gls::DrawTestSpec::INDEXTYPE_SHORT, { -1, -2 } }, { false, gls::DrawTestSpec::INDEXTYPE_INT, { -1, -2 } }, }; gls::DrawTestSpec spec; glu::ContextType contextType = m_context.getRenderContext().getType(); genBasicSpec(spec, contextType, m_method); spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER; for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx) { const IndexTest& indexTest = tests[testNdx]; const std::string name = std::string("index_") + (indexTest.positiveBase ? "" : "neg_") + gls::DrawTestSpec::indexTypeToString(indexTest.type); const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type); gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()); spec.indexType = indexTest.type; for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.baseVertex); ++iterationNdx) { const std::string iterationDesc = std::string("base vertex ") + de::toString(indexTest.baseVertex[iterationNdx]); spec.baseVertex = indexTest.baseVertex[iterationNdx]; // spec.indexMin + spec.baseVertex can not be a negative value if (spec.indexMin + spec.baseVertex < 0) { spec.indexMax -= (spec.indexMin + spec.baseVertex); spec.indexMin -= (spec.indexMin + spec.baseVertex); } test->addIteration(spec, iterationDesc.c_str()); } addChild(test); } } class AttributeGroup : public TestCaseGroup { public: AttributeGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage); ~AttributeGroup (void); void init (void); private: gls::DrawTestSpec::DrawMethod m_method; gls::DrawTestSpec::Primitive m_primitive; gls::DrawTestSpec::IndexType m_indexType; gls::DrawTestSpec::Storage m_indexStorage; }; AttributeGroup::AttributeGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage) : TestCaseGroup (context, name, descr) , m_method (drawMethod) , m_primitive (primitive) , m_indexType (indexType) , m_indexStorage (indexStorage) { } AttributeGroup::~AttributeGroup (void) { } void AttributeGroup::init (void) { // Single attribute { gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array."); gls::DrawTestSpec spec; glu::ContextType contextType = m_context.getRenderContext().getType(); spec.apiType = glu::isContextTypeES(contextType) ? glu::ApiType::es(3,1) : contextType.getAPI(); spec.primitive = m_primitive; spec.primitiveCount = 5; spec.drawMethod = m_method; spec.indexType = m_indexType; spec.indexPointerOffset = 0; spec.indexStorage = m_indexStorage; spec.first = 0; spec.indexMin = 0; spec.indexMax = 0; spec.instanceCount = 1; spec.indirectOffset = 0; spec.attribs.resize(1); spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[0].componentCount = 2; spec.attribs[0].offset = 0; spec.attribs[0].stride = 0; spec.attribs[0].normalize = false; spec.attribs[0].instanceDivisor = 0; spec.attribs[0].useDefaultAttribute = false; addTestIterations(test, spec, TYPE_DRAW_COUNT); this->addChild(test); } // Multiple attribute { gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes", "Multiple attribute arrays."); gls::DrawTestSpec spec; glu::ContextType contextType = m_context.getRenderContext().getType(); spec.apiType = glu::isContextTypeES(contextType) ? glu::ApiType::es(3,1) : contextType.getAPI(); spec.primitive = m_primitive; spec.primitiveCount = 5; spec.drawMethod = m_method; spec.indexType = m_indexType; spec.indexPointerOffset = 0; spec.indexStorage = m_indexStorage; spec.first = 0; spec.indexMin = 0; spec.indexMax = 0; spec.instanceCount = 1; spec.indirectOffset = 0; spec.attribs.resize(2); spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[0].componentCount = 4; spec.attribs[0].offset = 0; spec.attribs[0].stride = 0; spec.attribs[0].normalize = false; spec.attribs[0].instanceDivisor = 0; spec.attribs[0].useDefaultAttribute = false; spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[1].componentCount = 2; spec.attribs[1].offset = 0; spec.attribs[1].stride = 0; spec.attribs[1].normalize = false; spec.attribs[1].instanceDivisor = 0; spec.attribs[1].useDefaultAttribute = false; addTestIterations(test, spec, TYPE_DRAW_COUNT); this->addChild(test); } // Multiple attribute, second one divided { gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes", "Instanced attribute array."); gls::DrawTestSpec spec; glu::ContextType contextType = m_context.getRenderContext().getType(); spec.apiType = glu::isContextTypeES(contextType) ? glu::ApiType::es(3,1) : contextType.getAPI(); spec.primitive = m_primitive; spec.primitiveCount = 5; spec.drawMethod = m_method; spec.indexType = m_indexType; spec.indexPointerOffset = 0; spec.indexStorage = m_indexStorage; spec.first = 0; spec.indexMin = 0; spec.indexMax = 0; spec.instanceCount = 1; spec.indirectOffset = 0; spec.attribs.resize(3); spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[0].componentCount = 4; spec.attribs[0].offset = 0; spec.attribs[0].stride = 0; spec.attribs[0].normalize = false; spec.attribs[0].instanceDivisor = 0; spec.attribs[0].useDefaultAttribute = false; // Add another position component so the instances wont be drawn on each other spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[1].componentCount = 2; spec.attribs[1].offset = 0; spec.attribs[1].stride = 0; spec.attribs[1].normalize = false; spec.attribs[1].instanceDivisor = 1; spec.attribs[1].useDefaultAttribute = false; spec.attribs[1].additionalPositionAttribute = true; // Instanced color spec.attribs[2].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[2].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[2].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[2].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[2].componentCount = 3; spec.attribs[2].offset = 0; spec.attribs[2].stride = 0; spec.attribs[2].normalize = false; spec.attribs[2].instanceDivisor = 1; spec.attribs[2].useDefaultAttribute = false; addTestIterations(test, spec, TYPE_INSTANCE_COUNT); this->addChild(test); } // Multiple attribute, second one default { gls::DrawTest* test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute", "Attribute specified with glVertexAttrib*."); gls::DrawTestSpec spec; glu::ContextType contextType = m_context.getRenderContext().getType(); spec.apiType = glu::isContextTypeES(contextType) ? glu::ApiType::es(3,1) : contextType.getAPI(); spec.primitive = m_primitive; spec.primitiveCount = 5; spec.drawMethod = m_method; spec.indexType = m_indexType; spec.indexPointerOffset = 0; spec.indexStorage = m_indexStorage; spec.first = 0; spec.indexMin = 0; spec.indexMax = 0; spec.instanceCount = 1; spec.indirectOffset = 0; spec.attribs.resize(2); spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[0].componentCount = 2; spec.attribs[0].offset = 0; spec.attribs[0].stride = 0; spec.attribs[0].normalize = false; spec.attribs[0].instanceDivisor = 0; spec.attribs[0].useDefaultAttribute = false; struct IOPair { gls::DrawTestSpec::InputType input; gls::DrawTestSpec::OutputType output; int componentCount; } iopairs[] = { { gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC2, 4 }, { gls::DrawTestSpec::INPUTTYPE_FLOAT, gls::DrawTestSpec::OUTPUTTYPE_VEC4, 2 }, { gls::DrawTestSpec::INPUTTYPE_INT, gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4 }, { gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4 }, }; for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx) { const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) + de::toString(iopairs[ioNdx].componentCount) + " to " + gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output); spec.attribs[1].inputType = iopairs[ioNdx].input; spec.attribs[1].outputType = iopairs[ioNdx].output; spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; spec.attribs[1].componentCount = iopairs[ioNdx].componentCount; spec.attribs[1].offset = 0; spec.attribs[1].stride = 0; spec.attribs[1].normalize = false; spec.attribs[1].instanceDivisor = 0; spec.attribs[1].useDefaultAttribute = true; test->addIteration(spec, desc.c_str()); } this->addChild(test); } } class MethodGroup : public TestCaseGroup { public: MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); ~MethodGroup (void); void init (void); private: gls::DrawTestSpec::DrawMethod m_method; }; MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) : TestCaseGroup (context, name, descr) , m_method (drawMethod) { } MethodGroup::~MethodGroup (void) { } void MethodGroup::init (void) { const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX); const gls::DrawTestSpec::Primitive primitive[] = { gls::DrawTestSpec::PRIMITIVE_POINTS, gls::DrawTestSpec::PRIMITIVE_TRIANGLES, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP, gls::DrawTestSpec::PRIMITIVE_LINES, gls::DrawTestSpec::PRIMITIVE_LINE_STRIP, gls::DrawTestSpec::PRIMITIVE_LINE_LOOP }; if (indexed) { // Index-tests this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method)); this->addChild(new BaseVertexGroup(m_context, "base_vertex", "Base vertex tests", m_method)); this->addChild(new BuiltInVariableGroup(m_context, "builtin_variable", "Built in shader variable tests", m_method)); } for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx) { const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]); const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]); this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx], gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER)); } } } // anonymous DrawElementsBaseVertexTests::DrawElementsBaseVertexTests (Context& context) : TestCaseGroup(context, "draw_base_vertex", "Base vertex extension drawing tests") { } DrawElementsBaseVertexTests::~DrawElementsBaseVertexTests (void) { } void DrawElementsBaseVertexTests::init (void) { const gls::DrawTestSpec::DrawMethod basicMethods[] = { gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX, gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX, gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX, }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx) { const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx])); } } } // Functional } // gles31 } // deqp