Edit

kc3-lang/angle/src/tests/gl_tests/DrawBaseVertexVariantsTest.cpp

Branch :

  • Show log

    Commit

  • Author : shrekshao
    Date : 2020-04-10 16:04:26
    Hash : d26fb99e
    Message : Add DrawBaseVertexVariants Tests This tests different DrawElements*BaseVertex draw calls from different extensions including OES_draw_elements_base_vertex, EXT_draw_elements_base_vertex, and ANGLE_base_vertex_base_instance, with various combinations of base vertex, base index values. Bug: angleproject:4536 Change-Id: I3cd256522684c6040199d7704aac8575237dbd96 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2146292 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shrek Shao <shrekshao@google.com> Commit-Queue: Shrek Shao <shrekshao@google.com>

  • src/tests/gl_tests/DrawBaseVertexVariantsTest.cpp
  • //
    // Copyright 2020 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // DrawBaseVertexVariantsTest: Tests variants of drawElements*BaseVertex* call from different
    // extensions
    
    #include "gpu_info_util/SystemInfo.h"
    #include "test_utils/ANGLETest.h"
    #include "test_utils/gl_raii.h"
    
    #include <numeric>
    
    using namespace angle;
    
    namespace
    {
    
    // Create a kWidth * kHeight canvas equally split into kCountX * kCountY tiles
    // each containing a quad partially covering each tile
    constexpr uint32_t kWidth                   = 256;
    constexpr uint32_t kHeight                  = 256;
    constexpr uint32_t kCountX                  = 8;
    constexpr uint32_t kCountY                  = 8;
    constexpr int kBoxCount                     = kCountX * kCountY;
    constexpr uint32_t kIndexPatternRepeatCount = 3;
    constexpr std::array<GLfloat, 2> kTileSize  = {
        1.f / static_cast<GLfloat>(kCountX),
        1.f / static_cast<GLfloat>(kCountY),
    };
    constexpr std::array<uint32_t, 2> kTilePixelSize  = {kWidth / kCountX, kHeight / kCountY};
    constexpr std::array<GLfloat, 2> kQuadRadius      = {0.25f * kTileSize[0], 0.25f * kTileSize[1]};
    constexpr std::array<uint32_t, 2> kPixelCheckSize = {
        static_cast<uint32_t>(kQuadRadius[0] * kWidth),
        static_cast<uint32_t>(kQuadRadius[1] * kHeight)};
    
    constexpr std::array<GLfloat, 2> GetTileCenter(uint32_t x, uint32_t y)
    {
        return {
            kTileSize[0] * (0.5f + static_cast<GLfloat>(x)),
            kTileSize[1] * (0.5f + static_cast<GLfloat>(y)),
        };
    }
    constexpr std::array<std::array<GLfloat, 2>, 4> GetQuadVertices(uint32_t x, uint32_t y)
    {
        const auto center = GetTileCenter(x, y);
        return {
            std::array<GLfloat, 2>{center[0] - kQuadRadius[0], center[1] - kQuadRadius[1]},
            std::array<GLfloat, 2>{center[0] + kQuadRadius[0], center[1] - kQuadRadius[1]},
            std::array<GLfloat, 2>{center[0] + kQuadRadius[0], center[1] + kQuadRadius[1]},
            std::array<GLfloat, 2>{center[0] - kQuadRadius[0], center[1] + kQuadRadius[1]},
        };
    }
    
    enum class DrawCallVariants
    {
        DrawElementsBaseVertex,
        DrawElementsInstancedBaseVertex,
        DrawRangeElementsBaseVertex,
        DrawElementsInstancedBaseVertexBaseInstance
    };
    
    // These tests check correctness of variants of baseVertex draw calls from different extensions
    
    class DrawBaseVertexVariantsTest : public ANGLETest
    {
      protected:
        DrawBaseVertexVariantsTest()
        {
            setWindowWidth(kWidth);
            setWindowHeight(kHeight);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
    
            std::array<GLushort, 6> indices = {0, 1, 2, 0, 2, 3};
            mIndices.resize(indices.size() * kIndexPatternRepeatCount);
            for (uint32_t i = 0; i < kIndexPatternRepeatCount; i++)
            {
                size_t o  = i * indices.size();
                size_t vo = i * 4;  // each quad has 4 vertices, index offset by 4
                for (size_t j = 0; j < indices.size(); j++)
                {
                    mIndices[o + j] = vo + indices[j];
                }
            }
    
            mColorPalette = {GLColor(0x7f, 0x7f, 0x7f, 0xff),
                             GLColor::red,
                             GLColor::green,
                             GLColor::yellow,
                             GLColor::blue,
                             GLColor::magenta,
                             GLColor::cyan,
                             GLColor::white};
    
            for (uint32_t y = 0; y < kCountY; ++y)
            {
                for (uint32_t x = 0; x < kCountX; ++x)
                {
                    // v3 ---- v2
                    // |       |
                    // |       |
                    // v0 ---- v1
    
                    const auto vs = ::GetQuadVertices(x, y);
    
                    for (const auto &v : vs)
                    {
                        mVertices.insert(mVertices.end(), v.begin(), v.end());
                    }
    
                    const auto &colorPicked = mColorPalette[(x + y) % mColorPalette.size()];
                    for (int i = 0; i < 4; ++i)
                    {
                        mVertexColors.push_back(colorPicked.R);
                        mVertexColors.push_back(colorPicked.G);
                        mVertexColors.push_back(colorPicked.B);
                        mVertexColors.push_back(colorPicked.A);
                    }
                }
            }
    
            mRegularIndices.resize(kCountY * kCountX * mIndices.size());
            for (uint32_t y = 0; y < kCountY; y++)
            {
                for (uint32_t x = 0; x < kCountX; x++)
                {
                    uint32_t i  = x + y * kCountX;
                    uint32_t oi = 6 * i;
                    uint32_t ov = 4 * i;
                    for (uint32_t j = 0; j < 6; j++)
                    {
                        mRegularIndices[oi + j] = mIndices[j] + ov;
                    }
                }
            }
        }
    
        void setupProgram(GLProgram &program)
        {
            constexpr char vs[] = R"(
    precision mediump float;
    attribute vec2 vPosition;
    attribute vec4 vColor;
    varying vec4 color;
    void main()
    {
        gl_Position = vec4(vec3(vPosition, 1.0) * 2.0 - 1.0, 1.0);
        color = vColor;
    })";
            constexpr char fs[] = R"(
    precision mediump float;
    varying vec4 color;
    void main()
    {
        gl_FragColor = color;
    })";
            program.makeRaster(vs, fs);
            EXPECT_GL_NO_ERROR();
            ASSERT_TRUE(program.valid());
            glUseProgram(program.get());
            mPositionLoc = glGetAttribLocation(program.get(), "vPosition");
            ASSERT_NE(-1, mPositionLoc);
            mColorLoc = glGetAttribLocation(program.get(), "vColor");
            ASSERT_NE(-1, mColorLoc);
        }
    
        void setupIndexedBuffers(GLBuffer &vertexPositionBuffer,
                                 GLBuffer &vertexColorBuffer,
                                 GLBuffer &indexBuffer)
        {
            glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
            glBufferData(GL_ARRAY_BUFFER, sizeof(GLubyte) * mVertexColors.size(), mVertexColors.data(),
                         GL_STATIC_DRAW);
    
            glEnableVertexAttribArray(mColorLoc);
            glVertexAttribPointer(mColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
    
            glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer);
            glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mVertices.size(), mVertices.data(),
                         GL_STATIC_DRAW);
    
            glEnableVertexAttribArray(mPositionLoc);
            glVertexAttribPointer(mPositionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
    
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mIndices.size(), mIndices.data(),
                         GL_STATIC_DRAW);
    
            ASSERT_GL_NO_ERROR();
        }
    
        void doDrawElementsBaseVertexVariants(DrawCallVariants drawCallType)
        {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
            int baseRepetition = 0;
            int i              = 0;
    
            // Start at various repetitions within the patterned index buffer to exercise base
            // index.
    
            static_assert(kIndexPatternRepeatCount >= 3, "Repeat pattern count should be at least 3");
    
            while (i < kBoxCount)
            {
                int repetitionCount = std::min(3 - baseRepetition, kBoxCount - i);
    
                switch (drawCallType)
                {
                    case DrawCallVariants::DrawElementsInstancedBaseVertexBaseInstance:
                        glDrawElementsInstancedBaseVertexBaseInstanceANGLE(
                            GL_TRIANGLES, repetitionCount * 6, GL_UNSIGNED_SHORT,
                            reinterpret_cast<GLvoid *>(
                                static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
                            1, (i - baseRepetition) * 4, 0);
                        break;
                    case DrawCallVariants::DrawElementsBaseVertex:
                        glDrawElementsBaseVertexEXT(
                            GL_TRIANGLES, repetitionCount * 6, GL_UNSIGNED_SHORT,
                            reinterpret_cast<GLvoid *>(
                                static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
                            (i - baseRepetition) * 4);
                        break;
                    case DrawCallVariants::DrawElementsInstancedBaseVertex:
                        glDrawElementsInstancedBaseVertexEXT(
                            GL_TRIANGLES, repetitionCount * 6, GL_UNSIGNED_SHORT,
                            reinterpret_cast<GLvoid *>(
                                static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
                            1, (i - baseRepetition) * 4);
                        break;
                    case DrawCallVariants::DrawRangeElementsBaseVertex:
                        glDrawRangeElementsBaseVertexEXT(
                            GL_TRIANGLES, baseRepetition * 4,
                            (baseRepetition + repetitionCount) * 4 - 1, repetitionCount * 6,
                            GL_UNSIGNED_SHORT,
                            reinterpret_cast<GLvoid *>(
                                static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
                            (i - baseRepetition) * 4);
                        break;
                    default:
                        EXPECT_TRUE(false);
                        break;
                }
    
                baseRepetition = (baseRepetition + 1) % 3;
                i += repetitionCount;
            }
    
            EXPECT_GL_NO_ERROR();
            checkDrawResult();
        }
    
        void checkDrawResult()
        {
            for (uint32_t y = 0; y < kCountY; ++y)
            {
                for (uint32_t x = 0; x < kCountX; ++x)
                {
                    uint32_t center_x = x * kTilePixelSize[0] + kTilePixelSize[0] / 2;
                    uint32_t center_y = y * kTilePixelSize[1] + kTilePixelSize[1] / 2;
    
                    const auto &color = mColorPalette[(x + y) % mColorPalette.size()];
    
                    EXPECT_PIXEL_NEAR(center_x - kPixelCheckSize[0] / 2,
                                      center_y - kPixelCheckSize[1] / 2, color[0], color[1], color[2],
                                      color[3], 1);
                }
            }
        }
    
        bool requestAngleBaseVertexBaseInstanceExtensions()
        {
            if (getClientMajorVersion() <= 2)
            {
                if (!EnsureGLExtensionEnabled("GL_ANGLE_instanced_arrays"))
                {
                    return false;
                }
            }
            return EnsureGLExtensionEnabled("GL_ANGLE_base_vertex_base_instance");
        }
    
        bool requestNativeBaseVertexExtensions()
        {
            return (EnsureGLExtensionEnabled("GL_OES_draw_elements_base_vertex") ||
                    EnsureGLExtensionEnabled("GL_EXT_draw_elements_base_vertex"));
        }
    
        std::vector<GLushort> mIndices;
        std::vector<GLfloat> mVertices;
        std::vector<GLubyte> mVertexColors;
    
        std::vector<GLColor> mColorPalette;
        std::vector<GLushort> mRegularIndices;
        GLint mPositionLoc;
        GLint mColorLoc;
    };
    
    // Test drawElementsBaseVertex from OES/EXT_draw_elements_base_vertex
    TEST_P(DrawBaseVertexVariantsTest, DrawElementsBaseVertex)
    {
        ANGLE_SKIP_TEST_IF(!requestNativeBaseVertexExtensions());
    
        GLProgram program;
        setupProgram(program);
    
        GLBuffer indexBuffer;
        GLBuffer vertexPositionBuffer;
        GLBuffer vertexColorBuffer;
        setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
    
        doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsBaseVertex);
    }
    
    // Test drawElementsInstancedBaseVertex from OES/EXT_draw_elements_base_vertex
    TEST_P(DrawBaseVertexVariantsTest, DrawElementsInstancedBaseVertex)
    {
        ANGLE_SKIP_TEST_IF(!requestNativeBaseVertexExtensions());
    
        GLProgram program;
        setupProgram(program);
    
        GLBuffer indexBuffer;
        GLBuffer vertexPositionBuffer;
        GLBuffer vertexColorBuffer;
        setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
    
        doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsInstancedBaseVertex);
    }
    
    // Test drawRangeElementsBaseVertex from OES/EXT_draw_elements_base_vertex
    TEST_P(DrawBaseVertexVariantsTest, DrawRangeElementsBaseVertex)
    {
        ANGLE_SKIP_TEST_IF(!requestNativeBaseVertexExtensions());
    
        GLProgram program;
        setupProgram(program);
    
        GLBuffer indexBuffer;
        GLBuffer vertexPositionBuffer;
        GLBuffer vertexColorBuffer;
        setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
    
        doDrawElementsBaseVertexVariants(DrawCallVariants::DrawRangeElementsBaseVertex);
    }
    
    // Test drawElementsInstancedBaseVertexBaseInstance from ANGLE_base_vertex_base_instance
    TEST_P(DrawBaseVertexVariantsTest, DrawElementsInstancedBaseVertexBaseInstance)
    {
        ANGLE_SKIP_TEST_IF(!requestAngleBaseVertexBaseInstanceExtensions());
    
        GLProgram program;
        setupProgram(program);
    
        GLBuffer indexBuffer;
        GLBuffer vertexPositionBuffer;
        GLBuffer vertexColorBuffer;
        setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
    
        doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsInstancedBaseVertexBaseInstance);
    }
    
    ANGLE_INSTANTIATE_TEST_ES3(DrawBaseVertexVariantsTest);
    
    }  // namespace