// // 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. // // AtomicCounter_test.cpp: // Tests for validating ESSL 3.10 section 4.4.6. // #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 AtomicCounterTest : public ShaderCompileTreeTest { public: AtomicCounterTest() {} protected: ::GLenum getShaderType() const override { return GL_VERTEX_SHADER; } ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; } void initResources(ShBuiltInResources *resources) override { resources->MaxAtomicCounterBindings = 8; } }; // Test that layout qualifiers described in ESSL 3.10 section 4.4.6 can be successfully compiled, // and the values of offset are properly assigned to counter variables. TEST_F(AtomicCounterTest, BasicAtomicCounterDeclaration) { mExtraCompileOptions |= SH_VARIABLES; const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint a;\n" "layout(binding = 2) uniform atomic_uint b;\n" "layout(binding = 2, offset = 12) uniform atomic_uint c, d;\n" "layout(binding = 1, offset = 4) uniform atomic_uint e;\n" "void main()\n" "{\n" "}\n"; if (!compile(source)) { FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog; } std::vector counters = getUniforms(); EXPECT_EQ(std::string("a"), counters[0].name); EXPECT_EQ(2, counters[0].binding); EXPECT_EQ(4, counters[0].offset); EXPECT_EQ(std::string("b"), counters[1].name); EXPECT_EQ(2, counters[1].binding); EXPECT_EQ(8, counters[1].offset); EXPECT_EQ(std::string("c"), counters[2].name); EXPECT_EQ(2, counters[2].binding); EXPECT_EQ(12, counters[2].offset); EXPECT_EQ(std::string("d"), counters[3].name); EXPECT_EQ(2, counters[3].binding); EXPECT_EQ(16, counters[3].offset); EXPECT_EQ(std::string("e"), counters[4].name); EXPECT_EQ(1, counters[4].binding); EXPECT_EQ(4, counters[4].offset); } // Test that ESSL 3.00 doesn't support atomic_uint. TEST_F(AtomicCounterTest, InvalidShaderVersion) { const std::string &source = "#version 300 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint a;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test that any qualifier other than uniform leads to compile-time error. TEST_F(AtomicCounterTest, InvalidQualifier) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) in atomic_uint a;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test that uniform must be specified for declaration. TEST_F(AtomicCounterTest, UniformMustSpecifiedForDeclaration) { const std::string &source = "#version 310 es\n" "atomic_uint a;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test that offset overlapping leads to compile-time error(ESSL 3.10 section 4.4.6). TEST_F(AtomicCounterTest, BindingOffsetOverlapping) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint a;\n" "layout(binding = 2, offset = 6) uniform atomic_uint b;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test offset inheritance for multiple variables in one same declaration. TEST_F(AtomicCounterTest, MultipleVariablesDeclaration) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint a, b;\n" "layout(binding = 2, offset = 8) uniform atomic_uint c;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test that subsequent declarations inherit the globally specified offset. TEST_F(AtomicCounterTest, GlobalBindingOffsetOverlapping) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint;\n" "layout(binding = 2) uniform atomic_uint b;\n" "layout(binding = 2, offset = 4) uniform atomic_uint c;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // The spec only demands offset unique and non-overlapping. So this should be allowed. TEST_F(AtomicCounterTest, DeclarationSequenceWithDecrementalOffsetsSpecified) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint a;\n" "layout(binding = 2, offset = 0) uniform atomic_uint b;\n" "void main()\n" "{\n" "}\n"; if (!compile(source)) { FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog; } } // Test that image format qualifiers are not allowed for atomic counters. TEST_F(AtomicCounterTest, ImageFormatMustNotSpecified) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4, rgba32f) uniform atomic_uint a;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test that global layout qualifiers must not use 'offset'. TEST_F(AtomicCounterTest, OffsetMustNotSpecifiedForGlobalLayoutQualifier) { const std::string &source = "#version 310 es\n" "layout(offset = 4) in;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } } // Test that offset overlapping leads to compile-time error (ESSL 3.10 section 4.4.6). // Note that there is some vagueness in the spec when it comes to this test. TEST_F(AtomicCounterTest, BindingOffsetOverlappingForArrays) { const std::string &source = "#version 310 es\n" "layout(binding = 2, offset = 4) uniform atomic_uint[2] a;\n" "layout(binding = 2, offset = 8) uniform atomic_uint b;\n" "void main()\n" "{\n" "}\n"; if (compile(source)) { FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; } }