Rewrite switch statements in GLSL strict-ES2 mode.
Once this lands, switch statements will work everywhere--Metal, SPIR-V, GLSL, and SkVM. Change-Id: I2797d0a872de8be77bb9f7aa6acb93421d571d70 Bug: skia:12450 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/452356 Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
4144211e06
commit
45e3838006
@ -176,6 +176,10 @@ sksl_glsl_tests = [
|
||||
"/sksl/glsl/UsesPrecisionModifiers.sksl",
|
||||
"/sksl/glsl/Version110.sksl",
|
||||
"/sksl/glsl/Version450Core.sksl",
|
||||
"/sksl/runtime/Switch.rts",
|
||||
"/sksl/runtime/SwitchDefaultOnly.rts",
|
||||
"/sksl/runtime/SwitchWithFallthrough.rts",
|
||||
"/sksl/runtime/SwitchWithLoops.rts",
|
||||
]
|
||||
|
||||
sksl_metal_tests = [
|
||||
|
@ -1355,8 +1355,66 @@ void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
|
||||
|
||||
void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
|
||||
if (fProgram.fConfig->strictES2Mode()) {
|
||||
// TODO(skia:12450): write switch compatibility code
|
||||
fContext.fErrors->error(s.fOffset, "switch statements are not supported");
|
||||
String fallthroughVar = "_tmpSwitchFallthrough" + to_string(fVarCount++);
|
||||
String valueVar = "_tmpSwitchValue" + to_string(fVarCount++);
|
||||
String loopVar = "_tmpSwitchLoop" + to_string(fVarCount++);
|
||||
this->write("int ");
|
||||
this->write(valueVar);
|
||||
this->write(" = ");
|
||||
this->writeExpression(*s.value(), Precedence::kAssignment);
|
||||
this->write(", ");
|
||||
this->write(fallthroughVar);
|
||||
this->writeLine(" = 0; ");
|
||||
this->write("for (int ");
|
||||
this->write(loopVar);
|
||||
this->write(" = 0; ");
|
||||
this->write(loopVar);
|
||||
this->write(" < 1; ");
|
||||
this->write(loopVar);
|
||||
this->writeLine("++) {");
|
||||
fIndentation++;
|
||||
|
||||
bool firstCase = true;
|
||||
for (const std::unique_ptr<Statement>& stmt : s.cases()) {
|
||||
const SwitchCase& c = stmt->as<SwitchCase>();
|
||||
if (c.value()) {
|
||||
this->write("if ((");
|
||||
if (firstCase) {
|
||||
firstCase = false;
|
||||
} else {
|
||||
this->write(fallthroughVar);
|
||||
this->write(" > 0) || (");
|
||||
}
|
||||
this->write(valueVar);
|
||||
this->write(" == ");
|
||||
this->writeExpression(*c.value(), Precedence::kEquality);
|
||||
this->writeLine(")) {");
|
||||
fIndentation++;
|
||||
|
||||
// We write the entire case-block statement here, and then set `switchFallthrough`
|
||||
// to 1. If the case-block had a break statement in it, we break out of the outer
|
||||
// for-loop entirely, meaning the `switchFallthrough` assignment never occurs, nor
|
||||
// does any code after it inside the switch. We've forbidden `continue` statements
|
||||
// inside switch case-blocks entirely, so we don't need to consider their effect on
|
||||
// control flow; see the Finalizer in FunctionDefinition::Convert.
|
||||
this->writeStatement(*c.statement());
|
||||
this->finishLine();
|
||||
this->write(fallthroughVar);
|
||||
this->write(" = 1;");
|
||||
this->writeLine();
|
||||
|
||||
fIndentation--;
|
||||
this->writeLine("}");
|
||||
} else {
|
||||
// This is the default case. Since it's always last, we can just dump in the code.
|
||||
this->writeStatement(*c.statement());
|
||||
this->finishLine();
|
||||
}
|
||||
}
|
||||
|
||||
fIndentation--;
|
||||
this->writeLine("}");
|
||||
return;
|
||||
}
|
||||
|
||||
this->write("switch (");
|
||||
|
@ -323,10 +323,10 @@ SKSL_TEST(SkSLStaticIf, "shared/StaticIf.sksl")
|
||||
SKSL_TEST_ES3(SkSLStaticSwitch, "shared/StaticSwitch.sksl")
|
||||
SKSL_TEST(SkSLStructArrayFollowedByScalar, "shared/StructArrayFollowedByScalar.sksl")
|
||||
SKSL_TEST(SkSLStructsInFunctions, "shared/StructsInFunctions.sksl")
|
||||
SKSL_TEST_ES3(SkSLSwitch, "shared/Switch.sksl")
|
||||
SKSL_TEST_ES3(SkSLSwitchDefaultOnly, "shared/SwitchDefaultOnly.sksl")
|
||||
SKSL_TEST_ES3(SkSLSwitchWithFallthrough, "shared/SwitchWithFallthrough.sksl")
|
||||
SKSL_TEST_ES3(SkSLSwitchWithLoops, "shared/SwitchWithLoops.sksl")
|
||||
SKSL_TEST(SkSLSwitch, "shared/Switch.sksl")
|
||||
SKSL_TEST(SkSLSwitchDefaultOnly, "shared/SwitchDefaultOnly.sksl")
|
||||
SKSL_TEST(SkSLSwitchWithFallthrough, "shared/SwitchWithFallthrough.sksl")
|
||||
SKSL_TEST(SkSLSwitchWithLoops, "shared/SwitchWithLoops.sksl")
|
||||
SKSL_TEST(SkSLSwizzleBoolConstants, "shared/SwizzleBoolConstants.sksl")
|
||||
SKSL_TEST(SkSLSwizzleByConstantIndex, "shared/SwizzleByConstantIndex.sksl")
|
||||
SKSL_TEST(SkSLSwizzleConstants, "shared/SwizzleConstants.sksl")
|
||||
|
22
tests/sksl/runtime/Switch.glsl
Normal file
22
tests/sksl/runtime/Switch.glsl
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
vec4 main() {
|
||||
vec4 color;
|
||||
int _tmpSwitchValue1 = int(colorGreen.y), _tmpSwitchFallthrough0 = 0;
|
||||
for (int _tmpSwitchLoop2 = 0; _tmpSwitchLoop2 < 1; _tmpSwitchLoop2++) {
|
||||
if ((_tmpSwitchValue1 == 0)) {
|
||||
color = colorRed;
|
||||
break;
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
if ((_tmpSwitchFallthrough0 > 0) || (_tmpSwitchValue1 == 1)) {
|
||||
color = colorGreen;
|
||||
break;
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
color = colorRed;
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
}
|
9
tests/sksl/runtime/SwitchDefaultOnly.glsl
Normal file
9
tests/sksl/runtime/SwitchDefaultOnly.glsl
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
vec4 main() {
|
||||
int _tmpSwitchValue1 = int(colorGreen.y), _tmpSwitchFallthrough0 = 0;
|
||||
for (int _tmpSwitchLoop2 = 0; _tmpSwitchLoop2 < 1; _tmpSwitchLoop2++) {
|
||||
return colorGreen;
|
||||
}
|
||||
}
|
53
tests/sksl/runtime/SwitchWithFallthrough.glsl
Normal file
53
tests/sksl/runtime/SwitchWithFallthrough.glsl
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
bool switch_fallthrough_twice_bi(int value) {
|
||||
bool ok = false;
|
||||
int _tmpSwitchValue1 = value, _tmpSwitchFallthrough0 = 0;
|
||||
for (int _tmpSwitchLoop2 = 0; _tmpSwitchLoop2 < 1; _tmpSwitchLoop2++) {
|
||||
if ((_tmpSwitchValue1 == 0)) {
|
||||
break;
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
if ((_tmpSwitchFallthrough0 > 0) || (_tmpSwitchValue1 == 1)) {
|
||||
{
|
||||
}
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
if ((_tmpSwitchFallthrough0 > 0) || (_tmpSwitchValue1 == 2)) {
|
||||
{
|
||||
}
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
if ((_tmpSwitchFallthrough0 > 0) || (_tmpSwitchValue1 == 3)) {
|
||||
ok = true;
|
||||
break;
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
vec4 main() {
|
||||
int x = int(colorGreen.y);
|
||||
bool _0_ok = false;
|
||||
int _tmpSwitchValue4 = x, _tmpSwitchFallthrough3 = 0;
|
||||
for (int _tmpSwitchLoop5 = 0; _tmpSwitchLoop5 < 1; _tmpSwitchLoop5++) {
|
||||
if ((_tmpSwitchValue4 == 2)) {
|
||||
break;
|
||||
_tmpSwitchFallthrough3 = 1;
|
||||
}
|
||||
if ((_tmpSwitchFallthrough3 > 0) || (_tmpSwitchValue4 == 1)) {
|
||||
{
|
||||
}
|
||||
_tmpSwitchFallthrough3 = 1;
|
||||
}
|
||||
if ((_tmpSwitchFallthrough3 > 0) || (_tmpSwitchValue4 == 0)) {
|
||||
_0_ok = true;
|
||||
break;
|
||||
_tmpSwitchFallthrough3 = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return _0_ok && switch_fallthrough_twice_bi(x) ? colorGreen : colorRed;
|
||||
}
|
52
tests/sksl/runtime/SwitchWithLoops.glsl
Normal file
52
tests/sksl/runtime/SwitchWithLoops.glsl
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
bool switch_with_continue_in_loop_bi(int x) {
|
||||
int val = 0;
|
||||
int _tmpSwitchValue1 = x, _tmpSwitchFallthrough0 = 0;
|
||||
for (int _tmpSwitchLoop2 = 0; _tmpSwitchLoop2 < 1; _tmpSwitchLoop2++) {
|
||||
if ((_tmpSwitchValue1 == 1)) {
|
||||
for (int i = 0;i < 10; ++i) {
|
||||
++val;
|
||||
continue;
|
||||
++val;
|
||||
}
|
||||
_tmpSwitchFallthrough0 = 1;
|
||||
}
|
||||
++val;
|
||||
}
|
||||
return val == 11;
|
||||
}
|
||||
bool loop_with_break_in_switch_bi(int x) {
|
||||
int val = 0;
|
||||
for (int i = 0;i < 10; ++i) {
|
||||
int _tmpSwitchValue4 = x, _tmpSwitchFallthrough3 = 0;
|
||||
for (int _tmpSwitchLoop5 = 0; _tmpSwitchLoop5 < 1; _tmpSwitchLoop5++) {
|
||||
if ((_tmpSwitchValue4 == 1)) {
|
||||
++val;
|
||||
break;
|
||||
_tmpSwitchFallthrough3 = 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
++val;
|
||||
}
|
||||
return val == 20;
|
||||
}
|
||||
vec4 main() {
|
||||
int x = int(colorGreen.y);
|
||||
int _0_val = 0;
|
||||
int _tmpSwitchValue7 = x, _tmpSwitchFallthrough6 = 0;
|
||||
for (int _tmpSwitchLoop8 = 0; _tmpSwitchLoop8 < 1; _tmpSwitchLoop8++) {
|
||||
if ((_tmpSwitchValue7 == 1)) {
|
||||
for (int _1_i = 0;_1_i < 10; ++_1_i) {
|
||||
++_0_val;
|
||||
break;
|
||||
++_0_val;
|
||||
}
|
||||
_tmpSwitchFallthrough6 = 1;
|
||||
}
|
||||
++_0_val;
|
||||
}
|
||||
return (_0_val == 2 && switch_with_continue_in_loop_bi(x)) && loop_with_break_in_switch_bi(x) ? colorGreen : colorRed;
|
||||
}
|
Loading…
Reference in New Issue
Block a user