Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2020-04-27 13:46:08
    Hash : 448b14bb
    Message : Vulkan: Apply binding size in updateBuffersDescriptorSet. Previously we would bind the full Vulkan buffer size in cases of unsized arrays in storage buffers. This then would lead to problems when binding a dynamic buffer that used sub-allocation or larger internal sizes. Instead use the GL binding size or GL buffer size as the size limits. Bug: angleproject:4380 Change-Id: Ia579bfeae3b8d068813336cbd5e1babee9f4f345 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2168020 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/tests/gl_tests/ShaderStorageBufferTest.cpp
  • //
    // Copyright 2017 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.
    //
    // ShaderStorageBufferTest:
    //   Various tests related for shader storage buffers.
    //
    
    #include "test_utils/ANGLETest.h"
    #include "test_utils/gl_raii.h"
    
    using namespace angle;
    
    namespace
    {
    
    struct MatrixCase
    {
        MatrixCase(unsigned cols,
                   unsigned rows,
                   unsigned matrixStride,
                   const char *computeShaderSource,
                   const float *inputData)
            : mColumns(cols),
              mRows(rows),
              mMatrixStride(matrixStride),
              mComputeShaderSource(computeShaderSource),
              mInputdata(inputData)
        {}
        unsigned int mColumns;
        unsigned int mRows;
        unsigned int mMatrixStride;
        const char *mComputeShaderSource;
        const float *mInputdata;
        const unsigned int kBytesPerComponent = sizeof(float);
    };
    
    struct VectorCase
    {
        VectorCase(unsigned components,
                   const char *computeShaderSource,
                   const GLuint *inputData,
                   const GLuint *expectedData)
            : mComponents(components),
              mComputeShaderSource(computeShaderSource),
              mInputdata(inputData),
              mExpectedData(expectedData)
        {}
        unsigned int mComponents;
        const char *mComputeShaderSource;
        const GLuint *mInputdata;
        const GLuint *mExpectedData;
        const unsigned int kBytesPerComponent = sizeof(GLuint);
    };
    
    class ShaderStorageBufferTest31 : public ANGLETest
    {
      protected:
        ShaderStorageBufferTest31()
        {
            setWindowWidth(128);
            setWindowHeight(128);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
    
            // Test flakiness was noticed when reusing displays.
            forceNewDisplay();
        }
    
        void runMatrixTest(const MatrixCase &matrixCase)
        {
            ANGLE_GL_COMPUTE_PROGRAM(program, matrixCase.mComputeShaderSource);
            glUseProgram(program);
    
            // Create shader storage buffer
            GLBuffer shaderStorageBuffer[2];
            glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
            glBufferData(GL_SHADER_STORAGE_BUFFER, matrixCase.mRows * matrixCase.mMatrixStride,
                         matrixCase.mInputdata, GL_STATIC_DRAW);
            glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
            glBufferData(GL_SHADER_STORAGE_BUFFER, matrixCase.mRows * matrixCase.mMatrixStride, nullptr,
                         GL_STATIC_DRAW);
    
            // Bind shader storage buffer
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
            glDispatchCompute(1, 1, 1);
            glFinish();
    
            // Read back shader storage buffer
            glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
            const GLfloat *ptr = reinterpret_cast<const GLfloat *>(
                glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0,
                                 matrixCase.mRows * matrixCase.mMatrixStride, GL_MAP_READ_BIT));
    
            for (unsigned int row = 0; row < matrixCase.mRows; row++)
            {
                for (unsigned int col = 0; col < matrixCase.mColumns; col++)
                {
                    GLfloat expected = matrixCase.mInputdata[row * (matrixCase.mMatrixStride /
                                                                    matrixCase.kBytesPerComponent) +
                                                             col];
                    GLfloat actual =
                        *(ptr + row * (matrixCase.mMatrixStride / matrixCase.kBytesPerComponent) + col);
    
                    EXPECT_EQ(expected, actual) << " at row " << row << " and column " << col;
                }
            }
    
            EXPECT_GL_NO_ERROR();
        }
    
        void runVectorTest(const VectorCase &vectorCase)
        {
            ANGLE_GL_COMPUTE_PROGRAM(program, vectorCase.mComputeShaderSource);
            glUseProgram(program);
    
            // Create shader storage buffer
            GLBuffer shaderStorageBuffer[2];
            glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
            glBufferData(GL_SHADER_STORAGE_BUFFER,
                         vectorCase.mComponents * vectorCase.kBytesPerComponent, vectorCase.mInputdata,
                         GL_STATIC_DRAW);
            glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
            glBufferData(GL_SHADER_STORAGE_BUFFER,
                         vectorCase.mComponents * vectorCase.kBytesPerComponent, nullptr,
                         GL_STATIC_DRAW);
    
            // Bind shader storage buffer
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
            glDispatchCompute(1, 1, 1);
            glFinish();
    
            // Read back shader storage buffer
            glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
            const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
                GL_SHADER_STORAGE_BUFFER, 0, vectorCase.mComponents * vectorCase.kBytesPerComponent,
                GL_MAP_READ_BIT));
            for (unsigned int idx = 0; idx < vectorCase.mComponents; idx++)
            {
                EXPECT_EQ(vectorCase.mExpectedData[idx], *(ptr + idx));
            }
    
            EXPECT_GL_NO_ERROR();
        }
    };
    
    // Matched block names within a shader interface must match in terms of having the same number of
    // declarations with the same sequence of types.
    TEST_P(ShaderStorageBufferTest31, MatchedBlockNameWithDifferentMemberType)
    {
        constexpr char kVS[] =
            "#version 310 es\n"
            "buffer blockName {\n"
            "    float data;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        constexpr char kFS[] =
            "#version 310 es\n"
            "buffer blockName {\n"
            "    uint data;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
    
        GLuint program = CompileProgram(kVS, kFS);
        EXPECT_EQ(0u, program);
    }
    
    // Linking should fail if blocks in vertex shader exceed GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS.
    TEST_P(ShaderStorageBufferTest31, ExceedMaxVertexShaderStorageBlocks)
    {
        std::ostringstream instanceCount;
        GLint maxVertexShaderStorageBlocks = 0;
        glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertexShaderStorageBlocks);
        EXPECT_GL_NO_ERROR();
        instanceCount << maxVertexShaderStorageBlocks;
    
        const std::string &vertexShaderSource =
            "#version 310 es\n"
            "layout(shared) buffer blockName {\n"
            "    uint data;\n"
            "} instance[" +
            instanceCount.str() +
            " + 1];\n"
            "void main()\n"
            "{\n"
            "}\n";
        constexpr char kFS[] =
            "#version 310 es\n"
            "void main()\n"
            "{\n"
            "}\n";
    
        GLuint program = CompileProgram(vertexShaderSource.c_str(), kFS);
        EXPECT_EQ(0u, program);
    }
    
    // Linking should fail if the sum of the number of active shader storage blocks exceeds
    // MAX_COMBINED_SHADER_STORAGE_BLOCKS.
    TEST_P(ShaderStorageBufferTest31, ExceedMaxCombinedShaderStorageBlocks)
    {
        std::ostringstream vertexInstanceCount;
        GLint maxVertexShaderStorageBlocks = 0;
        glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertexShaderStorageBlocks);
        vertexInstanceCount << maxVertexShaderStorageBlocks;
    
        GLint maxFragmentShaderStorageBlocks = 0;
        glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
    
        GLint maxCombinedShaderStorageBlocks = 0;
        glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxCombinedShaderStorageBlocks);
        EXPECT_GL_NO_ERROR();
    
        ASSERT_GE(maxCombinedShaderStorageBlocks, maxVertexShaderStorageBlocks);
        ASSERT_GE(maxCombinedShaderStorageBlocks, maxFragmentShaderStorageBlocks);
    
        // As SPEC allows MAX_VERTEX_SHADER_STORAGE_BLOCKS and MAX_FRAGMENT_SHADER_STORAGE_BLOCKS to be
        // 0, in this situation we should skip this test to prevent these unexpected compile errors.
        ANGLE_SKIP_TEST_IF(maxVertexShaderStorageBlocks == 0 || maxFragmentShaderStorageBlocks == 0);
    
        GLint fragmentShaderStorageBlocks =
            maxCombinedShaderStorageBlocks - maxVertexShaderStorageBlocks + 1;
        ANGLE_SKIP_TEST_IF(fragmentShaderStorageBlocks > maxFragmentShaderStorageBlocks);
    
        std::ostringstream fragmentInstanceCount;
        fragmentInstanceCount << fragmentShaderStorageBlocks;
    
        const std::string &vertexShaderSource =
            "#version 310 es\n"
            "layout(shared) buffer blockName0 {\n"
            "    uint data;\n"
            "} instance0[" +
            vertexInstanceCount.str() +
            "];\n"
            "void main()\n"
            "{\n"
            "}\n";
        const std::string &fragmentShaderSource =
            "#version 310 es\n"
            "layout(shared) buffer blockName1 {\n"
            "    uint data;\n"
            "} instance1[" +
            fragmentInstanceCount.str() +
            "];\n"
            "void main()\n"
            "{\n"
            "}\n";
    
        GLuint program = CompileProgram(vertexShaderSource.c_str(), fragmentShaderSource.c_str());
        EXPECT_EQ(0u, program);
    }
    
    // Test shader storage buffer read write.
    TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWrite)
    {
        constexpr char kCS[] =
            "#version 310 es\n"
            "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
            "layout(std140, binding = 1) buffer blockName {\n"
            "    uint data[2];\n"
            "} instanceName;\n"
            "void main()\n"
            "{\n"
            "    instanceName.data[0] = 3u;\n"
            "    instanceName.data[1] = 4u;\n"
            "}\n";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
    
        glUseProgram(program.get());
    
        constexpr unsigned int kElementCount = 2;
        // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
        constexpr unsigned int kArrayStride = 16;
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer;
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kElementCount * kArrayStride, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer);
    
        // Dispath compute
        glDispatchCompute(1, 1, 1);
    
        glFinish();
    
        // Read back shader storage buffer
        constexpr unsigned int kExpectedValues[2] = {3u, 4u};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        void *ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kElementCount * kArrayStride,
                                     GL_MAP_READ_BIT);
        for (unsigned int idx = 0; idx < kElementCount; idx++)
        {
            EXPECT_EQ(kExpectedValues[idx],
                      *(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
                                                         idx * kArrayStride)));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Tests modifying an existing shader storage buffer
    TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteSame)
    {
        // Missing PBO support in Vulkan.  http://anglebug.com/3210
        ANGLE_SKIP_TEST_IF(IsVulkan());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer block {
        uint data;
    } instance;
    void main()
    {
        uint temp = instance.data;
        instance.data = temp + 1u;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
    
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
        constexpr unsigned int kInitialData       = 123u;
    
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer;
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInitialData, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer);
    
        glDispatchCompute(1, 1, 1);
    
        glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        const void *bufferData =
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, GL_MAP_READ_BIT);
    
        constexpr unsigned int kExpectedData = 124u;
        EXPECT_EQ(kExpectedData, *static_cast<const GLuint *>(bufferData));
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    
        // Running shader twice to make sure that the buffer gets updated correctly 123->124->125
        glDispatchCompute(1, 1, 1);
    
        glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT);
    
        bufferData = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, GL_MAP_READ_BIT);
    
        constexpr unsigned int kExpectedData2 = 125u;
        EXPECT_EQ(kExpectedData2, *static_cast<const GLuint *>(bufferData));
    
        // Verify re-using the SSBO buffer with a PBO contains expected data.
        // This will read-back from FBO using a PBO into the same SSBO buffer.
    
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    
        GLTexture texture;
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
    
        GLFramebuffer framebuffer;
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        glBindBuffer(GL_PIXEL_PACK_BUFFER, shaderStorageBuffer);
        glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 0);
        EXPECT_GL_NO_ERROR();
    
        void *mappedPtr =
            glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, kBytesPerComponent, GL_MAP_READ_BIT);
        GLColor *dataColor = static_cast<GLColor *>(mappedPtr);
        EXPECT_GL_NO_ERROR();
    
        EXPECT_EQ(GLColor::red, dataColor[0]);
        glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
        EXPECT_GL_NO_ERROR();
    
        // Verify that binding the buffer back to the SSBO keeps the expected data.
    
        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        const GLColor *ptr = reinterpret_cast<GLColor *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, GL_MAP_READ_BIT));
        EXPECT_EQ(GLColor::red, *ptr);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Tests reading and writing to a shader storage buffer bound at an offset.
    TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteOffset)
    {
        // http://anglebug.com/4092
        ANGLE_SKIP_TEST_IF(isSwiftshader());
        constexpr char kCS[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    
    layout(std140, binding = 0) buffer block0 {
        uint data[2];
    } instance0;
    
    void main()
    {
        instance0.data[0] = 3u;
        instance0.data[1] = 4u;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
    
        glUseProgram(program);
    
        constexpr unsigned int kElementCount = 2;
        // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
        constexpr unsigned int kArrayStride = 16;
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer;
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
    
        int bufferAlignOffset;
        glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &bufferAlignOffset);
    
        constexpr int kBufferSize = kElementCount * kArrayStride;
        const int unalignedBytes  = kBufferSize % bufferAlignOffset;
        const int alignCorrection = unalignedBytes == 0 ? 0 : bufferAlignOffset - unalignedBytes;
        const int kBufferOffset   = kBufferSize + alignCorrection;
    
        glBufferData(GL_SHADER_STORAGE_BUFFER, kBufferOffset + kBufferSize, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer at an offset
        glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer, kBufferOffset, kBufferSize);
        EXPECT_GL_NO_ERROR();
    
        glDispatchCompute(1, 1, 1);
        glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
    
        // Bind the buffer at a separate location
        glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer, 0, kBufferSize);
        EXPECT_GL_NO_ERROR();
    
        glDispatchCompute(1, 1, 1);
        glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
    
        // Read back shader storage buffer
        constexpr unsigned int kExpectedValues[2] = {3u, 4u};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        void *ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT);
        for (unsigned int idx = 0; idx < kElementCount; idx++)
        {
            EXPECT_EQ(kExpectedValues[idx],
                      *(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
                                                         idx * kArrayStride)));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    
        ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, kBufferOffset, kBufferSize, GL_MAP_READ_BIT);
        for (unsigned int idx = 0; idx < kElementCount; idx++)
        {
            EXPECT_EQ(kExpectedValues[idx],
                      *(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
                                                         idx * kArrayStride)));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that access/write to vector data in shader storage buffer.
    TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferVector)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std140, binding = 0) buffer blockIn {
         uvec2 data;
     } instanceIn;
     layout(std140, binding = 1) buffer blockOut {
         uvec2 data;
     } instanceOut;
     void main()
     {
         instanceOut.data[0] = instanceIn.data[0];
         instanceOut.data[1] = instanceIn.data[1];
     }
     )";
    
        constexpr unsigned int kComponentCount         = 2;
        constexpr GLuint kInputValues[kComponentCount] = {3u, 4u};
    
        VectorCase vectorCase(kComponentCount, kComputeShaderSource, kInputValues, kInputValues);
        runVectorTest(vectorCase);
    }
    
    // Test that the shader works well with an active SSBO but not statically used.
    TEST_P(ShaderStorageBufferTest31, ActiveSSBOButNotStaticallyUsed)
    {
        // http://anglebug.com/3725
        ANGLE_SKIP_TEST_IF(IsAndroid() && IsPixel2() && IsVulkan());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std140, binding = 0) buffer blockIn {
         uvec2 data;
     } instanceIn;
     layout(std140, binding = 1) buffer blockOut {
         uvec2 data;
     } instanceOut;
     layout(std140, binding = 2) buffer blockC {
         uvec2 data;
     } instanceC;
     void main()
     {
         instanceOut.data[0] = instanceIn.data[0];
         instanceOut.data[1] = instanceIn.data[1];
     }
     )";
    
        GLBuffer shaderStorageBufferC;
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBufferC);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 32, nullptr, GL_STATIC_DRAW);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, shaderStorageBufferC);
    
        constexpr unsigned int kComponentCount         = 2;
        constexpr GLuint kInputValues[kComponentCount] = {3u, 4u};
    
        VectorCase vectorCase(kComponentCount, kComputeShaderSource, kInputValues, kInputValues);
        runVectorTest(vectorCase);
    }
    
    // Test that access/write to swizzle scalar data in shader storage block.
    TEST_P(ShaderStorageBufferTest31, ScalarSwizzleTest)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std140, binding = 0) buffer blockIn {
         uvec2 data;
     } instanceIn;
     layout(std140, binding = 1) buffer blockOut {
         uvec2 data;
     } instanceOut;
     void main()
     {
         instanceOut.data.x = instanceIn.data.y;
         instanceOut.data.y = instanceIn.data.x;
     }
     )";
    
        constexpr unsigned int kComponentCount            = 2;
        constexpr GLuint kInputValues[kComponentCount]    = {3u, 4u};
        constexpr GLuint kExpectedValues[kComponentCount] = {4u, 3u};
    
        VectorCase vectorCase(kComponentCount, kComputeShaderSource, kInputValues, kExpectedValues);
        runVectorTest(vectorCase);
    }
    
    // Test that access/write to swizzle vector data in shader storage block.
    TEST_P(ShaderStorageBufferTest31, VectorSwizzleTest)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std140, binding = 0) buffer blockIn {
         uvec2 data;
     } instanceIn;
     layout(std140, binding = 1) buffer blockOut {
         uvec2 data;
     } instanceOut;
     void main()
     {
         instanceOut.data.yx = instanceIn.data.xy;
     }
     )";
    
        constexpr unsigned int kComponentCount            = 2;
        constexpr GLuint kInputValues[kComponentCount]    = {3u, 4u};
        constexpr GLuint kExpectedValues[kComponentCount] = {4u, 3u};
    
        VectorCase vectorCase(kComponentCount, kComputeShaderSource, kInputValues, kExpectedValues);
        runVectorTest(vectorCase);
    }
    
    // Test that access/write to swizzle vector data in column_major matrix in shader storage block.
    TEST_P(ShaderStorageBufferTest31, VectorSwizzleInColumnMajorMatrixTest)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std140, binding = 0) buffer blockIn {
         layout(column_major) mat2x3 data;
     } instanceIn;
     layout(std140, binding = 1) buffer blockOut {
         layout(column_major) mat2x3 data;
     } instanceOut;
     void main()
     {
         instanceOut.data[0].xyz = instanceIn.data[0].xyz;
         instanceOut.data[1].xyz = instanceIn.data[1].xyz;
     }
     )";
    
        constexpr unsigned int kColumns                                             = 2;
        constexpr unsigned int kRows                                                = 3;
        constexpr unsigned int kBytesPerComponent                                   = sizeof(float);
        constexpr unsigned int kMatrixStride                                        = 16;
        constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
        MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    // Test that access/write to swizzle vector data in row_major matrix in shader storage block.
    TEST_P(ShaderStorageBufferTest31, VectorSwizzleInRowMajorMatrixTest)
    {
        ANGLE_SKIP_TEST_IF(IsAndroid());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std140, binding = 0) buffer blockIn {
         layout(row_major) mat2x3 data;
     } instanceIn;
     layout(std140, binding = 1) buffer blockOut {
         layout(row_major) mat2x3 data;
     } instanceOut;
     void main()
     {
         instanceOut.data[0].xyz = instanceIn.data[0].xyz;
         instanceOut.data[1].xyz = instanceIn.data[1].xyz;
     }
     )";
    
        constexpr unsigned int kColumns           = 2;
        constexpr unsigned int kRows              = 3;
        constexpr unsigned int kBytesPerComponent = sizeof(float);
        // std140 layout requires that base alignment and stride of arrays of scalars and vectors are
        // rounded up a multiple of the base alignment of a vec4.
        constexpr unsigned int kMatrixStride                                     = 16;
        constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
        MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    // Test that access/write to scalar data in matrix in shader storage block with row major.
    TEST_P(ShaderStorageBufferTest31, ScalarDataInMatrixInSSBOWithRowMajorQualifier)
    {
        // TODO(jiajia.qin@intel.com): Figure out why it fails on Intel Linux platform.
        // http://anglebug.com/1951
        ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
        ANGLE_SKIP_TEST_IF(IsAndroid());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer blockIn {
        layout(row_major) mat2x3 data;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        layout(row_major) mat2x3 data;
    } instanceOut;
    void main()
    {
        instanceOut.data[0][0] = instanceIn.data[0][0];
        instanceOut.data[0][1] = instanceIn.data[0][1];
        instanceOut.data[0][2] = instanceIn.data[0][2];
        instanceOut.data[1][0] = instanceIn.data[1][0];
        instanceOut.data[1][1] = instanceIn.data[1][1];
        instanceOut.data[1][2] = instanceIn.data[1][2];
    }
    )";
    
        constexpr unsigned int kColumns           = 2;
        constexpr unsigned int kRows              = 3;
        constexpr unsigned int kBytesPerComponent = sizeof(float);
        // std140 layout requires that base alignment and stride of arrays of scalars and vectors are
        // rounded up a multiple of the base alignment of a vec4.
        constexpr unsigned int kMatrixStride                                     = 16;
        constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
        MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    TEST_P(ShaderStorageBufferTest31, VectorDataInMatrixInSSBOWithRowMajorQualifier)
    {
        ANGLE_SKIP_TEST_IF(IsAndroid());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer blockIn {
        layout(row_major) mat2x3 data;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        layout(row_major) mat2x3 data;
    } instanceOut;
    void main()
    {
        instanceOut.data[0] = instanceIn.data[0];
        instanceOut.data[1] = instanceIn.data[1];
    }
    )";
    
        constexpr unsigned int kColumns           = 2;
        constexpr unsigned int kRows              = 3;
        constexpr unsigned int kBytesPerComponent = sizeof(float);
        // std140 layout requires that base alignment and stride of arrays of scalars and vectors are
        // rounded up a multiple of the base alignment of a vec4.
        constexpr unsigned int kMatrixStride                                     = 16;
        constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
        MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    TEST_P(ShaderStorageBufferTest31, MatrixDataInSSBOWithRowMajorQualifier)
    {
        ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer blockIn {
        layout(row_major) mat2x3 data;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        layout(row_major) mat2x3 data;
    } instanceOut;
    void main()
    {
        instanceOut.data = instanceIn.data;
    }
    )";
    
        constexpr unsigned int kColumns           = 2;
        constexpr unsigned int kRows              = 3;
        constexpr unsigned int kBytesPerComponent = sizeof(float);
        // std140 layout requires that base alignment and stride of arrays of scalars and vectors are
        // rounded up a multiple of the base alignment of a vec4.
        constexpr unsigned int kMatrixStride                                     = 16;
        constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
        MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    // Test that access/write to scalar data in structure matrix in shader storage block with row major.
    TEST_P(ShaderStorageBufferTest31, ScalarDataInMatrixInStructureInSSBOWithRowMajorQualifier)
    {
        // TODO(jiajia.qin@intel.com): Figure out why it fails on Intel Linux platform.
        // http://anglebug.com/1951
        ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
        ANGLE_SKIP_TEST_IF(IsAndroid());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    struct S
    {
        mat2x3 data;
    };
    layout(std140, binding = 0) buffer blockIn {
        layout(row_major) S s;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        layout(row_major) S s;
    } instanceOut;
    void main()
    {
        instanceOut.s.data[0][0] = instanceIn.s.data[0][0];
        instanceOut.s.data[0][1] = instanceIn.s.data[0][1];
        instanceOut.s.data[0][2] = instanceIn.s.data[0][2];
        instanceOut.s.data[1][0] = instanceIn.s.data[1][0];
        instanceOut.s.data[1][1] = instanceIn.s.data[1][1];
        instanceOut.s.data[1][2] = instanceIn.s.data[1][2];
    }
    )";
    
        constexpr unsigned int kColumns           = 2;
        constexpr unsigned int kRows              = 3;
        constexpr unsigned int kBytesPerComponent = sizeof(float);
        // std140 layout requires that base alignment and stride of arrays of scalars and vectors are
        // rounded up a multiple of the base alignment of a vec4.
        constexpr unsigned int kMatrixStride                                     = 16;
        constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
        MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    // Test that access/write to column major matrix data in shader storage buffer.
    TEST_P(ShaderStorageBufferTest31, ScalarDataInMatrixInSSBO)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer blockIn {
        mat2x3 data;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        mat2x3 data;
    } instanceOut;
    void main()
    {
        instanceOut.data[0][0] = instanceIn.data[0][0];
        instanceOut.data[0][1] = instanceIn.data[0][1];
        instanceOut.data[0][2] = instanceIn.data[0][2];
        instanceOut.data[1][0] = instanceIn.data[1][0];
        instanceOut.data[1][1] = instanceIn.data[1][1];
        instanceOut.data[1][2] = instanceIn.data[1][2];
    }
    )";
    
        constexpr unsigned int kColumns                                             = 2;
        constexpr unsigned int kRows                                                = 3;
        constexpr unsigned int kBytesPerComponent                                   = sizeof(float);
        constexpr unsigned int kMatrixStride                                        = 16;
        constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
        MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    TEST_P(ShaderStorageBufferTest31, VectorDataInMatrixInSSBOWithColumnMajorQualifier)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer blockIn {
        layout(column_major) mat2x3 data;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        layout(column_major) mat2x3 data;
    } instanceOut;
    void main()
    {
        instanceOut.data[0] = instanceIn.data[0];
        instanceOut.data[1] = instanceIn.data[1];
    }
    )";
    
        constexpr unsigned int kColumns                                             = 2;
        constexpr unsigned int kRows                                                = 3;
        constexpr unsigned int kBytesPerComponent                                   = sizeof(float);
        constexpr unsigned int kMatrixStride                                        = 16;
        constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
        MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    TEST_P(ShaderStorageBufferTest31, MatrixDataInSSBOWithColumnMajorQualifier)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 0) buffer blockIn {
        layout(column_major) mat2x3 data;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        layout(column_major) mat2x3 data;
    } instanceOut;
    void main()
    {
        instanceOut.data = instanceIn.data;
    }
    )";
    
        constexpr unsigned int kColumns                                             = 2;
        constexpr unsigned int kRows                                                = 3;
        constexpr unsigned int kBytesPerComponent                                   = sizeof(float);
        constexpr unsigned int kMatrixStride                                        = 16;
        constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
            0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
        MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    // Test that access/write to structure data in shader storage buffer.
    TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferStructureArray)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    struct S
    {
        uvec2 uvData;
        uint uiData[2];
    };
    layout(std140, binding = 0) buffer blockIn {
        S s[2];
        uint lastData;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        S s[2];
        uint lastData;
    } instanceOut;
    void main()
    {
        instanceOut.s[0].uvData = instanceIn.s[0].uvData;
        instanceOut.s[0].uiData[0] = instanceIn.s[0].uiData[0];
        instanceOut.s[0].uiData[1] = instanceIn.s[0].uiData[1];
        instanceOut.s[1].uvData = instanceIn.s[1].uvData;
        instanceOut.s[1].uiData[0] = instanceIn.s[1].uiData[0];
        instanceOut.s[1].uiData[1] = instanceIn.s[1].uiData[1];
        instanceOut.lastData = instanceIn.lastData;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
    
        glUseProgram(program);
    
        std::array<GLuint, 4> kUVData = {{
            1u,
            2u,
            0u,
            0u,
        }};
        std::array<GLuint, 8> kUIData = {{
            3u,
            0u,
            0u,
            0u,
            4u,
            0u,
            0u,
            0u,
        }};
        GLuint kLastData              = 5u;
    
        constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
        constexpr unsigned int kStructureStride   = 48;
        constexpr unsigned int totalSize          = kStructureStride * 2 + sizeof(kLastData);
    
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, totalSize, nullptr, GL_STATIC_DRAW);
        GLint offset = 0;
        // upload data to instanceIn.s[0]
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUVData.size() * kBytesPerComponent,
                        kUVData.data());
        offset += (kUVData.size() * kBytesPerComponent);
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUIData.size() * kBytesPerComponent,
                        kUIData.data());
        offset += (kUIData.size() * kBytesPerComponent);
        // upload data to instanceIn.s[1]
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUVData.size() * kBytesPerComponent,
                        kUVData.data());
        offset += (kUVData.size() * kBytesPerComponent);
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUIData.size() * kBytesPerComponent,
                        kUIData.data());
        offset += (kUIData.size() * kBytesPerComponent);
        // upload data to instanceIn.lastData
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, sizeof(kLastData), &kLastData);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, totalSize, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        constexpr float kExpectedValues[5] = {1u, 2u, 3u, 4u, 5u};
        const GLuint *ptr                  = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, totalSize, GL_MAP_READ_BIT));
        // instanceOut.s[0]
        EXPECT_EQ(kExpectedValues[0], *ptr);
        EXPECT_EQ(kExpectedValues[1], *(ptr + 1));
        EXPECT_EQ(kExpectedValues[2], *(ptr + 4));
        EXPECT_EQ(kExpectedValues[3], *(ptr + 8));
        // instanceOut.s[1]
        ptr += kStructureStride / kBytesPerComponent;
        EXPECT_EQ(kExpectedValues[0], *ptr);
        EXPECT_EQ(kExpectedValues[1], *(ptr + 1));
        EXPECT_EQ(kExpectedValues[2], *(ptr + 4));
        EXPECT_EQ(kExpectedValues[3], *(ptr + 8));
        // instanceOut.lastData
        ptr += kStructureStride / kBytesPerComponent;
        EXPECT_EQ(kExpectedValues[4], *(ptr));
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that access/write to array of array structure data in shader storage buffer.
    TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferStructureArrayOfArray)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    struct S
    {
        uvec2 uvData;
        uint uiData[2];
    };
    layout(std140, binding = 0) buffer blockIn {
        S s[3][2];
        uint lastData;
    } instanceIn;
    layout(std140, binding = 1) buffer blockOut {
        S s[3][2];
        uint lastData;
    } instanceOut;
    void main()
    {
        instanceOut.s[1][0].uvData = instanceIn.s[1][0].uvData;
        instanceOut.s[1][0].uiData[0] = instanceIn.s[1][0].uiData[0];
        instanceOut.s[1][0].uiData[1] = instanceIn.s[1][0].uiData[1];
        instanceOut.s[1][1].uvData = instanceIn.s[1][1].uvData;
        instanceOut.s[1][1].uiData[0] = instanceIn.s[1][1].uiData[0];
        instanceOut.s[1][1].uiData[1] = instanceIn.s[1][1].uiData[1];
    
        instanceOut.lastData = instanceIn.lastData;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
    
        glUseProgram(program);
    
        std::array<GLuint, 4> kUVData = {{
            1u,
            2u,
            0u,
            0u,
        }};
        std::array<GLuint, 8> kUIData = {{
            3u,
            0u,
            0u,
            0u,
            4u,
            0u,
            0u,
            0u,
        }};
        GLuint kLastData              = 5u;
    
        constexpr unsigned int kBytesPerComponent        = sizeof(GLuint);
        constexpr unsigned int kStructureStride          = 48;
        constexpr unsigned int kStructureArrayDimension0 = 3;
        constexpr unsigned int kStructureArrayDimension1 = 2;
        constexpr unsigned int kLastDataOffset =
            kStructureStride * kStructureArrayDimension0 * kStructureArrayDimension1;
        constexpr unsigned int totalSize = kLastDataOffset + sizeof(kLastData);
    
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, totalSize, nullptr, GL_STATIC_DRAW);
        // offset of instanceIn.s[1][0]
        GLint offset      = kStructureStride * (kStructureArrayDimension1 * 1 + 0);
        GLuint uintOffset = offset / kBytesPerComponent;
        // upload data to instanceIn.s[1][0]
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUVData.size() * kBytesPerComponent,
                        kUVData.data());
        offset += (kUVData.size() * kBytesPerComponent);
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUIData.size() * kBytesPerComponent,
                        kUIData.data());
        offset += (kUIData.size() * kBytesPerComponent);
        // upload data to instanceIn.s[1][1]
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUVData.size() * kBytesPerComponent,
                        kUVData.data());
        offset += (kUVData.size() * kBytesPerComponent);
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kUIData.size() * kBytesPerComponent,
                        kUIData.data());
        // upload data to instanceIn.lastData
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, kLastDataOffset, sizeof(kLastData), &kLastData);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, totalSize, nullptr, GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        constexpr float kExpectedValues[5] = {1u, 2u, 3u, 4u, 5u};
        const GLuint *ptr                  = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, totalSize, GL_MAP_READ_BIT));
    
        // instanceOut.s[0][0]
        EXPECT_EQ(kExpectedValues[0], *(ptr + uintOffset));
        EXPECT_EQ(kExpectedValues[1], *(ptr + uintOffset + 1));
        EXPECT_EQ(kExpectedValues[2], *(ptr + uintOffset + 4));
        EXPECT_EQ(kExpectedValues[3], *(ptr + uintOffset + 8));
    
        // instanceOut.s[0][1]
        EXPECT_EQ(kExpectedValues[0], *(ptr + uintOffset + 12));
        EXPECT_EQ(kExpectedValues[1], *(ptr + uintOffset + 13));
        EXPECT_EQ(kExpectedValues[2], *(ptr + uintOffset + 16));
        EXPECT_EQ(kExpectedValues[3], *(ptr + uintOffset + 20));
    
        // instanceOut.lastData
        EXPECT_EQ(kExpectedValues[4], *(ptr + (kLastDataOffset / kBytesPerComponent)));
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that access/write to vector data in std430 shader storage block.
    TEST_P(ShaderStorageBufferTest31, VectorArrayInSSBOWithStd430Qualifier)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std430, binding = 0) buffer blockIn {
        uvec2 data[2];
    } instanceIn;
    layout(std430, binding = 1) buffer blockOut {
        uvec2 data[2];
    } instanceOut;
    void main()
    {
        instanceOut.data[0] = instanceIn.data[0];
        instanceOut.data[1] = instanceIn.data[1];
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
    
        glUseProgram(program);
    
        constexpr unsigned int kElementCount      = 2;
        constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
        constexpr unsigned int kArrayStride       = 8;
        constexpr unsigned int kComponentCount    = kArrayStride / kBytesPerComponent;
        constexpr unsigned int kExpectedValues[kElementCount][kComponentCount] = {{1u, 2u}, {3u, 4u}};
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kElementCount * kArrayStride, kExpectedValues,
                     GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kElementCount * kArrayStride, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
    
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
            GL_SHADER_STORAGE_BUFFER, 0, kElementCount * kArrayStride, GL_MAP_READ_BIT));
        for (unsigned int idx = 0; idx < kElementCount; idx++)
        {
            for (unsigned int idy = 0; idy < kComponentCount; idy++)
            {
                EXPECT_EQ(kExpectedValues[idx][idy], *(ptr + idx * kComponentCount + idy));
            }
        }
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that access/write to matrix data in std430 shader storage block.
    TEST_P(ShaderStorageBufferTest31, MatrixInSSBOWithStd430Qualifier)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std430, binding = 0) buffer blockIn {
        mat2 data;
    } instanceIn;
    layout(std430, binding = 1) buffer blockOut {
        mat2 data;
    } instanceOut;
    void main()
    {
        instanceOut.data = instanceIn.data;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
    
        glUseProgram(program);
    
        constexpr unsigned int kColumns              = 2;
        constexpr unsigned int kRows                 = 2;
        constexpr unsigned int kBytesPerComponent    = sizeof(float);
        constexpr unsigned int kMatrixStride         = kRows * kBytesPerComponent;
        constexpr float kInputDada[kColumns * kRows] = {0.1, 0.2, 0.4, 0.5};
        MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
        runMatrixTest(matrixCase);
    }
    
    // Test that access/write to structure data in std430 shader storage block.
    TEST_P(ShaderStorageBufferTest31, StructureInSSBOWithStd430Qualifier)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    struct S
    {
        uvec2 u;
    };
    layout(std430, binding = 0) buffer blockIn {
        uint i1;
        S s;
        uint i2;
    } instanceIn;
    layout(std430, binding = 1) buffer blockOut {
        uint i1;
        S s;
        uint i2;
    } instanceOut;
    void main()
    {
        instanceOut.i1 = instanceIn.i1;
        instanceOut.s.u = instanceIn.s.u;
        instanceOut.i2 = instanceIn.i2;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        GLuint kI1Data               = 1u;
        std::array<GLuint, 2> kUData = {{
            2u,
            3u,
        }};
        GLuint kI2Data               = 4u;
    
        constexpr unsigned int kBytesPerComponent    = sizeof(GLuint);
        constexpr unsigned int kStructureStartOffset = 8;
        constexpr unsigned int kStructureSize        = 8;
        constexpr unsigned int kTotalSize = kStructureStartOffset + kStructureSize + kBytesPerComponent;
    
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
        // upload data to instanceIn.i1
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, &kI1Data);
        // upload data to instanceIn.s.u
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureStartOffset, kStructureSize, kUData.data());
        // upload data to instanceIn.i2
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureStartOffset + kStructureSize,
                        kBytesPerComponent, &kI2Data);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        GLuint kExpectedValues[4] = {1u, 2u, 3u, 4u};
        const GLuint *ptr         = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kTotalSize, GL_MAP_READ_BIT));
        EXPECT_EQ(kExpectedValues[0], *ptr);
        ptr += (kStructureStartOffset / kBytesPerComponent);
        EXPECT_EQ(kExpectedValues[1], *ptr);
        EXPECT_EQ(kExpectedValues[2], *(ptr + 1));
        ptr += (kStructureSize / kBytesPerComponent);
        EXPECT_EQ(kExpectedValues[3], *ptr);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that access/write to structure of structure data in std430 shader storage block.
    TEST_P(ShaderStorageBufferTest31, StructureOfStructureInSSBOWithStd430Qualifier)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    struct S2
    {
        uvec3 u2;
    };
    struct S1
    {
        uvec2 u1;
        S2 s2;
    };
    layout(std430, binding = 0) buffer blockIn {
        uint i1;
        S1 s1;
        uint i2;
    } instanceIn;
    layout(std430, binding = 1) buffer blockOut {
        uint i1;
        S1 s1;
        uint i2;
    } instanceOut;
    void main()
    {
        instanceOut.i1 = instanceIn.i1;
        instanceOut.s1.u1 = instanceIn.s1.u1;
        instanceOut.s1.s2.u2 = instanceIn.s1.s2.u2;
        instanceOut.i2 = instanceIn.i2;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent      = sizeof(GLuint);
        constexpr unsigned int kStructureS1StartOffset = 16;
        constexpr unsigned int kStructureS2StartOffset = 32;
        constexpr unsigned int kStructureS1Size        = 32;
        constexpr unsigned int kTotalSize =
            kStructureS1StartOffset + kStructureS1Size + kBytesPerComponent;
    
        GLuint kI1Data                = 1u;
        std::array<GLuint, 2> kU1Data = {{2u, 3u}};
        std::array<GLuint, 3> kU2Data = {{4u, 5u, 6u}};
        GLuint kI2Data                = 7u;
    
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
        // upload data to instanceIn.i1
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, &kI1Data);
        // upload data to instanceIn.s1.u1
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureS1StartOffset,
                        kU1Data.size() * kBytesPerComponent, kU1Data.data());
        // upload data to instanceIn.s1.s2.u2
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureS2StartOffset,
                        kU2Data.size() * kBytesPerComponent, kU2Data.data());
        // upload data to instanceIn.i2
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureS1StartOffset + kStructureS1Size,
                        kBytesPerComponent, &kI2Data);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        GLuint kExpectedValues[7] = {1u, 2u, 3u, 4u, 5u, 6u, 7u};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kTotalSize, GL_MAP_READ_BIT));
        EXPECT_EQ(kExpectedValues[0], *ptr);
        ptr += (kStructureS1StartOffset / kBytesPerComponent);
        EXPECT_EQ(kExpectedValues[1], *ptr);
        EXPECT_EQ(kExpectedValues[2], *(ptr + 1));
        ptr += ((kStructureS2StartOffset - kStructureS1StartOffset) / kBytesPerComponent);
        EXPECT_EQ(kExpectedValues[3], *ptr);
        EXPECT_EQ(kExpectedValues[4], *(ptr + 1));
        EXPECT_EQ(kExpectedValues[5], *(ptr + 2));
        ptr += ((kStructureS1Size - kStructureS2StartOffset) / kBytesPerComponent);
        EXPECT_EQ(kExpectedValues[6], *(ptr + 4));
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test atomic memory functions.
    TEST_P(ShaderStorageBufferTest31, AtomicMemoryFunctions)
    {
        constexpr char kCS[] = R"(#version 310 es
    layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
    layout(std140, binding = 1) buffer blockName {
        uint data[2];
    } instanceName;
    
    void main()
    {
        instanceName.data[0] = 0u;
        instanceName.data[1] = 0u;
        atomicAdd(instanceName.data[0], 5u);
        atomicMax(instanceName.data[1], 7u);
    })";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
    
        glUseProgram(program.get());
    
        constexpr unsigned int kElementCount = 2;
        // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
        constexpr unsigned int kArrayStride = 16;
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer;
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kElementCount * kArrayStride, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer);
    
        // Dispath compute
        glDispatchCompute(1, 1, 1);
    
        glFinish();
    
        // Read back shader storage buffer
        constexpr unsigned int kExpectedValues[2] = {5u, 7u};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        void *ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kElementCount * kArrayStride,
                                     GL_MAP_READ_BIT);
        for (unsigned int idx = 0; idx < kElementCount; idx++)
        {
            EXPECT_EQ(kExpectedValues[idx],
                      *(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
                                                         idx * kArrayStride)));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test multiple storage buffers work correctly when program switching. In angle, storage buffer
    // bindings are updated accord to current program. If switch program, need to update storage buffer
    // bindings again.
    TEST_P(ShaderStorageBufferTest31, MultiStorageBuffersForMultiPrograms)
    {
        constexpr char kCS1[] = R"(#version 310 es
    layout(local_size_x=3, local_size_y=1, local_size_z=1) in;
    layout(binding = 1) buffer Output {
        uint result1[];
    } sb_out1;
    void main()
    {
        highp uint offset = gl_LocalInvocationID.x;
        sb_out1.result1[gl_LocalInvocationIndex] = gl_LocalInvocationIndex + 1u;
    })";
    
        constexpr char kCS2[] = R"(#version 310 es
    layout(local_size_x=3, local_size_y=1, local_size_z=1) in;
    layout(binding = 2) buffer Output {
        uint result2[];
    } sb_out2;
    void main()
    {
        highp uint offset = gl_LocalInvocationID.x;
        sb_out2.result2[gl_LocalInvocationIndex] = gl_LocalInvocationIndex + 2u;
    })";
    
        constexpr unsigned int numInvocations = 3;
        int arrayStride1 = 0, arrayStride2 = 0;
        GLenum props[] = {GL_ARRAY_STRIDE};
        GLBuffer shaderStorageBuffer1, shaderStorageBuffer2;
    
        ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
        ANGLE_GL_COMPUTE_PROGRAM(program2, kCS2);
        EXPECT_GL_NO_ERROR();
    
        unsigned int outVarIndex1 =
            glGetProgramResourceIndex(program1.get(), GL_BUFFER_VARIABLE, "Output.result1");
        glGetProgramResourceiv(program1.get(), GL_BUFFER_VARIABLE, outVarIndex1, 1, props, 1, 0,
                               &arrayStride1);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer1);
        glBufferData(GL_SHADER_STORAGE_BUFFER, numInvocations * arrayStride1, nullptr, GL_STREAM_READ);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer1);
        EXPECT_GL_NO_ERROR();
    
        unsigned int outVarIndex2 =
            glGetProgramResourceIndex(program2.get(), GL_BUFFER_VARIABLE, "Output.result2");
        glGetProgramResourceiv(program2.get(), GL_BUFFER_VARIABLE, outVarIndex2, 1, props, 1, 0,
                               &arrayStride2);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer2);
        glBufferData(GL_SHADER_STORAGE_BUFFER, numInvocations * arrayStride2, nullptr, GL_STREAM_READ);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, shaderStorageBuffer2);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program1.get());
        glDispatchCompute(1, 1, 1);
        EXPECT_GL_NO_ERROR();
        glUseProgram(program2.get());
        glDispatchCompute(1, 1, 1);
        EXPECT_GL_NO_ERROR();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer1);
        const void *ptr1 =
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * arrayStride1, GL_MAP_READ_BIT);
        for (unsigned int idx = 0; idx < numInvocations; idx++)
        {
            EXPECT_EQ(idx + 1, *((const GLuint *)((const GLbyte *)ptr1 + idx * arrayStride1)));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
        EXPECT_GL_NO_ERROR();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer2);
        const void *ptr2 =
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * arrayStride2, GL_MAP_READ_BIT);
        EXPECT_GL_NO_ERROR();
        for (unsigned int idx = 0; idx < numInvocations; idx++)
        {
            EXPECT_EQ(idx + 2, *((const GLuint *)((const GLbyte *)ptr2 + idx * arrayStride2)));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
        EXPECT_GL_NO_ERROR();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that function calling is supported in SSBO access chain.
    TEST_P(ShaderStorageBufferTest31, FunctionCallInSSBOAccessChain)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=4) in;
    highp uint getIndex (in highp uvec2 localID, uint element)
    {
        return localID.x + element;
    }
    layout(binding=0, std430) buffer Storage
    {
        highp uint values[];
    } sb_store;
    
    void main()
    {
        sb_store.values[getIndex(gl_LocalInvocationID.xy, 0u)] = gl_LocalInvocationIndex;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that unary operator is supported in SSBO access chain.
    TEST_P(ShaderStorageBufferTest31, UnaryOperatorInSSBOAccessChain)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=4) in;
    layout(binding=0, std430) buffer Storage
    {
        highp uint values[];
    } sb_store;
    
    void main()
    {
        uint invocationNdx = gl_LocalInvocationIndex;
        sb_store.values[++invocationNdx] = invocationNdx;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that ternary operator is supported in SSBO access chain.
    TEST_P(ShaderStorageBufferTest31, TernaryOperatorInSSBOAccessChain)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=4) in;
    layout(binding=0, std430) buffer Storage
    {
        highp uint values[];
    } sb_store;
    
    void main()
    {
        sb_store.values[gl_LocalInvocationIndex > 2u ? gl_NumWorkGroups.x : gl_NumWorkGroups.y]
                = gl_LocalInvocationIndex;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    }
    
    // Tests that alignment is correct for bools inside a SSB and that the values
    // are written correctly by a trivial shader. Currently tests only the alignment
    // of the initial block.
    TEST_P(ShaderStorageBufferTest31, LoadAndStoreBooleanValue)
    {
        // TODO(jiajia.qin@intel.com): Figure out why it fails on Intel Linux platform.
        // http://anglebug.com/1951
        ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
    
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage0
    {
        bool b1;
        bool b2;
        bool b3;
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        bool b1;
        bool b2;
        bool b3;
    } sb_store;
    void main()
    {
       sb_store.b1 = sb_load.b1;
       sb_store.b2 = sb_load.b2;
       sb_store.b3 = sb_load.b3;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program);
    
        constexpr GLuint kB1Value                 = 1u;
        constexpr GLuint kB2Value[2]              = {0u, 1u};
        constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
        GLint offset = 0;
        // upload data to sb_load.b1
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kBytesPerComponent, &kB1Value);
        offset += kBytesPerComponent;
        // upload data to sb_load.b2
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, 2 * kBytesPerComponent, kB2Value);
    
        constexpr GLuint kStoreBufferContents[3] = {0x1BCD1234, 0x2BCD1234, 0x3BCD1234};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, kStoreBufferContents,
                     GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * kBytesPerComponent, GL_MAP_READ_BIT));
        EXPECT_EQ(kB1Value, ptr[0]);
        EXPECT_EQ(kB2Value[0], ptr[1]);
        EXPECT_EQ(kB2Value[1], ptr[2]);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Tests that alignment is correct for bvecs3 inside a SSB and that the
    // values are written correctly by a trivial shader. Currently tests only the
    // alignment of the initial block.
    TEST_P(ShaderStorageBufferTest31, LoadAndStoreBooleanVec3)
    {
        // TODO(jiajia.qin@intel.com): Figure out why it fails on Intel Linux platform.
        // http://anglebug.com/1951
        ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
    
        ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
    
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage0
    {
        bvec3 b;
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        bvec3 b;
    } sb_store;
    void main()
    {
       sb_store.b = sb_load.b;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program);
    
        constexpr GLuint kBValues[3]              = {1u, 0u, 1u};
        constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, 3 * kBytesPerComponent, &kBValues);
    
        constexpr GLuint kStoreBufferContents[3] = {0x1BCD1234, 0x2BCD1234, 0x3BCD1234};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, kStoreBufferContents,
                     GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * kBytesPerComponent, GL_MAP_READ_BIT));
        EXPECT_EQ(kBValues[0], ptr[0]);
        EXPECT_EQ(kBValues[1], ptr[1]);
        EXPECT_EQ(kBValues[2], ptr[2]);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Tests that alignment is correct for bool + bvecs2 inside a SSB and that the
    // values are written correctly by a trivial shader. Currently tests only the
    // alignment of the initial block. Compare to LoadAndStoreBooleanVec3 to see how
    // the alignment rules affect the memory layout.
    TEST_P(ShaderStorageBufferTest31, LoadAndStoreBooleanVarAndVec2)
    {
        // TODO(jiajia.qin@intel.com): Figure out why it fails on Intel Linux platform.
        // http://anglebug.com/1951
        ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
    
        ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
    
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage0
    {
        bool b1;
        bvec2 b2;
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        bool b1;
        bvec2 b2;
    } sb_store;
    void main()
    {
       sb_store.b1 = sb_load.b1;
       sb_store.b2 = sb_load.b2;
    }
    )";
        // https://www.khronos.org/registry/OpenGL/specs/es/3.1/es_spec_3.1.pdf
        // 7.6.2.2 Standard Uniform Block Layout
    
        // ... A structure and each structure member have a base offset and a base
        // alignment, from which an aligned offset is computed by rounding the base
        // offset up to a multiple of the base alignment. The base offset of the
        // first member of a structure is taken from the aligned offset of the
        // structure itself. ... The members of a toplevel uniform block are laid
        // out in buffer storage by treating the uniform block as a structure with a
        // base offset of zero.
    
        // 1. If the member is a scalar consuming N basic machine units, the base
        // alignment is N.
    
        // 2. If the member is a two- or four-component vector with components
        // consuming N basic machine units, the base alignment is 2N or 4N,
        // respectively
    
        // b1 N == 4, basic offset 0, alignment 4, is at 0..3
        // b2 N == 4, basic offset 4, alignment 2*4 = 8, is at 8..16.
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program);
        constexpr GLuint kAlignPadding  = 0x1abcd789u;
        constexpr GLuint kBValues[]     = {1u, kAlignPadding, 0u, 1u};
        constexpr unsigned int kSsbSize = sizeof(kBValues);
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kSsbSize, nullptr, GL_STATIC_DRAW);
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kSsbSize, &kBValues);
    
        constexpr GLuint kStoreBufferContents[4] = {0x1BCD1234, 0x2BCD1234, 0x3BCD1234, 0x3BCD1277};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kSsbSize, kStoreBufferContents, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSsbSize, GL_MAP_READ_BIT));
        EXPECT_EQ(kBValues[0], ptr[0]);
        // Index 1 is padding.
        EXPECT_EQ(kBValues[2], ptr[2]);
        EXPECT_EQ(kBValues[3], ptr[3]);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that non-structure array of arrays is supported in SSBO.
    TEST_P(ShaderStorageBufferTest31, SimpleArrayOfArrays)
    {
        constexpr char kComputeShaderSource[] = R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage0
    {
        uint a[2][2][2];
        uint b;
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        uint a[2][2][2];
        uint b;
    } sb_store;
    void main()
    {
       sb_store.a[0][0][0] = sb_load.a[0][0][0];
       sb_store.a[0][0][1] = sb_load.a[0][0][1];
       sb_store.a[0][1][0] = sb_load.a[0][1][0];
       sb_store.a[0][1][1] = sb_load.a[0][1][1];
       sb_store.a[1][0][0] = sb_load.a[1][0][0];
       sb_store.a[1][0][1] = sb_load.a[1][0][1];
       sb_store.a[1][1][0] = sb_load.a[1][1][0];
       sb_store.a[1][1][1] = sb_load.a[1][1][1];
       sb_store.b = sb_load.b;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
        // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
        constexpr unsigned int kArrayStride                 = 16;
        constexpr unsigned int kDimension0                  = 2;
        constexpr unsigned int kDimension1                  = 2;
        constexpr unsigned int kDimension2                  = 2;
        constexpr unsigned int kAElementCount               = kDimension0 * kDimension1 * kDimension2;
        constexpr unsigned int kAComponentCountPerDimension = kArrayStride / kBytesPerComponent;
        constexpr unsigned int kTotalSize = kArrayStride * kAElementCount + kBytesPerComponent;
    
        constexpr GLuint kInputADatas[kAElementCount * kAComponentCountPerDimension] = {
            1u, 0u, 0u, 0u, 2u, 0u, 0u, 0u, 3u, 0u, 0u, 0u, 4u, 0u, 0u, 0u,
            5u, 0u, 0u, 0u, 6u, 0u, 0u, 0u, 7u, 0u, 0u, 0u, 8u, 0u, 0u, 0u};
        constexpr GLuint kInputBData = 9u;
    
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
        GLint offset = 0;
        // upload data to sb_load.a
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kAElementCount * kArrayStride, kInputADatas);
        offset += (kAElementCount * kArrayStride);
        // upload data to sb_load.b
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, kBytesPerComponent, &kInputBData);
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        constexpr GLuint kExpectedADatas[kAElementCount] = {1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u};
        const GLuint *ptr                                = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kTotalSize, GL_MAP_READ_BIT));
        for (unsigned i = 0u; i < kDimension0; i++)
        {
            for (unsigned j = 0u; j < kDimension1; j++)
            {
                for (unsigned k = 0u; k < kDimension2; k++)
                {
                    unsigned index = i * (kDimension1 * kDimension2) + j * kDimension2 + k;
                    EXPECT_EQ(kExpectedADatas[index],
                              *(ptr + index * (kArrayStride / kBytesPerComponent)));
                }
            }
        }
    
        ptr += (kAElementCount * (kArrayStride / kBytesPerComponent));
        EXPECT_EQ(kInputBData, *ptr);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that the length of unsized array is supported.
    TEST_P(ShaderStorageBufferTest31, UnsizedArrayLength)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    layout(std430, binding = 0) buffer Storage0 {
      uint buf1[2];
      uint buf2[];
    } sb_load;
    layout(std430, binding = 1) buffer Storage1 {
      int unsizedArrayLength;
      uint buf1[2];
      uint buf2[];
    } sb_store;
    
    void main()
    {
      sb_store.unsizedArrayLength = sb_store.buf2.length();
      for (int i = 0; i < sb_load.buf1.length(); i++) {
        sb_store.buf1[i] = sb_load.buf1[i];
      }
      for (int i = 0; i < sb_load.buf2.length(); i++) {
        sb_store.buf2[i] = sb_load.buf2[i];
      }
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent                       = sizeof(unsigned int);
        constexpr unsigned int kLoadBlockElementCount                   = 5;
        constexpr unsigned int kStoreBlockElementCount                  = 6;
        constexpr unsigned int kInputValues[kLoadBlockElementCount]     = {1u, 2u, 3u, 4u, 5u};
        constexpr unsigned int kExpectedValues[kStoreBlockElementCount] = {3u, 1u, 2u, 3u, 4u, 5u};
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kLoadBlockElementCount * kBytesPerComponent,
                     &kInputValues, GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kStoreBlockElementCount * kBytesPerComponent, nullptr,
                     GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kStoreBlockElementCount * kBytesPerComponent,
                             GL_MAP_READ_BIT));
        for (unsigned int i = 0; i < kStoreBlockElementCount; i++)
        {
            EXPECT_EQ(kExpectedValues[i], *(ptr + i));
        }
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test back to back that the length of unsized array is correct after respecifying the buffer
    // size to be smaller than the first
    TEST_P(ShaderStorageBufferTest31, UnsizedArrayLengthRespecifySize)
    {
        // http://anglebug.com/4566
        ANGLE_SKIP_TEST_IF(IsD3D11() || (IsAndroid() && IsOpenGLES()));
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    layout(std430, binding = 0) buffer Storage0 {
      uint buf1[2];
      uint buf2[];
    } sb_load;
    layout(std430, binding = 1) buffer Storage1 {
      int unsizedArrayLength;
      uint buf1[2];
      uint buf2[];
    } sb_store;
    
    void main()
    {
      sb_store.unsizedArrayLength = sb_store.buf2.length();
      for (int i = 0; i < sb_load.buf1.length(); i++) {
        sb_store.buf1[i] = sb_load.buf1[i];
      }
      for (int i = 0; i < sb_load.buf2.length(); i++) {
        sb_store.buf2[i] = sb_load.buf2[i];
      }
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent                       = sizeof(unsigned int);
        constexpr unsigned int kLoadBlockElementCount                   = 5;
        constexpr unsigned int kStoreBlockElementCount                  = 6;
        constexpr unsigned int kInputValues[kLoadBlockElementCount]     = {1u, 2u, 3u, 4u, 5u};
        constexpr unsigned int kExpectedValues[kStoreBlockElementCount] = {3u, 1u, 2u, 3u, 4u, 5u};
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kLoadBlockElementCount * kBytesPerComponent,
                     &kInputValues, GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kStoreBlockElementCount * kBytesPerComponent, nullptr,
                     GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kStoreBlockElementCount * kBytesPerComponent,
                             GL_MAP_READ_BIT));
        for (unsigned int i = 0; i < kStoreBlockElementCount; i++)
        {
            EXPECT_EQ(kExpectedValues[i], *(ptr + i));
        }
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    
        EXPECT_GL_NO_ERROR();
    
        // Respecify these SSBOs to be smaller
        constexpr unsigned int kSmallerLoadBlockElementCount                          = 3;
        constexpr unsigned int kSmallerStoreBlockElementCount                         = 4;
        constexpr unsigned int kSmallerInputValues[kSmallerLoadBlockElementCount]     = {1u, 2u, 3u};
        constexpr unsigned int kSmallerExpectedValues[kSmallerStoreBlockElementCount] = {1u, 1u, 2u,
                                                                                         3u};
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kSmallerLoadBlockElementCount * kBytesPerComponent,
                     &kSmallerInputValues, GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kSmallerStoreBlockElementCount * kBytesPerComponent,
                     nullptr, GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr2 = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0,
                             kSmallerStoreBlockElementCount * kBytesPerComponent, GL_MAP_READ_BIT));
        for (unsigned int i = 0; i < kSmallerStoreBlockElementCount; i++)
        {
            EXPECT_EQ(kSmallerExpectedValues[i], *(ptr2 + i));
        }
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that compond assignment operator for buffer variable is correctly handled.
    TEST_P(ShaderStorageBufferTest31, CompoundAssignmentOperator)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage0
    {
        uint b;
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        uint b;
    } sb_store;
    void main()
    {
        uint temp = 2u;
        temp += sb_load.b;
        sb_store.b += temp;
        sb_store.b += sb_load.b;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
        constexpr unsigned int kInputValue        = 1u;
        constexpr unsigned int kExpectedValue     = 5u;
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInputValue, GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInputValue, GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, GL_MAP_READ_BIT));
        EXPECT_EQ(kExpectedValue, *ptr);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that readonly binary operator for buffer variable is correctly handled.
    TEST_P(ShaderStorageBufferTest31, ReadonlyBinaryOperator)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
     layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
     layout(std430, binding = 0) buffer blockIn1 {
         uvec2 data1;
     };
     layout(std430, binding = 1) buffer blockIn2 {
         uvec2 data2;
     };
     layout(std430, binding = 2) buffer blockIn3 {
         uvec2 data;
     } instanceIn3;
     layout(std430, binding = 3) buffer blockOut {
         uvec2 data;
     } instanceOut;
     void main()
     {
         instanceOut.data = data1 + data2 + instanceIn3.data;
     }
     )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kComponentCount                = 2;
        constexpr unsigned int kBytesPerComponent             = sizeof(unsigned int);
        constexpr unsigned int kInputValues1[kComponentCount] = {1u, 2u};
        constexpr unsigned int kInputValues2[kComponentCount] = {3u, 4u};
        constexpr unsigned int kInputValues3[kComponentCount] = {5u, 6u};
        // Create shader storage buffer
        GLBuffer shaderStorageBuffer[4];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kInputValues1,
                     GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kInputValues2,
                     GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[2]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kInputValues3,
                     GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[3]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, nullptr,
                     GL_STATIC_DRAW);
    
        // Bind shader storage buffer
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, shaderStorageBuffer[2]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, shaderStorageBuffer[3]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        // Read back shader storage buffer
        constexpr unsigned int kExpectedValues[kComponentCount] = {9u, 12u};
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[3]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
            GL_SHADER_STORAGE_BUFFER, 0, kComponentCount * kBytesPerComponent, GL_MAP_READ_BIT));
        for (unsigned int idx = 0; idx < kComponentCount; idx++)
        {
            EXPECT_EQ(kExpectedValues[idx], *(ptr + idx));
        }
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that ssbo as an argument of a function can be translated.
    TEST_P(ShaderStorageBufferTest31, SSBOAsFunctionArgument)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout(local_size_x = 1) in;
    
    layout(std430, binding = 0) buffer Block
    {
        uint var1;
        uint var2;
    };
    
    bool compare(uint a, uint b)
    {
        return a == b;
    }
    
    uint increase(inout uint a)
    {
        a++;
        return a;
    }
    
    void main(void)
    {
        bool isEqual = compare(var1, 2u);
        if (isEqual)
        {
            var2 += increase(var1);
        }
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
        constexpr unsigned int kInputValues[2]    = {2u, 2u};
        constexpr unsigned int kExpectedValues[2] = {3u, 5u};
        GLBuffer shaderStorageBuffer;
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 2 * kBytesPerComponent, &kInputValues, GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 2 * kBytesPerComponent, GL_MAP_READ_BIT));
        EXPECT_EQ(kExpectedValues[0], *ptr);
        EXPECT_EQ(kExpectedValues[1], *(ptr + 1));
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that ssbo as unary operand works well.
    TEST_P(ShaderStorageBufferTest31, SSBOAsUnaryOperand)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage0
    {
        uint b;
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        uint i;
    } sb_store;
    void main()
    {
        sb_store.i = +sb_load.b;
        ++sb_store.i;
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        glUseProgram(program);
    
        constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
        constexpr unsigned kInputValue            = 1u;
        constexpr unsigned int kExpectedValue     = 2u;
        GLBuffer shaderStorageBuffer[2];
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInputValue, GL_STATIC_DRAW);
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInputValue, GL_STATIC_DRAW);
    
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
    
        glDispatchCompute(1, 1, 1);
        glFinish();
    
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
        const GLuint *ptr = reinterpret_cast<const GLuint *>(
            glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, GL_MAP_READ_BIT));
        EXPECT_EQ(kExpectedValue, *ptr);
    
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that uniform can be used as the index of buffer variable.
    TEST_P(ShaderStorageBufferTest31, UniformUsedAsIndexOfBufferVariable)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=4) in;
    layout(std140, binding = 0) uniform CB
    {
        uint index;
    } cb;
    
    layout(binding=0, std140) buffer Storage0
    {
        uint data[];
    } sb_load;
    layout(binding=1, std140) buffer Storage1
    {
        uint data[];
    } sb_store;
    void main()
    {
        sb_store.data[gl_LocalInvocationIndex] = sb_load.data[gl_LocalInvocationID.x + cb.index];
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    }
    
    // Test that inactive but statically used SSBOs with unsized array are handled correctly.
    //
    // Glslang wrapper used to replace the layout/qualifier of an inactive SSBO with |struct|,
    // effectively turning the interface block declaration into a struct definition.  This generally
    // worked except for SSBOs with an unsized array.  This test makes sure this special case is
    // now properly handled.
    TEST_P(ShaderStorageBufferTest31, InactiveButStaticallyUsedWithUnsizedArray)
    {
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    layout(binding=0, std140) buffer Storage
    {
        uint data[];
    } sb;
    void main()
    {
        if (false)
        {
            sb.data[0] = 1u;
        }
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program);
        glDispatchCompute(1, 1, 1);
        EXPECT_GL_NO_ERROR();
    }
    
    // Verify the size of the buffer with unsized struct array is calculated correctly
    TEST_P(ShaderStorageBufferTest31, BigStructUnsizedStructArraySize)
    {
        // TODO(http://anglebug.com/3596)
        ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    
    struct S
    {
        mat4 m;     // 4 vec4 = 16 floats
        vec4 a[10]; // 10 vec4 = 40 floats
    };
    
    layout(binding=0) buffer B
    {
        vec4 precedingMember;               // 4 floats
        S precedingMemberUnsizedArray[];    // 56 floats
    } b;
    
    void main()
    {
        if (false)
        {
            b.precedingMember = vec4(1.0, 1.0, 1.0, 1.0);
        }
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program);
        glDispatchCompute(1, 1, 1);
        EXPECT_GL_NO_ERROR();
    
        GLuint resourceIndex = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "B");
        EXPECT_GL_NO_ERROR();
        EXPECT_NE(resourceIndex, 0xFFFFFFFF);
    
        GLenum property = GL_BUFFER_DATA_SIZE;
        GLint queryData = -1;
        glGetProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &property, 1,
                               nullptr, &queryData);
        EXPECT_GL_NO_ERROR();
    
        // 60 * sizeof(float) = 240
        // Vulkan rounds up to the required buffer alignment, so >= 240
        EXPECT_GE(queryData, 240);
    }
    
    // Verify the size of the buffer with unsized float array is calculated correctly
    TEST_P(ShaderStorageBufferTest31, BigStructUnsizedFloatArraySize)
    {
        // TODO(http://anglebug.com/3596)
        ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
    
        constexpr char kComputeShaderSource[] =
            R"(#version 310 es
    layout (local_size_x=1) in;
    
    layout(binding=0) buffer B
    {
        vec4 precedingMember;                   // 4 floats
        float precedingMemberUnsizedArray[];    // "1" float
    } b;
    
    void main()
    {
        if (false)
        {
            b.precedingMember = vec4(1.0, 1.0, 1.0, 1.0);
        }
    }
    )";
    
        ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
        EXPECT_GL_NO_ERROR();
    
        glUseProgram(program);
        glDispatchCompute(1, 1, 1);
        EXPECT_GL_NO_ERROR();
    
        GLuint resourceIndex = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "B");
        EXPECT_GL_NO_ERROR();
        EXPECT_NE(resourceIndex, 0xFFFFFFFF);
    
        GLenum property = GL_BUFFER_DATA_SIZE;
        GLint queryData = -1;
        glGetProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &property, 1,
                               nullptr, &queryData);
        EXPECT_GL_NO_ERROR();
    
        // 5 * sizeof(float) = 20
        // Vulkan rounds up to the required buffer alignment, so >= 20
        EXPECT_GE(queryData, 20);
    }
    
    ANGLE_INSTANTIATE_TEST_ES31(ShaderStorageBufferTest31);
    
    }  // namespace