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>
This commit is contained in:
parent
f62934b85a
commit
be056f4f62
@ -556,6 +556,7 @@ sksl_rte_tests = [
|
||||
"/sksl/runtime/LoopFloat.rts",
|
||||
"/sksl/runtime/PrecisionQualifiers.rts",
|
||||
"/sksl/runtime/SampleWithExplicitCoord.rts",
|
||||
"/sksl/runtime/Switch.rts",
|
||||
"/sksl/runtime/VectorIndexing.rts",
|
||||
]
|
||||
|
||||
|
15
resources/sksl/runtime/Switch.rts
Normal file
15
resources/sksl/runtime/Switch.rts
Normal file
@ -0,0 +1,15 @@
|
||||
uniform half4 colorGreen, colorRed;
|
||||
|
||||
half4 main(float2 coords) {
|
||||
// Basic switch test.
|
||||
switch (int(colorGreen.g)) {
|
||||
case 0:
|
||||
return colorRed;
|
||||
|
||||
case 1:
|
||||
return colorGreen;
|
||||
|
||||
default:
|
||||
return colorRed;
|
||||
}
|
||||
}
|
@ -1,17 +1,15 @@
|
||||
uniform float unknownInput;
|
||||
uniform half4 colorGreen, colorRed;
|
||||
|
||||
void main() {
|
||||
half4 main(float2 coords) {
|
||||
// Basic switch test.
|
||||
half value;
|
||||
switch (int(unknownInput)) {
|
||||
switch (int(colorGreen.g)) {
|
||||
case 0:
|
||||
value = 0.0;
|
||||
break;
|
||||
return colorRed;
|
||||
|
||||
case 1:
|
||||
value = 1.0;
|
||||
break;
|
||||
return colorGreen;
|
||||
|
||||
default:
|
||||
value = 2.0;
|
||||
return colorRed;
|
||||
}
|
||||
sk_FragColor = value.xxxx;
|
||||
}
|
||||
|
@ -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 @@ private:
|
||||
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 @@ void PipelineStageCodeGenerator::writeReturnStatement(const ReturnStatement& r)
|
||||
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 @@ void PipelineStageCodeGenerator::writeStatement(const Statement& s) {
|
||||
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:
|
||||
|
@ -323,6 +323,7 @@ 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(SkSLSwizzleBoolConstants, "shared/SwizzleBoolConstants.sksl")
|
||||
SKSL_TEST(SkSLSwizzleByConstantIndex, "shared/SwizzleByConstantIndex.sksl")
|
||||
SKSL_TEST(SkSLSwizzleConstants, "shared/SwizzleConstants.sksl")
|
||||
|
5
tests/sksl/runtime/Switch.skvm
Normal file
5
tests/sksl/runtime/Switch.skvm
Normal file
@ -0,0 +1,5 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 5: switch statements are not supported
|
||||
error: 3: function 'main' can exit without returning a value
|
||||
2 errors
|
5
tests/sksl/runtime/Switch.stage
Normal file
5
tests/sksl/runtime/Switch.stage
Normal file
@ -0,0 +1,5 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 5: switch statements are not supported
|
||||
error: 3: function 'main' can exit without returning a value
|
||||
2 errors
|
@ -1,25 +1,31 @@
|
||||
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"
|
||||
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 %30 RelaxedPrecision
|
||||
OpDecorate %31 RelaxedPrecision
|
||||
OpDecorate %32 RelaxedPrecision
|
||||
OpDecorate %39 RelaxedPrecision
|
||||
OpDecorate %41 RelaxedPrecision
|
||||
OpDecorate %43 RelaxedPrecision
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
@ -27,38 +33,49 @@ OpDecorate %32 RelaxedPrecision
|
||||
%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_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
|
||||
%26 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
|
||||
%30 = OpLoad %v4float %26
|
||||
%31 = OpCompositeExtract %float %30 1
|
||||
%32 = OpConvertFToS %int %31
|
||||
OpSelectionMerge %33 None
|
||||
OpSwitch %32 %36 0 %34 1 %35
|
||||
%34 = OpLabel
|
||||
%37 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
|
||||
%39 = OpLoad %v4float %37
|
||||
OpReturnValue %39
|
||||
%35 = OpLabel
|
||||
%40 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
|
||||
%41 = OpLoad %v4float %40
|
||||
OpReturnValue %41
|
||||
%36 = OpLabel
|
||||
%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
|
||||
%43 = OpLoad %v4float %42
|
||||
OpReturnValue %43
|
||||
%33 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
|
@ -1,17 +1,14 @@
|
||||
|
||||
out vec4 sk_FragColor;
|
||||
uniform float unknownInput;
|
||||
void main() {
|
||||
float value;
|
||||
switch (int(unknownInput)) {
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
vec4 main() {
|
||||
switch (int(colorGreen.y)) {
|
||||
case 0:
|
||||
value = 0.0;
|
||||
break;
|
||||
return colorRed;
|
||||
case 1:
|
||||
value = 1.0;
|
||||
break;
|
||||
return colorGreen;
|
||||
default:
|
||||
value = 2.0;
|
||||
return colorRed;
|
||||
}
|
||||
sk_FragColor = vec4(value);
|
||||
}
|
||||
|
@ -2,7 +2,8 @@
|
||||
#include <simd/simd.h>
|
||||
using namespace metal;
|
||||
struct Uniforms {
|
||||
float unknownInput;
|
||||
float4 colorGreen;
|
||||
float4 colorRed;
|
||||
};
|
||||
struct Inputs {
|
||||
};
|
||||
@ -12,17 +13,16 @@ struct Outputs {
|
||||
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)) {
|
||||
switch (int(_uniforms.colorGreen.y)) {
|
||||
case 0:
|
||||
value = 0.0;
|
||||
break;
|
||||
_out.sk_FragColor = _uniforms.colorRed;
|
||||
return _out;
|
||||
case 1:
|
||||
value = 1.0;
|
||||
break;
|
||||
_out.sk_FragColor = _uniforms.colorGreen;
|
||||
return _out;
|
||||
default:
|
||||
value = 2.0;
|
||||
_out.sk_FragColor = _uniforms.colorRed;
|
||||
return _out;
|
||||
}
|
||||
_out.sk_FragColor = float4(value);
|
||||
return _out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user