Edit

kc3-lang/angle/src/tests/compiler_tests/BufferVariables_test.cpp

Branch :

  • Show log

    Commit

  • Author : Qin Jiajia
    Date : 2018-02-22 14:11:34
    Hash : 76bf01d7
    Message : Fix that readonly buffer variable can be assigned This change will add memory qualifier checking for binaryNode in case the memory qualifier information is lost. BUG=angleproject:1951 TEST=angle_unittests Change-Id: I3f0cfd7d8a059753cf3c982ee0a977b4b0fd0128 Reviewed-on: https://chromium-review.googlesource.com/929877 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • src/tests/compiler_tests/BufferVariables_test.cpp
  • //
    // Copyright (c) 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.
    //
    // BufferVariables_test.cpp:
    //   Tests for buffer variables in GLSL ES 3.10 section 4.3.7.
    //
    
    #include "gtest/gtest.h"
    
    #include "GLSLANG/ShaderLang.h"
    #include "angle_gl.h"
    #include "gtest/gtest.h"
    #include "tests/test_utils/ShaderCompileTreeTest.h"
    
    using namespace sh;
    
    class BufferVariablesTest : public ShaderCompileTreeTest
    {
      public:
        BufferVariablesTest() {}
    
      protected:
        ::GLenum getShaderType() const override { return GL_VERTEX_SHADER; }
        ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
        void initResources(ShBuiltInResources *resources) override
        {
            resources->MaxShaderStorageBufferBindings = 8;
        }
    };
    
    // Test that the buffer qualifier described in GLSL ES 3.10 section 4.3.7 can be successfully
    // compiled.
    TEST_F(BufferVariablesTest, BasicShaderStorageBlockDeclaration)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    int b1;\n"
            "    buffer int b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that shader storage block layout qualifiers can be declared for global scope.
    TEST_F(BufferVariablesTest, LayoutQualifiersDeclaredInGlobal)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(shared, column_major) buffer;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that shader storage block can be used with one or more memory qualifiers.
    TEST_F(BufferVariablesTest, ShaderStorageBlockWithMemoryQualifier)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) writeonly buffer buf {\n"
            "    int b1;\n"
            "    buffer int b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that buffer variables can be used with one or more memory qualifiers.
    TEST_F(BufferVariablesTest, BufferVariablesWithMemoryQualifier)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly int b1;\n"
            "    writeonly buffer int b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that it is a compile-time error to declare buffer variables at global scope (outside a
    // block).
    TEST_F(BufferVariablesTest, DeclareBufferVariableAtGlobal)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer int a;\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that the buffer variable can't be opaque type.
    TEST_F(BufferVariablesTest, BufferVariableWithOpaqueType)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    int b1;\n"
            "    atomic_uint b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that the uniform variable can't be in shader storage block.
    TEST_F(BufferVariablesTest, UniformVariableInShaderStorageBlock)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    uniform int a;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that buffer qualifier is not supported in verson lower than GLSL ES 3.10.
    TEST_F(BufferVariablesTest, BufferQualifierInESSL3)
    {
        const std::string &source =
            "#version 300 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    int b1;\n"
            "    buffer int b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that can't assign to a readonly buffer variable.
    TEST_F(BufferVariablesTest, AssignToReadonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    readonly int b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    b1 = 5;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that can't assign to a buffer variable declared within shader storage block with readonly.
    TEST_F(BufferVariablesTest, AssignToBufferVariableWithinReadonlyBlock)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) readonly buffer buf {\n"
            "    int b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    b1 = 5;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that can't assign to a readonly buffer variable through an instance name.
    TEST_F(BufferVariablesTest, AssignToReadonlyBufferVariableByInstanceName)
    {
        const std::string &source =
            R"(#version 310 es
            layout(binding = 3) buffer buf {
                readonly float f;
            } instanceBuffer;
            void main()
            {
                instanceBuffer.f += 0.2;
            })";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that can't assign to a readonly struct buffer variable.
    TEST_F(BufferVariablesTest, AssignToReadonlyStructBufferVariable)
    {
        const std::string &source =
            R"(#version 310 es
            struct S {
                float f;
            };
            layout(binding = 3) buffer buf {
                readonly S s;
            };
            void main()
            {
                s.f += 0.2;
            })";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that can't assign to a readonly struct buffer variable through an instance name.
    TEST_F(BufferVariablesTest, AssignToReadonlyStructBufferVariableByInstanceName)
    {
        const std::string &source =
            R"(#version 310 es
            struct S {
                float f;
            };
            layout(binding = 3) buffer buf {
                readonly S s;
            } instanceBuffer;
            void main()
            {
                instanceBuffer.s.f += 0.2;
            })";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that a readonly and writeonly buffer variable should neither read or write.
    TEST_F(BufferVariablesTest, AccessReadonlyWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    readonly writeonly int b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    b1 = 5;\n"
            "    int test = b1;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that accessing a writeonly buffer variable should be error.
    TEST_F(BufferVariablesTest, AccessWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly int b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    int test = b1;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that accessing a buffer variable through an instance name is ok.
    TEST_F(BufferVariablesTest, AccessReadonlyBufferVariableByInstanceName)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    readonly float f;\n"
            "} instanceBuffer;\n"
            "void main()\n"
            "{\n"
            "    gl_Position.x = instanceBuffer.f;\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that accessing a buffer variable through an instance name inherits the writeonly qualifier
    // and generates errors.
    TEST_F(BufferVariablesTest, AccessWriteonlyBufferVariableByInstanceName)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) writeonly buffer buf {\n"
            "    float f;\n"
            "} instanceBuffer;\n"
            "void main()\n"
            "{\n"
            "    float test = instanceBuffer.f;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as the argument of a unary operator should be error.
    TEST_F(BufferVariablesTest, UnaryOperatorWithWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly int b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    ++b1;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable on the left-hand side of compound assignment should be error.
    TEST_F(BufferVariablesTest, CompoundAssignmentToWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly int b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    b1 += 5;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as ternary op argument should be error.
    TEST_F(BufferVariablesTest, TernarySelectionWithWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly bool b1;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    int test = b1 ? 1 : 0;\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as array constructor argument should be error.
    TEST_F(BufferVariablesTest, ArrayConstructorWithWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly float f;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    float a[3] = float[3](f, f, f);\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as structure constructor argument should be error.
    TEST_F(BufferVariablesTest, StructureConstructorWithWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "struct S {\n"
            "    int a;\n"
            "};\n"
            "struct T {\n"
            "    S b;\n"
            "};\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly S c;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    T t = T(c);\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as built-in function argument should be error.
    TEST_F(BufferVariablesTest, BuildInFunctionWithWriteonlyBufferVariable)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly int a;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "    int test = min(a, 1);\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that readonly buffer variable as user-defined function in argument should be ok.
    TEST_F(BufferVariablesTest, UserDefinedFunctionWithReadonlyBufferVariableInArgument)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    readonly float f;\n"
            "};\n"
            "void foo(float a) {}\n"
            "void main()\n"
            "{\n"
            "    foo(f);\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as user-defined function in argument should be error.
    TEST_F(BufferVariablesTest, UserDefinedFunctionWithWriteonlyBufferVariableInArgument)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly float f;\n"
            "};\n"
            "void foo(float a) {}\n"
            "void main()\n"
            "{\n"
            "    foo(f);\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that writeonly buffer variable as user-defined function out argument should be ok.
    TEST_F(BufferVariablesTest, UserDefinedFunctionWithWriteonlyBufferVariableOutArgument)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    writeonly float f;\n"
            "};\n"
            "void foo(out float a) {}\n"
            "void main()\n"
            "{\n"
            "    foo(f);\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that readonly buffer variable as user-defined function out argument should be error.
    TEST_F(BufferVariablesTest, UserDefinedFunctionWithReadonlyBufferVariableOutArgument)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(binding = 3) buffer buf {\n"
            "    readonly float f;\n"
            "};\n"
            "void foo(out float a) {}\n"
            "void main()\n"
            "{\n"
            "    foo(f);\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that buffer qualifier can't modify a function parameter.
    TEST_F(BufferVariablesTest, BufferQualifierOnFunctionParameter)
    {
        const std::string &source =
            "#version 310 es\n"
            "void foo(buffer float a) {}\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that std430 qualifier is supported for shader storage blocks.
    TEST_F(BufferVariablesTest, ShaderStorageBlockWithStd430)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(std430) buffer buf {\n"
            "    int b1;\n"
            "    int b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that using std430 qualifier on a uniform block will fail to compile.
    TEST_F(BufferVariablesTest, UniformBlockWithStd430)
    {
        const std::string &source =
            "#version 310 es\n"
            "layout(std430) uniform buf {\n"
            "    int b1;\n"
            "    int b2;\n"
            "};\n"
            "void main()\n"
            "{\n"
            "}\n";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that indexing a runtime-sized array with a positive index compiles.
    TEST_F(BufferVariablesTest, IndexRuntimeSizedArray)
    {
        const std::string &source =
            R"(#version 310 es
    
            layout(std430) buffer buf
            {
                int arr[];
            };
    
            void main()
            {
                arr[100];
            })";
        if (!compile(source))
        {
            FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
        }
    }
    
    // Test that indexing a runtime-sized array with a negative constant index does not compile.
    TEST_F(BufferVariablesTest, IndexRuntimeSizedArrayWithNegativeIndex)
    {
        const std::string &source =
            R"(#version 310 es
    
            layout(std430) buffer buf
            {
                int arr[];
            };
    
            void main()
            {
                arr[-1];
            })";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }
    
    // Test that only the last member of a buffer can be runtime-sized.
    TEST_F(BufferVariablesTest, RuntimeSizedVariableInNotLastInBuffer)
    {
        const std::string &source =
            R"(#version 310 es
    
            layout(std430) buffer buf
            {
                int arr[];
                int i;
            };
    
            void main()
            {
            })";
        if (compile(source))
        {
            FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
        }
    }