Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2020-07-02 16:21:59
    Hash : ad782a84
    Message : Tests: Use "__" to delineate test config names. This will allow the ANGLE test runner to identify test configs for tests that use parameterization to break up different test permutations with the same config. Note that GoogleTest doesn't allow for anything other than alphanumeric characters or "_" in test names. Bug: angleproject:3162 Change-Id: Iee215fbd8c397eef04dce0269da9b58ec568fce7 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2280402 Reviewed-by: Yuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • 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 GLenum kBufferDataUsage[] = {GL_STATIC_DRAW, GL_DYNAMIC_DRAW, GL_STREAM_DRAW};
    
    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
    };
    
    using DrawBaseVertexVariantsTestParams = std::tuple<angle::PlatformParameters, GLenum>;
    
    std::string DrawBaseVertexVariantsTestPrint(
        const ::testing::TestParamInfo<DrawBaseVertexVariantsTestParams> &paramsInfo)
    {
        const DrawBaseVertexVariantsTestParams &params = paramsInfo.param;
        std::ostringstream out;
    
        out << std::get<0>(params) << "__";
    
        switch (std::get<1>(params))
        {
            case GL_STATIC_DRAW:
                out << "STATIC_DRAW";
                break;
            case GL_DYNAMIC_DRAW:
                out << "DYNAMIC_DRAW";
                break;
            case GL_STREAM_DRAW:
                out << "STREAM_DRAW";
                break;
            default:
                out << "UPDATE_THIS_SWITCH";
                break;
        }
    
        return out.str();
    }
    
    // These tests check correctness of variants of baseVertex draw calls from different extensions
    
    class DrawBaseVertexVariantsTest : public ANGLETestWithParam<DrawBaseVertexVariantsTestParams>
    {
      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)
        {
            GLenum usage = std::get<1>(GetParam());
    
            glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
            glBufferData(GL_ARRAY_BUFFER, sizeof(GLubyte) * mVertexColors.size(), mVertexColors.data(),
                         usage);
    
            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(), usage);
    
            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(),
                         usage);
    
            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);
    
                updateVertexColorData(i, repetitionCount);
    
                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 updateVertexColorData(GLint drawnQuadCount, GLint toDrawQuadCount)
        {
            // update the vertex color of the next [count] of quads to draw
            if (std::get<1>(GetParam()) == GL_STATIC_DRAW)
            {
                return;
            }
    
            GLint offset = sizeof(GLubyte) * drawnQuadCount * 4 * sizeof(GLColor);
    
            for (GLint i = 0; i < toDrawQuadCount; i++)
            {
                const GLColor &color = mColorPalette[(drawnQuadCount + i) % mColorPalette.size()];
                for (GLint j = 0; j < 4; j++)
                {
                    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(GLColor), color.data());
                    offset += sizeof(GLColor);
                }
            }
        }
    
        void checkDrawResult()
        {
            bool dynamicLayout = std::get<1>(GetParam()) == GL_STATIC_DRAW ? false : true;
    
            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[(dynamicLayout ? x : 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);
    
        // for potential update vertex color later
        glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
    
        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);
    
        // for potential update vertex color later
        glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
    
        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);
    
        // for potential update vertex color later
        glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
    
        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);
    
        // for potential update vertex color later
        glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
    
        doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsInstancedBaseVertexBaseInstance);
    }
    
    ANGLE_INSTANTIATE_TEST_COMBINE_1(DrawBaseVertexVariantsTest,
                                     DrawBaseVertexVariantsTestPrint,
                                     testing::ValuesIn(kBufferDataUsage),
                                     ES3_D3D11(),
                                     ES3_OPENGL(),
                                     ES3_OPENGLES(),
                                     ES3_VULKAN());
    
    }  // namespace