blob: 79f1df95bfc5960f5b79346b89ba302a21c694a2 [file] [log] [blame]
//
// 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.
//
// MSLOutput_test.cpp:
// Tests for MSL output.
//
#include <regex>
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "tests/test_utils/compiler_test.h"
using namespace sh;
class MSLVertexOutputTest : public MatchOutputCodeTest
{
public:
MSLVertexOutputTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_MSL_METAL_OUTPUT)
{
ShCompileOptions defaultCompileOptions = {};
setDefaultCompileOptions(defaultCompileOptions);
}
};
class MSLOutputTest : public MatchOutputCodeTest
{
public:
MSLOutputTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_MSL_METAL_OUTPUT)
{
ShCompileOptions defaultCompileOptions = {};
setDefaultCompileOptions(defaultCompileOptions);
}
};
// Test that having dynamic indexing of a vector inside the right hand side of logical or doesn't
// trigger asserts in MSL output.
TEST_F(MSLOutputTest, DynamicIndexingOfVectorOnRightSideOfLogicalOr)
{
const std::string &shaderString =
"#version 300 es\n"
"precision highp float;\n"
"out vec4 my_FragColor;\n"
"uniform int u1;\n"
"void main() {\n"
" bvec4 v = bvec4(true, true, true, false);\n"
" my_FragColor = vec4(v[u1 + 1] || v[u1]);\n"
"}\n";
compile(shaderString);
}
// Test that having an array constructor as a statement doesn't trigger an assert in MSL output.
TEST_F(MSLOutputTest, ArrayConstructorStatement)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
out vec4 outColor;
void main()
{
outColor = vec4(0.0, 0.0, 0.0, 1.0);
float[1](outColor[1]++);
})";
compile(shaderString);
}
// Test an array of arrays constructor as a statement.
TEST_F(MSLOutputTest, ArrayOfArraysStatement)
{
const std::string &shaderString =
R"(#version 310 es
precision mediump float;
out vec4 outColor;
void main()
{
outColor = vec4(0.0, 0.0, 0.0, 1.0);
float[2][2](float[2](outColor[1]++, 0.0), float[2](1.0, 2.0));
})";
compile(shaderString);
}
// Test dynamic indexing of a vector. This makes sure that helper functions added for dynamic
// indexing have correct data that subsequent traversal steps rely on.
TEST_F(MSLOutputTest, VectorDynamicIndexing)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
out vec4 outColor;
uniform int i;
void main()
{
vec4 foo = vec4(0.0, 0.0, 0.0, 1.0);
foo[i] = foo[i + 1];
outColor = foo;
})";
compile(shaderString);
}
// Test returning an array from a user-defined function. This makes sure that function symbols are
// changed consistently when the user-defined function is changed to have an array out parameter.
TEST_F(MSLOutputTest, ArrayReturnValue)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float u;
out vec4 outColor;
float[2] getArray(float f)
{
return float[2](f, f + 1.0);
}
void main()
{
float[2] arr = getArray(u);
outColor = vec4(arr[0], arr[1], 0.0, 1.0);
})";
compile(shaderString);
}
// Test that writing parameters without a name doesn't assert.
TEST_F(MSLOutputTest, ParameterWithNoName)
{
const std::string &shaderString =
R"(precision mediump float;
uniform vec4 v;
vec4 s(vec4)
{
return v;
}
void main()
{
gl_FragColor = s(v);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, Macro)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
#define FOO vec4
out vec4 outColor;
void main()
{
outColor = FOO(1.0, 2.0, 3.0, 4.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, UniformSimple)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 outColor;
uniform float x;
void main()
{
outColor = vec4(x, x, x, x);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, FragmentOutSimple)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 outColor;
void main()
{
outColor = vec4(1.0, 2.0, 3.0, 4.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, FragmentOutIndirect1)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 outColor;
void foo()
{
outColor = vec4(1.0, 2.0, 3.0, 4.0);
}
void bar()
{
foo();
}
void main()
{
bar();
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, FragmentOutIndirect2)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 outColor;
void foo();
void bar()
{
foo();
}
void foo()
{
outColor = vec4(1.0, 2.0, 3.0, 4.0);
}
void main()
{
bar();
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, FragmentOutIndirect3)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 outColor;
float foo(float x, float y)
{
outColor = vec4(x, y, 3.0, 4.0);
return 7.0;
}
float bar(float x)
{
return foo(x, 2.0);
}
float baz()
{
return 13.0;
}
float identity(float x)
{
return x;
}
void main()
{
identity(bar(baz()));
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, VertexInOut)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
in float in0;
out float out0;
void main()
{
out0 = in0;
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, SymbolSharing)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out vec4 outColor;
struct Foo {
float x;
float y;
};
void doFoo(Foo foo, float zw);
void doFoo(Foo foo, float zw)
{
foo.x = foo.y;
outColor = vec4(foo.x, foo.y, zw, zw);
}
void main()
{
Foo foo;
foo.x = 2.0;
foo.y = 2.0;
doFoo(foo, 3.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, StructDecl)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
out float out0;
struct Foo {
float value;
};
void main()
{
Foo foo;
out0 = foo.value;
}
)";
compile(shaderString);
}
TEST_F(MSLOutputTest, Structs)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
struct Foo {
float value;
};
out vec4 out0;
struct Bar {
Foo foo;
};
void go();
uniform UniInstance {
Bar bar;
float instance;
} uniInstance;
uniform UniGlobal {
Foo foo;
float global;
};
void main()
{
go();
}
struct Baz {
Bar bar;
} baz;
void go()
{
out0.x = baz.bar.foo.value;
out0.y = global;
out0.z = uniInstance.instance;
out0.w = 0.0;
}
)";
compile(shaderString);
}
TEST_F(MSLOutputTest, KeywordConflict)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
struct fragment {
float kernel;
} device;
struct Foo {
fragment frag;
} foo;
out float vertex;
float kernel;
float stage_in(float x)
{
return x;
}
void metal(float metal, float fragment);
void metal(float metal, float fragment)
{
vertex = metal * fragment * foo.frag.kernel;
}
void main()
{
metal(stage_in(stage_in(kernel * device.kernel)), foo.frag.kernel);
})";
compile(shaderString);
}
TEST_F(MSLVertexOutputTest, Vertex)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
void main()
{
gl_Position = vec4(1.0,1.0,1.0,1.0);
})";
compile(shaderString);
}
TEST_F(MSLVertexOutputTest, LastReturn)
{
const std::string &shaderString =
R"(#version 300 es
in highp vec4 a_position;
in highp vec4 a_coords;
out highp vec4 v_color;
void main (void)
{
gl_Position = a_position;
v_color = vec4(a_coords.xyz, 1.0);
return;
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, LastReturn)
{
const std::string &shaderString =
R"(#version 300 es
in mediump vec4 v_coords;
layout(location = 0) out mediump vec4 o_color;
void main (void)
{
o_color = vec4(v_coords.xyz, 1.0);
return;
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, FragColor)
{
const std::string &shaderString = R"(
void main ()
{
gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, MatrixIn)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
in mat4 mat;
out float out0;
void main()
{
out0 = mat[0][0];
}
)";
compile(shaderString);
}
TEST_F(MSLOutputTest, WhileTrue)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float uf;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
while (true)
{
break;
}
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, ForTrue)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float uf;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
for (;true;)
{
break;
}
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, ForEmpty)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float uf;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
for (;;)
{
break;
}
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, ForComplex)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float uf;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
for (int i = 0, j = 2; i < j; ++i) {
if (i == 0) continue;
if (i == 42) break;
my_FragColor.x += float(i);
}
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, ForSymbol)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float uf;
out vec4 my_FragColor;
void main()
{
bool cond = true;
for (;cond;)
{
my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
cond = false;
}
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, DoWhileSymbol)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
uniform float uf;
out vec4 my_FragColor;
void main()
{
bool cond = false;
do
{
my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} while (cond);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, AnonymousStruct)
{
const std::string &shaderString =
R"(
precision mediump float;
struct { vec4 v; } anonStruct;
void main() {
anonStruct.v = vec4(0.0,1.0,0.0,1.0);
gl_FragColor = anonStruct.v;
})";
compile(shaderString);
// TODO(anglebug.com/6395): This success condition is expected to fail now.
// When WebKit build is able to run the tests, this should be changed to something else.
// ASSERT_TRUE(foundInCode(SH_MSL_METAL_OUTPUT, "__unnamed"));
}
TEST_F(MSLOutputTest, GlobalRescopingSimple)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should rescope uf into main
float uf;
out vec4 my_FragColor;
void main()
{
uf += 1.0f;
my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingNoRescope)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should not rescope any variable
float uf;
out vec4 my_FragColor;
void modifyGlobal()
{
uf = 1.0f;
}
void main()
{
modifyGlobal();
my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingInitializer)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should rescope uf into main
float uf = 1.0f;
out vec4 my_FragColor;
void main()
{
uf += 1.0;
my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingInitializerNoRescope)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should not rescope any variable
float uf = 1.0f;
out vec4 my_FragColor;
void modifyGlobal()
{
uf =+ 1.0f;
}
void main()
{
modifyGlobal();
my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingNestedFunction)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should rescope a info modifyGlobal
float a = 1.0f;
float uf = 1.0f;
out vec4 my_FragColor;
void modifyGlobal()
{
uf =+ a;
}
void main()
{
modifyGlobal();
my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingMultipleUses)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should rescope uf into main
float uf = 1.0f;
out vec4 my_FragColor;
void main()
{
uf =+ 1.0;
if (uf > 0.0)
{
uf =- 0.5;
}
my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingGloballyReferencedVar)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should rescope uf into main
const float a = 1.0f;
float uf = a;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(uf, 0.0, a, 0.0);
})";
compile(shaderString);
}
TEST_F(MSLOutputTest, GlobalRescopingDeclarationAfterFunction)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
// Should rescope c and b into main
float a = 1.0f;
float c = 1.0f;
out vec4 my_FragColor;
void modifyGlobal()
{
a =+ 1.0f;
}
float b = 1.0f;
void main()
{
modifyGlobal();
my_FragColor = vec4(a, b, c, 0.0);
}
)";
compile(shaderString);
}
TEST_F(MSLOutputTest, ReusedOutVarName)
{
const std::string &shaderString =
R"(#version 300 es
precision mediump float;
out vec4 my_FragColor;
void funcWith1Out(
out float outC) {
outC = 1.0;
}
void funcWith4Outs(
out float outA,
out float outB,
out float outC,
out float outD) {
outA = 1.0;
outB = 1.0;
outD = 1.0;
}
void main()
{
funcWith1Out(my_FragColor.g);
funcWith4Outs(my_FragColor.r, my_FragColor.g, my_FragColor.b, my_FragColor.a);
}
)";
compile(shaderString);
}