Reland "Add switch statement support to PipelineStage."
This is a reland of be056f4f62de76c3f3d6ffb2321bf6592841dc46
The Switch test has been restructured to dodge an iOS bug.
Original change's description:
> Add switch statement support to PipelineStage.
>
> This allows us to write SKSL_TEST_ES3 tests in SkSLTest and have them
> run properly. Previously, such a test would assert inside the pipeline-
> stage generator. In ES2 mode, we will rewrite switches as chained ifs,
> but in ES3 mode we will want to continue emitting them as-is (they will
> be faster than chained ifs on a modern GPU).
>
> `writeSwitchStatement` is adapted from GLSLCodeGenerator.
>
> Change-Id: I532ea5ed49869e7cdffced0cdcd0e353af8d4d79
> Bug: skia:12450
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/450478
> Commit-Queue: John Stiles <johnstiles@google.com>
> Commit-Queue: Brian Osman <brianosman@google.com>
> Auto-Submit: John Stiles <johnstiles@google.com>
> Reviewed-by: Brian Osman <brianosman@google.com>
Bug: skia:12450
Change-Id: I5102081c636ef09cd23f5bc894e6c96e92a4c121
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/450757
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 098a7c6..5a18df9 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -556,6 +556,7 @@
"/sksl/runtime/LoopFloat.rts",
"/sksl/runtime/PrecisionQualifiers.rts",
"/sksl/runtime/SampleWithExplicitCoord.rts",
+ "/sksl/runtime/Switch.rts",
"/sksl/runtime/VectorIndexing.rts",
]
diff --git a/resources/sksl/runtime/Switch.rts b/resources/sksl/runtime/Switch.rts
new file mode 100644
index 0000000..bb54a5c
--- /dev/null
+++ b/resources/sksl/runtime/Switch.rts
@@ -0,0 +1,18 @@
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+ // Basic switch test.
+ half4 color;
+ switch (int(colorGreen.g)) {
+ case 0:
+ color = colorRed;
+ break;
+ case 1:
+ color = colorGreen;
+ break;
+ default:
+ color = colorRed;
+ break;
+ }
+ return color;
+}
diff --git a/resources/sksl/shared/Switch.sksl b/resources/sksl/shared/Switch.sksl
index deabebc..bb54a5c 100644
--- a/resources/sksl/shared/Switch.sksl
+++ b/resources/sksl/shared/Switch.sksl
@@ -1,17 +1,18 @@
-uniform float unknownInput;
+uniform half4 colorGreen, colorRed;
-void main() {
+half4 main(float2 coords) {
// Basic switch test.
- half value;
- switch (int(unknownInput)) {
+ half4 color;
+ switch (int(colorGreen.g)) {
case 0:
- value = 0.0;
+ color = colorRed;
break;
case 1:
- value = 1.0;
+ color = colorGreen;
break;
default:
- value = 2.0;
+ color = colorRed;
+ break;
}
- sk_FragColor = value.xxxx;
+ return color;
}
diff --git a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
index fed3718..9e7bcdd 100644
--- a/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLPipelineStageCodeGenerator.cpp
@@ -30,6 +30,7 @@
#include "src/sksl/ir/SkSLPrefixExpression.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLStructDefinition.h"
+#include "src/sksl/ir/SkSLSwitchStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
@@ -98,6 +99,7 @@
void writeDoStatement(const DoStatement& d);
void writeForStatement(const ForStatement& f);
void writeReturnStatement(const ReturnStatement& r);
+ void writeSwitchStatement(const SwitchStatement& s);
void writeProgramElement(const ProgramElement& e);
@@ -277,6 +279,28 @@
this->write(";");
}
+void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
+ this->write("switch (");
+ this->writeExpression(*s.value(), Precedence::kTopLevel);
+ this->writeLine(") {");
+ for (const std::unique_ptr<Statement>& stmt : s.cases()) {
+ const SwitchCase& c = stmt->as<SwitchCase>();
+ if (c.value()) {
+ this->write("case ");
+ this->writeExpression(*c.value(), Precedence::kTopLevel);
+ this->writeLine(":");
+ } else {
+ this->writeLine("default:");
+ }
+ if (!c.statement()->isEmpty()) {
+ this->writeStatement(*c.statement());
+ this->writeLine();
+ }
+ }
+ this->writeLine();
+ this->write("}");
+}
+
String PipelineStageCodeGenerator::functionName(const FunctionDeclaration& decl) {
if (decl.isMain()) {
return String(decl.name());
@@ -637,11 +661,13 @@
case Statement::Kind::kReturn:
this->writeReturnStatement(s.as<ReturnStatement>());
break;
+ case Statement::Kind::kSwitch:
+ this->writeSwitchStatement(s.as<SwitchStatement>());
+ break;
case Statement::Kind::kVarDeclaration:
this->writeVarDeclaration(s.as<VarDeclaration>());
break;
case Statement::Kind::kDiscard:
- case Statement::Kind::kSwitch:
SkDEBUGFAIL("Unsupported control flow");
break;
case Statement::Kind::kInlineMarker:
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index 53843c5..c167ebe 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -323,6 +323,7 @@
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(SkSLSwizzleBoolConstants, "shared/SwizzleBoolConstants.sksl")
SKSL_TEST(SkSLSwizzleByConstantIndex, "shared/SwizzleByConstantIndex.sksl")
SKSL_TEST(SkSLSwizzleConstants, "shared/SwizzleConstants.sksl")
diff --git a/tests/sksl/runtime/Switch.skvm b/tests/sksl/runtime/Switch.skvm
new file mode 100644
index 0000000..9df38e1
--- /dev/null
+++ b/tests/sksl/runtime/Switch.skvm
@@ -0,0 +1,4 @@
+### Compilation failed:
+
+error: 6: switch statements are not supported
+1 error
diff --git a/tests/sksl/runtime/Switch.stage b/tests/sksl/runtime/Switch.stage
new file mode 100644
index 0000000..9df38e1
--- /dev/null
+++ b/tests/sksl/runtime/Switch.stage
@@ -0,0 +1,4 @@
+### Compilation failed:
+
+error: 6: switch statements are not supported
+1 error
diff --git a/tests/sksl/shared/Switch.asm.frag b/tests/sksl/shared/Switch.asm.frag
index ed5beb9..60559ea 100644
--- a/tests/sksl/shared/Switch.asm.frag
+++ b/tests/sksl/shared/Switch.asm.frag
@@ -1,25 +1,34 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
OpName %sk_FragColor "sk_FragColor"
OpName %sk_Clockwise "sk_Clockwise"
OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "unknownInput"
+OpMemberName %_UniformBuffer 0 "colorGreen"
+OpMemberName %_UniformBuffer 1 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
OpName %main "main"
-OpName %value "value"
+OpName %color "color"
OpDecorate %sk_FragColor RelaxedPrecision
OpDecorate %sk_FragColor Location 0
OpDecorate %sk_FragColor Index 0
OpDecorate %sk_Clockwise BuiltIn FrontFacing
OpMemberDecorate %_UniformBuffer 0 Offset 0
+OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
OpDecorate %_UniformBuffer Block
OpDecorate %10 Binding 0
OpDecorate %10 DescriptorSet 0
-OpDecorate %value RelaxedPrecision
-OpDecorate %31 RelaxedPrecision
+OpDecorate %color RelaxedPrecision
OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %45 RelaxedPrecision
+OpDecorate %46 RelaxedPrecision
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -27,38 +36,55 @@
%bool = OpTypeBool
%_ptr_Input_bool = OpTypePointer Input %bool
%sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float
%_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
%10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
%void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Function_float = OpTypePointer Function %float
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
-%float_0 = OpConstant %float 0
-%float_1 = OpConstant %float 1
-%float_2 = OpConstant %float 2
-%main = OpFunction %void None %14
-%15 = OpLabel
-%value = OpVariable %_ptr_Function_float Function
-%18 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%22 = OpLoad %float %18
-%23 = OpConvertFToS %int %22
-OpSelectionMerge %24 None
-OpSwitch %23 %27 0 %25 1 %26
-%25 = OpLabel
-OpStore %value %float_0
-OpBranch %24
-%26 = OpLabel
-OpStore %value %float_1
-OpBranch %24
-%27 = OpLabel
-OpStore %value %float_2
-OpBranch %24
-%24 = OpLabel
-%31 = OpLoad %float %value
-%32 = OpCompositeConstruct %v4float %31 %31 %31 %31
-OpStore %sk_FragColor %32
+%int_1 = OpConstant %int 1
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
OpReturn
OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%color = OpVariable %_ptr_Function_v4float Function
+%28 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%32 = OpLoad %v4float %28
+%33 = OpCompositeExtract %float %32 1
+%34 = OpConvertFToS %int %33
+OpSelectionMerge %35 None
+OpSwitch %34 %38 0 %36 1 %37
+%36 = OpLabel
+%39 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%41 = OpLoad %v4float %39
+OpStore %color %41
+OpBranch %35
+%37 = OpLabel
+%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%43 = OpLoad %v4float %42
+OpStore %color %43
+OpBranch %35
+%38 = OpLabel
+%44 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%45 = OpLoad %v4float %44
+OpStore %color %45
+OpBranch %35
+%35 = OpLabel
+%46 = OpLoad %v4float %color
+OpReturnValue %46
+OpFunctionEnd
diff --git a/tests/sksl/shared/Switch.glsl b/tests/sksl/shared/Switch.glsl
index 39b48e2..93d9818 100644
--- a/tests/sksl/shared/Switch.glsl
+++ b/tests/sksl/shared/Switch.glsl
@@ -1,17 +1,19 @@
out vec4 sk_FragColor;
-uniform float unknownInput;
-void main() {
- float value;
- switch (int(unknownInput)) {
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+ vec4 color;
+ switch (int(colorGreen.y)) {
case 0:
- value = 0.0;
+ color = colorRed;
break;
case 1:
- value = 1.0;
+ color = colorGreen;
break;
default:
- value = 2.0;
+ color = colorRed;
+ break;
}
- sk_FragColor = vec4(value);
+ return color;
}
diff --git a/tests/sksl/shared/Switch.metal b/tests/sksl/shared/Switch.metal
index fcc6674..16aad7f 100644
--- a/tests/sksl/shared/Switch.metal
+++ b/tests/sksl/shared/Switch.metal
@@ -2,7 +2,8 @@
#include <simd/simd.h>
using namespace metal;
struct Uniforms {
- float unknownInput;
+ float4 colorGreen;
+ float4 colorRed;
};
struct Inputs {
};
@@ -12,17 +13,18 @@
fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
Outputs _out;
(void)_out;
- float value;
- switch (int(_uniforms.unknownInput)) {
+ float4 color;
+ switch (int(_uniforms.colorGreen.y)) {
case 0:
- value = 0.0;
+ color = _uniforms.colorRed;
break;
case 1:
- value = 1.0;
+ color = _uniforms.colorGreen;
break;
default:
- value = 2.0;
+ color = _uniforms.colorRed;
+ break;
}
- _out.sk_FragColor = float4(value);
+ _out.sk_FragColor = color;
return _out;
}