Edit

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

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2020-12-01 15:43:13
    Hash : bb3adfa4
    Message : Rename ShaderVariable::structName to structOrBlockName Bug: angleproject:3580 Change-Id: Ic53a5267972f153dad2e20948e493e9767a45d16 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2568247 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/compiler_tests/ShaderVariable_test.cpp
  • //
    // Copyright 2014 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.
    //
    // CollectVariables_test.cpp:
    //   Some tests for shader inspection
    //
    
    #include "GLSLANG/ShaderLang.h"
    #include "angle_gl.h"
    #include "compiler/translator/Compiler.h"
    #include "gtest/gtest.h"
    
    namespace sh
    {
    
    TEST(ShaderVariableTest, FindInfoByMappedName)
    {
        // struct A {
        //   float x[2];
        //   vec3 y;
        // };
        // struct B {
        //   A a[3];
        // };
        // B uni[2];
        ShaderVariable uni(0, 2);
        uni.name              = "uni";
        uni.mappedName        = "m_uni";
        uni.structOrBlockName = "B";
        {
            ShaderVariable a(0, 3);
            a.name              = "a";
            a.mappedName        = "m_a";
            a.structOrBlockName = "A";
            {
                ShaderVariable x(GL_FLOAT, 2);
                x.name       = "x";
                x.mappedName = "m_x";
                a.fields.push_back(x);
    
                ShaderVariable y(GL_FLOAT_VEC3);
                y.name       = "y";
                y.mappedName = "m_y";
                a.fields.push_back(y);
            }
            uni.fields.push_back(a);
        }
    
        const ShaderVariable *leafVar = nullptr;
        std::string originalFullName;
    
        std::string mappedFullName = "wrongName";
        EXPECT_FALSE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
    
        mappedFullName = "m_uni";
        EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
        EXPECT_EQ(&uni, leafVar);
        EXPECT_STREQ("uni", originalFullName.c_str());
    
        mappedFullName = "m_uni[0].m_a[1].wrongName";
        EXPECT_FALSE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
    
        mappedFullName = "m_uni[0].m_a[1].m_x";
        EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
        EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
        EXPECT_STREQ("uni[0].a[1].x", originalFullName.c_str());
    
        mappedFullName = "m_uni[0].m_a[1].m_x[0]";
        EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
        EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
        EXPECT_STREQ("uni[0].a[1].x[0]", originalFullName.c_str());
    
        mappedFullName = "m_uni[0].m_a[1].m_y";
        EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
        EXPECT_EQ(&(uni.fields[0].fields[1]), leafVar);
        EXPECT_STREQ("uni[0].a[1].y", originalFullName.c_str());
    }
    
    TEST(ShaderVariableTest, IsSameUniformWithDifferentFieldOrder)
    {
        // struct A {
        //   float x;
        //   float y;
        // };
        // uniform A uni;
        ShaderVariable vx_a;
        vx_a.name              = "uni";
        vx_a.mappedName        = "m_uni";
        vx_a.structOrBlockName = "A";
        {
            ShaderVariable x(GL_FLOAT);
            x.name       = "x";
            x.mappedName = "m_x";
            vx_a.fields.push_back(x);
    
            ShaderVariable y(GL_FLOAT);
            y.name       = "y";
            y.mappedName = "m_y";
            vx_a.fields.push_back(y);
        }
    
        // struct A {
        //   float y;
        //   float x;
        // };
        // uniform A uni;
        ShaderVariable fx_a;
        fx_a.name              = "uni";
        fx_a.mappedName        = "m_uni";
        fx_a.structOrBlockName = "A";
        {
            ShaderVariable y(GL_FLOAT);
            y.name       = "y";
            y.mappedName = "m_y";
            fx_a.fields.push_back(y);
    
            ShaderVariable x(GL_FLOAT);
            x.name       = "x";
            x.mappedName = "m_x";
            fx_a.fields.push_back(x);
        }
    
        EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
    }
    
    TEST(ShaderVariableTest, IsSameUniformWithDifferentStructNames)
    {
        // struct A {
        //   float x;
        //   float y;
        // };
        // uniform A uni;
        ShaderVariable vx_a;
        vx_a.name              = "uni";
        vx_a.mappedName        = "m_uni";
        vx_a.structOrBlockName = "A";
        {
            ShaderVariable x(GL_FLOAT);
            x.name       = "x";
            x.mappedName = "m_x";
            vx_a.fields.push_back(x);
    
            ShaderVariable y(GL_FLOAT);
            y.name       = "y";
            y.mappedName = "m_y";
            vx_a.fields.push_back(y);
        }
    
        // struct B {
        //   float x;
        //   float y;
        // };
        // uniform B uni;
        ShaderVariable fx_a;
        fx_a.name       = "uni";
        fx_a.mappedName = "m_uni";
        {
            ShaderVariable x(GL_FLOAT);
            x.name       = "x";
            x.mappedName = "m_x";
            fx_a.fields.push_back(x);
    
            ShaderVariable y(GL_FLOAT);
            y.name       = "y";
            y.mappedName = "m_y";
            fx_a.fields.push_back(y);
        }
    
        fx_a.structOrBlockName = "B";
        EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
    
        fx_a.structOrBlockName = "A";
        EXPECT_TRUE(vx_a.isSameUniformAtLinkTime(fx_a));
    
        fx_a.structOrBlockName = "";
        EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
    }
    
    TEST(ShaderVariableTest, IsSameVaryingWithDifferentInvariance)
    {
        // invariant varying float vary;
        ShaderVariable vx;
        vx.type        = GL_FLOAT;
        vx.precision   = GL_MEDIUM_FLOAT;
        vx.name        = "vary";
        vx.mappedName  = "m_vary";
        vx.staticUse   = true;
        vx.isInvariant = true;
    
        // varying float vary;
        ShaderVariable fx;
        fx.type        = GL_FLOAT;
        fx.precision   = GL_MEDIUM_FLOAT;
        fx.name        = "vary";
        fx.mappedName  = "m_vary";
        fx.staticUse   = true;
        fx.isInvariant = false;
    
        // Default to ESSL1 behavior: invariance must match
        EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx));
        EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 100));
        // ESSL3 behavior: invariance doesn't need to match
        EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 300));
    
        // invariant varying float vary;
        fx.isInvariant = true;
        EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx));
        EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 100));
        EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 300));
    }
    
    // Test that using invariant varyings doesn't trigger a double delete.
    TEST(ShaderVariableTest, InvariantDoubleDeleteBug)
    {
        ShBuiltInResources resources;
        sh::InitBuiltInResources(&resources);
    
        ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
                                                  SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
        EXPECT_NE(static_cast<ShHandle>(0), compiler);
    
        const char *program[] = {
            "attribute vec4 position;\n"
            "varying float v;\n"
            "invariant v;\n"
            "void main() {\n"
            "  v = 1.0;\n"
            "  gl_Position = position;\n"
            "}"};
    
        EXPECT_TRUE(sh::Compile(compiler, program, 1, SH_OBJECT_CODE));
        EXPECT_TRUE(sh::Compile(compiler, program, 1, SH_OBJECT_CODE));
        sh::Destruct(compiler);
    }
    
    TEST(ShaderVariableTest, IllegalInvariantVarying)
    {
        ShBuiltInResources resources;
        sh::InitBuiltInResources(&resources);
    
        ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
                                                  SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
        EXPECT_NE(static_cast<ShHandle>(0), compiler);
    
        const char *program1[] = {
            R"(void foo()
            {
            }
            varying vec4 v_varying;
            invariant v_varying;
            void main()
            {
               foo();
               gl_Position = v_varying;
            })"};
        const char *program2[] = {
            "varying vec4 v_varying;\n"
            "void foo() {\n"
            "  invariant v_varying;\n"
            "}\n"
            "void main() {\n"
            "  foo();\n"
            "  gl_Position = v_varying;\n"
            "}"};
    
        EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
        EXPECT_FALSE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
        sh::Destruct(compiler);
    }
    
    TEST(ShaderVariableTest, InvariantLeakAcrossShaders)
    {
        ShBuiltInResources resources;
        sh::InitBuiltInResources(&resources);
    
        ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
                                                  SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
        EXPECT_NE(static_cast<ShHandle>(0), compiler);
    
        const char *program1[] = {
            "varying vec4 v_varying;\n"
            "invariant v_varying;\n"
            "void main() {\n"
            "  gl_Position = v_varying;\n"
            "}"};
        const char *program2[] = {
            "varying vec4 v_varying;\n"
            "void main() {\n"
            "  gl_Position = v_varying;\n"
            "}"};
    
        EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
        const std::vector<sh::ShaderVariable> *varyings = sh::GetOutputVaryings(compiler);
        for (const sh::ShaderVariable &varying : *varyings)
        {
            if (varying.name == "v_varying")
            {
                EXPECT_TRUE(varying.isInvariant);
            }
        }
        EXPECT_TRUE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
        varyings = sh::GetOutputVaryings(compiler);
        for (const sh::ShaderVariable &varying : *varyings)
        {
            if (varying.name == "v_varying")
            {
                EXPECT_FALSE(varying.isInvariant);
            }
        }
        sh::Destruct(compiler);
    }
    
    TEST(ShaderVariableTest, GlobalInvariantLeakAcrossShaders)
    {
        ShBuiltInResources resources;
        sh::InitBuiltInResources(&resources);
    
        ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
                                                  SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
        EXPECT_NE(static_cast<ShHandle>(0), compiler);
    
        const char *program1[] = {
            "#pragma STDGL invariant(all)\n"
            "varying vec4 v_varying;\n"
            "void main() {\n"
            "  gl_Position = v_varying;\n"
            "}"};
        const char *program2[] = {
            "varying vec4 v_varying;\n"
            "void main() {\n"
            "  gl_Position = v_varying;\n"
            "}"};
    
        EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
        const std::vector<sh::ShaderVariable> *varyings = sh::GetOutputVaryings(compiler);
        for (const sh::ShaderVariable &varying : *varyings)
        {
            if (varying.name == "v_varying")
            {
                EXPECT_TRUE(varying.isInvariant);
            }
        }
        EXPECT_TRUE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
        varyings = sh::GetOutputVaryings(compiler);
        for (const sh::ShaderVariable &varying : *varyings)
        {
            if (varying.name == "v_varying")
            {
                EXPECT_FALSE(varying.isInvariant);
            }
        }
        sh::Destruct(compiler);
    }
    
    TEST(ShaderVariableTest, BuiltinInvariantVarying)
    {
    
        ShBuiltInResources resources;
        sh::InitBuiltInResources(&resources);
    
        ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
                                                  SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
        EXPECT_NE(static_cast<ShHandle>(0), compiler);
    
        const char *program1[] = {
            "invariant gl_Position;\n"
            "void main() {\n"
            "  gl_Position = vec4(0, 0, 0, 0);\n"
            "}"};
        const char *program2[] = {
            "void main() {\n"
            "  gl_Position = vec4(0, 0, 0, 0);\n"
            "}"};
        const char *program3[] = {
            "void main() {\n"
            "  invariant gl_Position;\n"
            "  gl_Position = vec4(0, 0, 0, 0);\n"
            "}"};
    
        EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
        const std::vector<sh::ShaderVariable> *varyings = sh::GetOutputVaryings(compiler);
        for (const sh::ShaderVariable &varying : *varyings)
        {
            if (varying.name == "gl_Position")
            {
                EXPECT_TRUE(varying.isInvariant);
            }
        }
        EXPECT_TRUE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
        varyings = sh::GetOutputVaryings(compiler);
        for (const sh::ShaderVariable &varying : *varyings)
        {
            if (varying.name == "gl_Position")
            {
                EXPECT_FALSE(varying.isInvariant);
            }
        }
        EXPECT_FALSE(sh::Compile(compiler, program3, 1, SH_VARIABLES));
        sh::Destruct(compiler);
    }
    
    // Verify in ES3.1 two varyings with either same name or same declared location can match.
    TEST(ShaderVariableTest, IsSameVaryingWithDifferentName)
    {
        // Varying float vary1;
        ShaderVariable vx;
        vx.type        = GL_FLOAT;
        vx.precision   = GL_MEDIUM_FLOAT;
        vx.name        = "vary1";
        vx.mappedName  = "m_vary1";
        vx.staticUse   = true;
        vx.isInvariant = false;
    
        // Varying float vary2;
        ShaderVariable fx;
        fx.type        = GL_FLOAT;
        fx.precision   = GL_MEDIUM_FLOAT;
        fx.name        = "vary2";
        fx.mappedName  = "m_vary2";
        fx.staticUse   = true;
        fx.isInvariant = false;
    
        // ESSL3 behavior: name must match
        EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 300));
    
        // ESSL3.1 behavior:
        // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
        // An output variable is considered to match an input variable in the subsequent shader if:
        // - the two variables match in name, type, and qualification; or
        // - the two variables are declared with the same location qualifier and match in type and
        //   qualification.
        vx.location = 0;
        fx.location = 0;
        EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 310));
    
        fx.name       = vx.name;
        fx.mappedName = vx.mappedName;
    
        fx.location = -1;
        EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 310));
    
        fx.location = 1;
        EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 310));
    
        fx.location = 0;
        EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 310));
    }
    
    }  // namespace sh