Edit

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

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2020-01-09 11:14:47
    Hash : 6b275406
    Message : Vulkan: Workaround vertex attributes vs stride issue on AMD Under robustBufferAccess, Vulkan states that: Vertex input attributes are considered out of bounds if the offset of the attribute in the bound vertex buffer range plus the size of the attribute is greater than either: - vertexBufferRangeSize, if bindingStride == 0; or - (vertexBufferRangeSize - (vertexBufferRangeSize % bindingStride)) The latter implies that if the buffer size is not a multiple of the vertex attribute stride, what lies beyond the last multiple of stride is considered out of bounds. It also says: Out-of-bounds buffer loads will return any of the following values: - Values from anywhere within the memory range(s) bound to the buffer (possibly including bytes of memory past the end of the buffer, up to the end of the bound range). - Zero values, or (0,0,0,x) vectors for vector reads where x is a valid value represented in the type of the vector components and may be any of ... The first bullet point indicates that the driver is allowed to load the attribute values from the buffer if its range still lies within the buffer size. Take the following example: - Buffer size = 12 - Attribute stride = 8 - Attribute offset = 0 - Attribute size = 4 Basically the buffer is thus laid out as follows: attr stride _________/\_________ / \ +----------+----------+----------+ | vertex 0 | padding | vertex 1 | +----------+----------+----------+ \___ ____/ V attr size In the above example, the attribute for vertex 1 is considered out of bounds, but the driver is allowed to either read it correctly, or return (0, 0, 0, 1) for it. Most drivers implement the former, while AMD implements the latter. This change introduces a workaround for AMD where GL_MAX_VERTEX_ATTRIB_STRIDE is limited to 2048 (the common value for it according to gpuinfo.org) and conservatively rounds up every buffer allocation to that size. While technically, this workaround should be applied on any device with the robustBufferAccess feature enabled, it is currently limited to AMD to avoid the inefficiency. A possible future revision of Vulkan may relax the above restrictions. Bug: angleproject:2848 Change-Id: Ida5ae5d777da10f22ce8be5a09a7644b5bbd778e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1991709 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/tests/gl_tests/IndexedPointsTest.cpp
  • //
    // Copyright 2015 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.
    //
    
    #include "test_utils/ANGLETest.h"
    
    using namespace angle;
    
    template <typename IndexType, GLenum IndexTypeName>
    class IndexedPointsTest : public ANGLETest
    {
      protected:
        IndexedPointsTest()
        {
            setWindowWidth(128);
            setWindowHeight(128);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
            setConfigDepthBits(24);
        }
    
        float getIndexPositionX(size_t idx) { return (idx == 0 || idx == 3) ? -0.5f : 0.5f; }
    
        float getIndexPositionY(size_t idx) { return (idx == 2 || idx == 3) ? -0.5f : 0.5f; }
    
        void testSetUp() override
        {
            constexpr char kVS[] = R"(precision highp float;
    attribute vec2 position;
    
    void main() {
        gl_PointSize = 5.0;
        gl_Position  = vec4(position, 0.0, 1.0);
    })";
    
            constexpr char kFS[] = R"(precision highp float;
    void main()
    {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    })";
    
            mProgram = CompileProgram(kVS, kFS);
            ASSERT_NE(0u, mProgram);
    
            constexpr char kVS2[] = R"(precision highp float;
    attribute vec2 position;
    attribute vec4 color;
    varying vec4 vcolor;
    
    void main() {
        gl_PointSize = 5.0;
        gl_Position  = vec4(position, 0.0, 1.0);
        vcolor       = color;
    })";
    
            constexpr char kFS2[] = R"(precision highp float;
    varying vec4 vcolor;
    
    void main()
    {
        gl_FragColor = vec4(vcolor.xyz, 1.0);
    })";
    
            mVertexWithColorBufferProgram = CompileProgram(kVS2, kFS2);
            ASSERT_NE(0u, mVertexWithColorBufferProgram);
    
            // Construct a vertex buffer of position values and color values
            // contained in a single structure
            const float verticesWithColor[] = {
                getIndexPositionX(0), getIndexPositionY(0), 0.0f, 1.0f, 0.0f,
                getIndexPositionX(2), getIndexPositionY(2), 0.0f, 1.0f, 0.0f,
                getIndexPositionX(1), getIndexPositionY(1), 0.0f, 1.0f, 0.0f,
                getIndexPositionX(3), getIndexPositionY(3), 0.0f, 1.0f, 0.0f,
            };
    
            glGenBuffers(1, &mVertexWithColorBuffer);
            glBindBuffer(GL_ARRAY_BUFFER, mVertexWithColorBuffer);
            glBufferData(GL_ARRAY_BUFFER, sizeof(verticesWithColor), &verticesWithColor[0],
                         GL_STATIC_DRAW);
    
            // Construct a vertex buffer of position values only
            const GLfloat vertices[] = {
                getIndexPositionX(0), getIndexPositionY(0), getIndexPositionX(2), getIndexPositionY(2),
                getIndexPositionX(1), getIndexPositionY(1), getIndexPositionX(3), getIndexPositionY(3),
            };
            glGenBuffers(1, &mVertexBuffer);
            glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
            glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
    
            // The indices buffer is shared between both variations of tests
            const IndexType indices[] = {0, 2, 1, 3};
            glGenBuffers(1, &mIndexBuffer);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0], GL_STATIC_DRAW);
        }
    
        void testTearDown() override
        {
            glDeleteBuffers(1, &mVertexBuffer);
            glDeleteBuffers(1, &mIndexBuffer);
            glDeleteProgram(mProgram);
    
            glDeleteBuffers(1, &mVertexWithColorBuffer);
            glDeleteProgram(mVertexWithColorBufferProgram);
        }
    
        void runTest(GLuint firstIndex, bool useVertexBufferWithColor = false)
        {
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
    
            GLint viewportSize[4];
            glGetIntegerv(GL_VIEWPORT, viewportSize);
    
            // Choose appropriate program to apply for the test
            GLuint program = useVertexBufferWithColor ? mVertexWithColorBufferProgram : mProgram;
    
            if (useVertexBufferWithColor)
            {
                glBindBuffer(GL_ARRAY_BUFFER, mVertexWithColorBuffer);
                GLint vertexLocation = glGetAttribLocation(program, "position");
                glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE,
                                      static_cast<const GLsizei>(VertexWithColorSize), 0);
                glEnableVertexAttribArray(vertexLocation);
    
                GLint vertexColorLocation = glGetAttribLocation(program, "color");
                glVertexAttribPointer(vertexColorLocation, 3, GL_FLOAT, GL_FALSE,
                                      static_cast<const GLsizei>(VertexWithColorSize),
                                      (void *)((sizeof(float) * 2)));
                glEnableVertexAttribArray(vertexColorLocation);
            }
            else
            {
                glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
                GLint vertexLocation = glGetAttribLocation(program, "position");
                glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
                glEnableVertexAttribArray(vertexLocation);
            }
    
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
            glUseProgram(program);
    
            glDrawElements(GL_POINTS, mPointCount - firstIndex, IndexTypeName,
                           reinterpret_cast<void *>(firstIndex * sizeof(IndexType)));
    
            for (size_t i = 0; i < mPointCount; i++)
            {
                GLuint x =
                    static_cast<GLuint>(viewportSize[0] + (getIndexPositionX(i) * 0.5f + 0.5f) *
                                                              (viewportSize[2] - viewportSize[0]));
                GLuint y =
                    static_cast<GLuint>(viewportSize[1] + (getIndexPositionY(i) * 0.5f + 0.5f) *
                                                              (viewportSize[3] - viewportSize[1]));
    
                if (i < firstIndex)
                {
                    EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::black);
                }
                else
                {
                    if (useVertexBufferWithColor)
                    {
                        EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
                    }
                    else
                    {
                        EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red);
                    }
                }
            }
            swapBuffers();
        }
    
        GLuint mProgram;
        GLuint mVertexBuffer;
        GLuint mIndexBuffer;
    
        GLuint mVertexWithColorBufferProgram;
        GLuint mVertexWithColorBuffer;
    
        static const GLuint mPointCount = 4;
    
      private:
        const size_t VertexWithColorSize = sizeof(float) * 5;
    };
    
    typedef IndexedPointsTest<GLubyte, GL_UNSIGNED_BYTE> IndexedPointsTestUByte;
    
    TEST_P(IndexedPointsTestUByte, UnsignedByteOffset0)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(0);
    }
    
    TEST_P(IndexedPointsTestUByte, UnsignedByteOffset1)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(1);
    }
    
    TEST_P(IndexedPointsTestUByte, UnsignedByteOffset2)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(2);
    }
    
    TEST_P(IndexedPointsTestUByte, UnsignedByteOffset3)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(3);
    }
    
    TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset0)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(0, true);
    }
    
    TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset1)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(1, true);
    }
    
    TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset2)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(2, true);
    }
    
    TEST_P(IndexedPointsTestUByte, VertexWithColorUnsignedByteOffset3)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(3, true);
    }
    
    typedef IndexedPointsTest<GLushort, GL_UNSIGNED_SHORT> IndexedPointsTestUShort;
    
    TEST_P(IndexedPointsTestUShort, UnsignedShortOffset0)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(0);
    }
    
    TEST_P(IndexedPointsTestUShort, UnsignedShortOffset1)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(1);
    }
    
    TEST_P(IndexedPointsTestUShort, UnsignedShortOffset2)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(2);
    }
    
    TEST_P(IndexedPointsTestUShort, UnsignedShortOffset3)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(3);
    }
    
    TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset0)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(0, true);
    }
    
    TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset1)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(1, true);
    }
    
    TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset2)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(2, true);
    }
    
    TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffset3)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        runTest(3, true);
    }
    
    TEST_P(IndexedPointsTestUShort, VertexWithColorUnsignedShortOffsetChangingIndices)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
    
        // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
        ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel() && IsOpenGLES());
    
        runTest(3, true);
        runTest(1, true);
        runTest(0, true);
        runTest(2, true);
    }
    
    typedef IndexedPointsTest<GLuint, GL_UNSIGNED_INT> IndexedPointsTestUInt;
    
    TEST_P(IndexedPointsTestUInt, UnsignedIntOffset0)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(0);
    }
    
    TEST_P(IndexedPointsTestUInt, UnsignedIntOffset1)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(1);
    }
    
    TEST_P(IndexedPointsTestUInt, UnsignedIntOffset2)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(2);
    }
    
    TEST_P(IndexedPointsTestUInt, UnsignedIntOffset3)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(3);
    }
    
    TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset0)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(0, true);
    }
    
    TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset1)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(1, true);
    }
    
    TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset2)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(2, true);
    }
    
    TEST_P(IndexedPointsTestUInt, VertexWithColorUnsignedIntOffset3)
    {
        if (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_element_index_uint"))
        {
            return;
        }
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        runTest(3, true);
    }
    
    // TODO(lucferron): Diagnose and fix the UByte tests below for Vulkan.
    // http://anglebug.com/2646
    
    // TODO(geofflang): Figure out why this test fails on Intel OpenGL
    ANGLE_INSTANTIATE_TEST_ES2(IndexedPointsTestUByte);
    ANGLE_INSTANTIATE_TEST_ES2(IndexedPointsTestUShort);
    ANGLE_INSTANTIATE_TEST_ES2(IndexedPointsTestUInt);