Edit

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

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2019-12-19 14:47:46
    Hash : 07f0f019
    Message : Translator: Memory qualifiers on SSBO fields These were not output prior to this CL. Of these qualifiers, readonly and writeonly are unnecessary as ANGLE already does the appropriate validation, but the rest (coherent, volatile, restrict) are necessary, even though the tests pass on the bots by coincidence of driver behavior/test simplicity. Bug: angleproject:3602 Change-Id: Ie75fee0f004944b50ef21124ba25c4315e082b85 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1976499 Reviewed-by: Cody Northrop <cnorthrop@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/tests/compiler_tests/BufferVariables_test.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.
    //
    // 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"
    #include "tests/test_utils/compiler_test.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;
        }
    };
    
    class BufferVariablesMatchTest : public MatchOutputCodeTest
    {
      public:
        BufferVariablesMatchTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, 0, SH_ESSL_OUTPUT)
        {
            getResources()->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;
        }
    }
    
    // Test that memory qualifiers are output.
    TEST_F(BufferVariablesMatchTest, MemoryQualifiers)
    {
        const std::string &source =
            R"(#version 310 es
    
            layout(std430) coherent buffer buf
            {
                int defaultCoherent;
                coherent ivec2 specifiedCoherent;
                volatile ivec3 specifiedVolatile;
                restrict ivec4 specifiedRestrict;
                readonly float specifiedReadOnly;
                writeonly vec2 specifiedWriteOnly;
                volatile readonly vec3 specifiedMultiple;
            };
    
            void main()
            {
            })";
        compile(source);
        ASSERT_TRUE(foundInESSLCode("coherent highp int"));
        ASSERT_TRUE(foundInESSLCode("coherent highp ivec2"));
        ASSERT_TRUE(foundInESSLCode("coherent volatile highp ivec3"));
        ASSERT_TRUE(foundInESSLCode("coherent restrict highp ivec4"));
        ASSERT_TRUE(foundInESSLCode("readonly coherent highp float"));
        ASSERT_TRUE(foundInESSLCode("writeonly coherent highp vec2"));
        ASSERT_TRUE(foundInESSLCode("readonly coherent volatile highp vec3"));
    }