/*------------------------------------------------------------------------- * 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::string; using std::vector; 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)); } } } // namespace 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])); } } } // namespace Functional } // namespace gles31 } // namespace deqp