Edit

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

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2017-11-14 15:03:14
    Hash : 7caa80e7
    Message : Edit tests to reference temporary variables The shader translator is intended to prune unreferenced variables in the future. To maintain test coverage when this is done, most tests that used to have unreferenced GLSL locals and globals are edited to use built-ins or reference the necessary variables instead. BUG=angleproject:2166 TEST=angle_unittests, angle_end2end_tests Change-Id: I3964e7a80d52fc04a95f57e73da6095e433095e8 Reviewed-on: https://chromium-review.googlesource.com/768740 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>

  • src/tests/compiler_tests/ShaderVariable_test.cpp
  • //
    // Copyright (c) 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 "angle_gl.h"
    #include "compiler/translator/Compiler.h"
    #include "gtest/gtest.h"
    #include "GLSLANG/ShaderLang.h"
    
    namespace sh
    {
    
    TEST(ShaderVariableTest, FindInfoByMappedName)
    {
        // struct A {
        //   float x[2];
        //   vec3 y;
        // };
        // struct B {
        //   A a[3];
        // };
        // B uni[2];
        ShaderVariable uni;
        uni.setArraySize(2);
        uni.name = "uni";
        uni.mappedName = "m_uni";
        uni.structName = "B";
        {
            ShaderVariable a;
            a.setArraySize(3);
            a.name = "a";
            a.mappedName = "m_a";
            a.structName = "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;
        Uniform vx_a;
        vx_a.name = "uni";
        vx_a.mappedName = "m_uni";
        vx_a.structName = "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;
        Uniform fx_a;
        fx_a.name = "uni";
        fx_a.mappedName = "m_uni";
        fx_a.structName = "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;
        Uniform vx_a;
        vx_a.name = "uni";
        vx_a.mappedName = "m_uni";
        vx_a.structName = "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;
        Uniform 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.structName = "B";
        EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
    
        fx_a.structName = "A";
        EXPECT_TRUE(vx_a.isSameUniformAtLinkTime(fx_a));
    
        fx_a.structName = "";
        EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
    }
    
    TEST(ShaderVariableTest, IsSameVaryingWithDifferentInvariance)
    {
        // invariant varying float vary;
        Varying 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;
        Varying 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::Varying> *varyings = sh::GetOutputVaryings(compiler);
        for (const sh::Varying &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::Varying &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::Varying> *varyings = sh::GetOutputVaryings(compiler);
        for (const sh::Varying &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::Varying &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::Varying> *varyings = sh::GetOutputVaryings(compiler);
        for (const sh::Varying &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::Varying &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;
        Varying 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;
        Varying 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