a003e8184e
We don't expect raw literals to ever appear here; this is a defensive maneuver. See http://review.skia.org/316440 for an example case where raw literals accidentally made it all the way to the inlining pass, due to a missing `coerce`. Change-Id: I80198f2f135791931aa53e0d6d92f1edfe4fb3b5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/315970 Reviewed-by: Ethan Nicholas <ethannicholas@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
1241 lines
30 KiB
C++
1241 lines
30 KiB
C++
/*
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "src/sksl/SkSLCompiler.h"
|
|
|
|
#include "tests/Test.h"
|
|
|
|
// Note that the optimizer will aggressively kill dead code and substitute constants in place of
|
|
// variables, so we have to jump through a few hoops to ensure that the code in these tests has the
|
|
// necessary side-effects to remain live. In some cases we rely on the optimizer not (yet) being
|
|
// smart enough to optimize around certain constructs; as the optimizer gets smarter it will
|
|
// undoubtedly end up breaking some of these tests. That is a good thing, as long as the new code is
|
|
// equivalent!
|
|
|
|
static void test(skiatest::Reporter* r, const SkSL::Program::Settings& settings,
|
|
const char* src, const char* expectedGLSL, SkSL::Program::Inputs* inputs,
|
|
SkSL::Program::Kind kind = SkSL::Program::kFragment_Kind) {
|
|
SkSL::Compiler compiler;
|
|
SkSL::String output;
|
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, SkSL::String(src),
|
|
settings);
|
|
if (!program) {
|
|
SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
|
|
}
|
|
REPORTER_ASSERT(r, program);
|
|
if (program) {
|
|
*inputs = program->fInputs;
|
|
REPORTER_ASSERT(r, compiler.toGLSL(*program, &output));
|
|
if (program) {
|
|
SkSL::String skExpected(expectedGLSL);
|
|
if (output != skExpected) {
|
|
SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'",
|
|
src, expectedGLSL, output.c_str());
|
|
}
|
|
REPORTER_ASSERT(r, output == skExpected);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test(skiatest::Reporter* r, const GrShaderCaps& caps,
|
|
const char* src, const char* expectedGLSL,
|
|
SkSL::Program::Kind kind = SkSL::Program::kFragment_Kind) {
|
|
SkSL::Program::Settings settings;
|
|
settings.fCaps = ∩︀
|
|
SkSL::Program::Inputs inputs;
|
|
test(r, settings, src, expectedGLSL, &inputs, kind);
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionInlineThreshold, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"void tooBig(inout int x) {"
|
|
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
|
|
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
|
|
"}"
|
|
"void main() { int x = 0; tooBig(x); }",
|
|
"#version 400\n"
|
|
"void tooBig(inout int x) {\n"
|
|
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
|
|
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
|
|
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
|
|
" ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n ++x;\n"
|
|
" ++x;\n ++x;\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" int x = 0;\n"
|
|
" tooBig(x);\n"
|
|
"}\n"
|
|
);
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionInlineKeywordOverridesThreshold, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"inline void tooBig(inout int x) {"
|
|
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
|
|
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
|
|
"}"
|
|
"void main() { int y = 0; tooBig(y); }",
|
|
R"__GLSL__(#version 400
|
|
void main() {
|
|
int y = 0;
|
|
{
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
++y;
|
|
}
|
|
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionUnableToInlineReturnsInsideLoop, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"inline void cantActuallyInline(inout int x) {"
|
|
" for (;;) {"
|
|
" ++x;"
|
|
" if (x > 10) return;"
|
|
" }"
|
|
"}"
|
|
"void main() { int x = 0; cantActuallyInline(x); }",
|
|
"#version 400\n"
|
|
"void cantActuallyInline(inout int x) {\n"
|
|
" for (; ; ) {\n"
|
|
" ++x;\n"
|
|
" if (x > 10) return;\n"
|
|
" }\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" int x = 0;\n"
|
|
" cantActuallyInline(x);\n"
|
|
"}\n");
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionInlineWithUnmodifiedArgument, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"half basic(half x) {"
|
|
" return x * 2;"
|
|
"}"
|
|
"void main() {"
|
|
" sk_FragColor.x = basic(1);"
|
|
" half y = 2;"
|
|
" sk_FragColor.y = basic(y);"
|
|
"}",
|
|
"#version 400\n"
|
|
"out vec4 sk_FragColor;\n"
|
|
"void main() {\n"
|
|
" sk_FragColor.x = 2.0;\n"
|
|
"\n"
|
|
" sk_FragColor.y = 4.0;\n"
|
|
"\n"
|
|
"}\n");
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionInlineWithModifiedArgument, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"half parameterWrite(half x) {"
|
|
" x *= 2;"
|
|
" return x;"
|
|
"}"
|
|
"void main() {"
|
|
" sk_FragColor.x = parameterWrite(1);"
|
|
"}",
|
|
R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
void main() {
|
|
float _0_parameterWrite;
|
|
float _1_x = 1.0;
|
|
{
|
|
_1_x *= 2.0;
|
|
_0_parameterWrite = _1_x;
|
|
}
|
|
|
|
sk_FragColor.x = _0_parameterWrite;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionInlineWithInoutArgument, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"void outParameter(inout half x) {"
|
|
" x *= 2;"
|
|
"}"
|
|
"void main() {"
|
|
" half x = 1;"
|
|
" outParameter(x);"
|
|
" sk_FragColor.x = x;"
|
|
"}",
|
|
R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
void main() {
|
|
float x = 1.0;
|
|
{
|
|
x *= 2.0;
|
|
}
|
|
|
|
|
|
sk_FragColor.x = x;
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionInlineWithNestedCall, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
"void foo(out half x) {"
|
|
" ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;"
|
|
" --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x;"
|
|
" x = 42;"
|
|
"}"
|
|
"half bar(half y) {"
|
|
" foo(y);"
|
|
" return y;"
|
|
"}"
|
|
"void main() {"
|
|
" half _1_y = 123;" // make sure the inliner doesn't try to reuse this name
|
|
" half z = 0;"
|
|
" bar(z);"
|
|
" sk_FragColor.x = z;"
|
|
"}",
|
|
R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
void foo(out float x) {
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
++x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
--x;
|
|
x = 42.0;
|
|
}
|
|
void main() {
|
|
float _2_y = 0.0;
|
|
{
|
|
foo(_2_y);
|
|
}
|
|
|
|
|
|
sk_FragColor.x = 0.0;
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPTernaryExpressionsShouldNotInlineResults, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half count = 0;
|
|
bool test(half4 v) {
|
|
return v.x <= 0.5;
|
|
}
|
|
half4 trueSide(half4 v) {
|
|
count += 1;
|
|
return half4(sin(v.x), sin(v.y), sin(v.z), sin(v.w));
|
|
}
|
|
half4 falseSide(half4 v) {
|
|
count += 1;
|
|
return half4(cos(v.y), cos(v.z), cos(v.w), cos(v.z));
|
|
}
|
|
void main() {
|
|
sk_FragColor = test(color) ? trueSide(color) : falseSide(color);
|
|
sk_FragColor *= count;
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
float count = 0.0;
|
|
vec4 trueSide(vec4 v) {
|
|
count += 1.0;
|
|
return vec4(sin(v.x), sin(v.y), sin(v.z), sin(v.w));
|
|
}
|
|
vec4 falseSide(vec4 v) {
|
|
count += 1.0;
|
|
return vec4(cos(v.y), cos(v.z), cos(v.w), cos(v.z));
|
|
}
|
|
void main() {
|
|
bool _0_test;
|
|
{
|
|
_0_test = color.x <= 0.5;
|
|
}
|
|
|
|
sk_FragColor = _0_test ? trueSide(color) : falseSide(color);
|
|
|
|
sk_FragColor *= count;
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPShortCircuitEvaluationsCannotInlineRightHandSide, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
bool testA(half4 v) {
|
|
return v.x <= 0.5;
|
|
}
|
|
bool testB(half4 v) {
|
|
return v.x > 0.5;
|
|
}
|
|
void main() {
|
|
sk_FragColor = half4(0);
|
|
if (testA(color) && testB(color)) {
|
|
sk_FragColor = half4(0.5);
|
|
}
|
|
if (testB(color) || testA(color)) {
|
|
sk_FragColor = half4(1.0);
|
|
}
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
bool testA(vec4 v) {
|
|
return v.x <= 0.5;
|
|
}
|
|
bool testB(vec4 v) {
|
|
return v.x > 0.5;
|
|
}
|
|
void main() {
|
|
sk_FragColor = vec4(0.0);
|
|
bool _0_testA;
|
|
{
|
|
_0_testA = color.x <= 0.5;
|
|
}
|
|
|
|
if (_0_testA && testB(color)) {
|
|
sk_FragColor = vec4(0.5);
|
|
}
|
|
|
|
bool _1_testB;
|
|
{
|
|
_1_testB = color.x > 0.5;
|
|
}
|
|
|
|
if (_1_testB || testA(color)) {
|
|
sk_FragColor = vec4(1.0);
|
|
}
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPWhileTestCannotBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
bool shouldLoop(half4 v) {
|
|
return v.x < 0.5;
|
|
}
|
|
void main() {
|
|
sk_FragColor = half4(0);
|
|
while (shouldLoop(sk_FragColor)) {
|
|
sk_FragColor += half4(0.125);
|
|
}
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
bool shouldLoop(vec4 v) {
|
|
return v.x < 0.5;
|
|
}
|
|
void main() {
|
|
sk_FragColor = vec4(0.0);
|
|
while (shouldLoop(sk_FragColor)) {
|
|
sk_FragColor += vec4(0.125);
|
|
}
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinedWhileBodyMustBeInAScope, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
half4 adjust(half4 v) {
|
|
return v + half4(0.125);
|
|
}
|
|
void main() {
|
|
sk_FragColor = half4(0);
|
|
while (sk_FragColor.x < 0.5)
|
|
sk_FragColor = adjust(sk_FragColor);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
void main() {
|
|
sk_FragColor = vec4(0.0);
|
|
while (sk_FragColor.x < 0.5) {
|
|
vec4 _0_adjust;
|
|
{
|
|
_0_adjust = sk_FragColor + vec4(0.125);
|
|
}
|
|
|
|
sk_FragColor = _0_adjust;
|
|
}
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPDoWhileTestCannotBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
bool shouldLoop(half4 v) {
|
|
return v.x < 0.5;
|
|
}
|
|
void main() {
|
|
sk_FragColor = half4(0);
|
|
do {
|
|
sk_FragColor += half4(0.125);
|
|
} while (shouldLoop(sk_FragColor));
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
bool shouldLoop(vec4 v) {
|
|
return v.x < 0.5;
|
|
}
|
|
void main() {
|
|
sk_FragColor = vec4(0.0);
|
|
do {
|
|
sk_FragColor += vec4(0.125);
|
|
} while (shouldLoop(sk_FragColor));
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinedDoWhileBodyMustBeInAScope, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
half4 adjust(half4 v) {
|
|
return v + half4(0.125);
|
|
}
|
|
void main() {
|
|
sk_FragColor = half4(0);
|
|
do
|
|
sk_FragColor = adjust(sk_FragColor);
|
|
while (sk_FragColor.x < 0.5);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
void main() {
|
|
sk_FragColor = vec4(0.0);
|
|
do {
|
|
vec4 _0_adjust;
|
|
{
|
|
_0_adjust = sk_FragColor + vec4(0.125);
|
|
}
|
|
|
|
sk_FragColor = _0_adjust;
|
|
} while (sk_FragColor.x < 0.5);
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPOnlyForInitializerExpressionsCanBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
half4 initLoopVar() {
|
|
return half4(0.0625);
|
|
}
|
|
bool shouldLoop(half4 v) {
|
|
return v.x < 0.5;
|
|
}
|
|
half4 grow(half4 v) {
|
|
return v + half4(0.125);
|
|
}
|
|
void main() {
|
|
for (sk_FragColor = initLoopVar();
|
|
shouldLoop(sk_FragColor);
|
|
sk_FragColor = grow(sk_FragColor)) {
|
|
}
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
bool shouldLoop(vec4 v) {
|
|
return v.x < 0.5;
|
|
}
|
|
vec4 grow(vec4 v) {
|
|
return v + vec4(0.125);
|
|
}
|
|
void main() {
|
|
for (sk_FragColor = vec4(0.0625);
|
|
shouldLoop(sk_FragColor); sk_FragColor = grow(sk_FragColor)) {
|
|
}
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinedForBodyMustBeInAScope, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
half4 adjust(half4 v) {
|
|
return v + half4(0.125);
|
|
}
|
|
void main() {
|
|
sk_FragColor = half4(0);
|
|
for (int x=0; x<4; ++x)
|
|
sk_FragColor = adjust(sk_FragColor);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
void main() {
|
|
sk_FragColor = vec4(0.0);
|
|
for (int x = 0;x < 4; ++x) {
|
|
vec4 _0_adjust;
|
|
{
|
|
_0_adjust = sk_FragColor + vec4(0.125);
|
|
}
|
|
|
|
sk_FragColor = _0_adjust;
|
|
}
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPIfTestsCanBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
bool ifTest(half4 v) {
|
|
return color.x >= 0.5;
|
|
}
|
|
void main() {
|
|
if (ifTest(color))
|
|
sk_FragColor = half4(1.0);
|
|
else
|
|
sk_FragColor = half4(0.5);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
bool _0_ifTest;
|
|
{
|
|
_0_ifTest = color.x >= 0.5;
|
|
}
|
|
|
|
if (_0_ifTest) sk_FragColor = vec4(1.0); else sk_FragColor = vec4(0.5);
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinedIfBodyMustBeInAScope, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 ifBody() {
|
|
return color + half4(0.125);
|
|
}
|
|
void main() {
|
|
half4 c = color;
|
|
if (c.x >= 0.5)
|
|
c = ifBody();
|
|
sk_FragColor = c;
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 c = color;
|
|
if (c.x >= 0.5) {
|
|
vec4 _0_ifBody;
|
|
{
|
|
_0_ifBody = color + vec4(0.125);
|
|
}
|
|
|
|
c = _0_ifBody;
|
|
}
|
|
sk_FragColor = c;
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinedElseBodyMustBeInAScope, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 elseBody() {
|
|
return color + half4(0.125);
|
|
}
|
|
void main() {
|
|
half4 c = color;
|
|
if (c.x >= 0.5)
|
|
;
|
|
else
|
|
c = elseBody();
|
|
sk_FragColor = c;
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 c = color;
|
|
if (c.x >= 0.5) {
|
|
} else {
|
|
vec4 _0_elseBody;
|
|
{
|
|
_0_elseBody = color + vec4(0.125);
|
|
}
|
|
|
|
c = _0_elseBody;
|
|
}
|
|
sk_FragColor = c;
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPSwitchWithReturnInsideCannotBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 switchy(half4 c) {
|
|
switch (int(c.x)) {
|
|
case 0: return c.yyyy;
|
|
}
|
|
return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_FragColor = switchy(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
vec4 switchy(vec4 c) {
|
|
switch (int(c.x)) {
|
|
case 0:
|
|
return c.yyyy;
|
|
}
|
|
return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_FragColor = switchy(color);
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPSwitchWithoutReturnInsideCanBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 switchy(half4 c) {
|
|
half4 result;
|
|
switch (int(c.x)) {
|
|
case 0: result = c.yyyy;
|
|
}
|
|
result = c.zzzz;
|
|
return result;
|
|
}
|
|
void main() {
|
|
sk_FragColor = switchy(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_switchy;
|
|
{
|
|
vec4 result;
|
|
switch (int(color.x)) {
|
|
case 0:
|
|
result = color.yyyy;
|
|
}
|
|
result = color.zzzz;
|
|
_0_switchy = result;
|
|
}
|
|
|
|
sk_FragColor = _0_switchy;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPForLoopWithReturnInsideCannotBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 loopy(half4 c) {
|
|
for (int x=0; x<5; ++x) {
|
|
if (x == int(c.w)) return c.yyyy;
|
|
}
|
|
return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_FragColor = loopy(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
vec4 loopy(vec4 c) {
|
|
for (int x = 0;x < 5; ++x) {
|
|
if (x == int(c.w)) return c.yyyy;
|
|
}
|
|
return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_FragColor = loopy(color);
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPSwitchWithCastCanBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 switchy(half4 c) {
|
|
half4 result;
|
|
switch (int(c.x)) {
|
|
case 1: result = c.yyyy; break;
|
|
default: result = c.zzzz; break;
|
|
}
|
|
return result;
|
|
}
|
|
void main() {
|
|
sk_FragColor = switchy(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_switchy;
|
|
{
|
|
vec4 result;
|
|
switch (int(color.x)) {
|
|
case 1:
|
|
result = color.yyyy;
|
|
break;
|
|
default:
|
|
result = color.zzzz;
|
|
break;
|
|
}
|
|
_0_switchy = result;
|
|
}
|
|
|
|
sk_FragColor = _0_switchy;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPForLoopWithoutReturnInsideCanBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 loopy(half4 c) {
|
|
half4 pix;
|
|
for (int x=0; x<5; ++x) {
|
|
if (x == int(c.w)) pix = c.yyyy;
|
|
}
|
|
pix = c.zzzz;
|
|
return pix;
|
|
}
|
|
void main() {
|
|
sk_FragColor = loopy(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_loopy;
|
|
{
|
|
vec4 pix;
|
|
for (int x = 0;x < 5; ++x) {
|
|
if (x == int(color.w)) pix = color.yyyy;
|
|
}
|
|
pix = color.zzzz;
|
|
_0_loopy = pix;
|
|
}
|
|
|
|
sk_FragColor = _0_loopy;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinerManglesOverlappingNames, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half add(half a, half b) {
|
|
half c = a + b;
|
|
return c;
|
|
}
|
|
half mul(half a, half b) {
|
|
return a * b;
|
|
}
|
|
half fma(half a, half b, half c) {
|
|
return add(mul(a, b), c);
|
|
}
|
|
half4 main() {
|
|
half a = fma(color.x, color.y, color.z);
|
|
half b = fma(color.y, color.z, color.w);
|
|
half c = fma(color.z, color.w, color.x);
|
|
return half4(a, b, mul(c, c), mul(a, mul(b, c)));
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
uniform vec4 color;
|
|
vec4 main() {
|
|
float _2_fma;
|
|
float _3_a = color.x;
|
|
float _4_b = color.y;
|
|
float _5_c = color.z;
|
|
{
|
|
float _0_mul;
|
|
{
|
|
_0_mul = _3_a * _4_b;
|
|
}
|
|
|
|
float _1_add;
|
|
{
|
|
float c = _0_mul + _5_c;
|
|
_1_add = c;
|
|
}
|
|
|
|
_2_fma = _1_add;
|
|
|
|
}
|
|
|
|
float a = _2_fma;
|
|
|
|
float _6_fma;
|
|
float _7_a = color.y;
|
|
float _8_b = color.z;
|
|
float _9_c = color.w;
|
|
{
|
|
float _0_mul;
|
|
{
|
|
_0_mul = _7_a * _8_b;
|
|
}
|
|
|
|
float _1_add;
|
|
{
|
|
float c = _0_mul + _9_c;
|
|
_1_add = c;
|
|
}
|
|
|
|
_6_fma = _1_add;
|
|
|
|
}
|
|
|
|
float b = _6_fma;
|
|
|
|
float _10_fma;
|
|
float _11_a = color.z;
|
|
float _12_b = color.w;
|
|
float _13_c = color.x;
|
|
{
|
|
float _0_mul;
|
|
{
|
|
_0_mul = _11_a * _12_b;
|
|
}
|
|
|
|
float _1_add;
|
|
{
|
|
float c = _0_mul + _13_c;
|
|
_1_add = c;
|
|
}
|
|
|
|
_10_fma = _1_add;
|
|
|
|
}
|
|
|
|
float c = _10_fma;
|
|
|
|
float _14_mul;
|
|
{
|
|
_14_mul = c * c;
|
|
}
|
|
|
|
float _15_mul;
|
|
{
|
|
_15_mul = b * c;
|
|
}
|
|
|
|
float _16_mul;
|
|
{
|
|
_16_mul = a * _15_mul;
|
|
}
|
|
|
|
return vec4(a, b, _14_mul, _16_mul);
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPIfStatementWithReturnInsideCanBeInlined, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 branchy(half4 c) {
|
|
if (c.z == c.w) return c.yyyy; else return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_FragColor = branchy(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_branchy;
|
|
{
|
|
if (color.z == color.w) _0_branchy = color.yyyy; else _0_branchy = color.zzzz;
|
|
}
|
|
|
|
sk_FragColor = _0_branchy;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPUnnecessaryBlocksDoNotAffectEarlyReturnDetection, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
half4 blocky(half4 c) {
|
|
{
|
|
return c;
|
|
}
|
|
}
|
|
void main() {
|
|
sk_FragColor = blocky(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_blocky;
|
|
{
|
|
{
|
|
_0_blocky = color;
|
|
}
|
|
}
|
|
|
|
sk_FragColor = _0_blocky;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPInlinedEarlyReturnsAreWrappedInDoWhileBlock, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
inline half4 returny(half4 c) {
|
|
if (c.x > c.y) return c.xxxx;
|
|
if (c.y > c.z) return c.yyyy;
|
|
return c.zzzz;
|
|
}
|
|
void main() {
|
|
sk_FragColor = returny(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_returny;
|
|
do {
|
|
if (color.x > color.y) {
|
|
_0_returny = color.xxxx;
|
|
break;
|
|
}
|
|
if (color.y > color.z) {
|
|
_0_returny = color.yyyy;
|
|
break;
|
|
}
|
|
{
|
|
_0_returny = color.zzzz;
|
|
break;
|
|
}
|
|
} while (false);
|
|
|
|
sk_FragColor = _0_returny;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFPEarlyReturnDetectionSupportsIfElse, r) {
|
|
// An if-else statement at the end of a function, with a return as the last statement on all
|
|
// paths, are not actually "early" returns. The inliner is able to recognize this pattern.
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
/*src=*/R"__SkSL__(
|
|
uniform half4 color;
|
|
inline half4 branchy(half4 c) {
|
|
c *= 0.5;
|
|
if (c.x > 0)
|
|
return c.xxxx;
|
|
else if (c.y > 0)
|
|
return c.yyyy;
|
|
else if (c.z > 0)
|
|
return c.zzzz;
|
|
else
|
|
return c.wwww;
|
|
}
|
|
inline half4 branchyAndBlocky(half4 c) {{{
|
|
if (c.x > 0) {
|
|
half4 d = c * 0.5;
|
|
return d.xxxx;
|
|
} else {{{
|
|
if (c.x < 0) {
|
|
return c.wwww;
|
|
} else {
|
|
return c.yyyy;
|
|
}
|
|
}}}
|
|
}}}
|
|
void main() {
|
|
sk_FragColor = branchy(color) * branchyAndBlocky(color);
|
|
}
|
|
)__SkSL__",
|
|
/*expectedGLSL=*/R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform vec4 color;
|
|
void main() {
|
|
vec4 _0_branchy;
|
|
vec4 _1_c = color;
|
|
{
|
|
_1_c *= 0.5;
|
|
if (_1_c.x > 0.0) _0_branchy = _1_c.xxxx; else if (_1_c.y > 0.0) _0_branchy = _1_c.yyyy; else if (_1_c.z > 0.0) _0_branchy = _1_c.zzzz; else _0_branchy = _1_c.wwww;
|
|
}
|
|
|
|
vec4 _2_branchyAndBlocky;
|
|
{
|
|
{
|
|
{
|
|
if (color.x > 0.0) {
|
|
vec4 d = color * 0.5;
|
|
_2_branchyAndBlocky = d.xxxx;
|
|
} else {
|
|
{
|
|
{
|
|
if (color.x < 0.0) {
|
|
_2_branchyAndBlocky = color.wwww;
|
|
} else {
|
|
_2_branchyAndBlocky = color.yyyy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sk_FragColor = _0_branchy * _2_branchyAndBlocky;
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|
|
|
|
DEF_TEST(SkSLFunctionMultipleInlinesOnOneLine, r) {
|
|
test(r,
|
|
*SkSL::ShaderCapsFactory::Default(),
|
|
R"__SkSL__(
|
|
uniform half val;
|
|
inline half BigX(half x) {
|
|
++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;
|
|
--x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x;
|
|
x = 123;
|
|
return x;
|
|
}
|
|
inline half BigY(half x) {
|
|
++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;
|
|
--x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x;
|
|
x = 456;
|
|
return x;
|
|
}
|
|
void main() {
|
|
sk_FragColor = BigX(BigY(val)).xxxx;
|
|
}
|
|
)__SkSL__",
|
|
R"__GLSL__(#version 400
|
|
out vec4 sk_FragColor;
|
|
uniform float val;
|
|
void main() {
|
|
float _1_x = val;
|
|
{
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
++_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
--_1_x;
|
|
_1_x = 456.0;
|
|
}
|
|
|
|
float _3_x = 456.0;
|
|
{
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
++_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
--_3_x;
|
|
_3_x = 123.0;
|
|
}
|
|
|
|
sk_FragColor = vec4(123.0);
|
|
|
|
}
|
|
)__GLSL__");
|
|
}
|