Detect alpha-preservation in ternary expressions.
It occurred to me that this was fairly easy to check. I'm not sure if
any of our shaders would actually exercise this path.
Change-Id: Iab22688b00a2d55333717f4ea9a0d92cc8e5e756
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/665857
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/analysis/SkSLReturnsInputAlpha.cpp b/src/sksl/analysis/SkSLReturnsInputAlpha.cpp
index 17a5dea..2a6d977 100644
--- a/src/sksl/analysis/SkSLReturnsInputAlpha.cpp
+++ b/src/sksl/analysis/SkSLReturnsInputAlpha.cpp
@@ -21,6 +21,7 @@
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
+#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVariable.h"
#include "src/sksl/ir/SkSLVariableReference.h"
@@ -69,11 +70,11 @@
return true;
}
if (expr.is<Swizzle>()) {
- // It's a swizzle: `input.___a`.
+ // It's a swizzle: check for `input.___a`.
return this->isInputSwizzleEndingWithAlpha(expr);
}
if (expr.is<ConstructorSplat>() || expr.is<ConstructorCompound>()) {
- // This is a splat or compound constructor with `input.a` as its final component.
+ // This is a splat or compound constructor; check for `input.a` as its final component.
const AnyConstructor& ctor = expr.asAnyConstructor();
return this->returnsInputAlpha(*ctor.argumentSpan().back());
}
@@ -82,6 +83,12 @@
const Expression& arg = *expr.as<ConstructorCompoundCast>().argument();
return arg.type().componentType().isFloat() && this->returnsInputAlpha(arg);
}
+ if (expr.is<TernaryExpression>()) {
+ // Both sides of the ternary must preserve input alpha.
+ const TernaryExpression& ternary = expr.as<TernaryExpression>();
+ return this->returnsInputAlpha(*ternary.ifTrue()) &&
+ this->returnsInputAlpha(*ternary.ifFalse());
+ }
// We weren't able to pattern-match here.
return false;
}
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index f6754bd..4da4066 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -1401,7 +1401,11 @@
expectAlphaUnchanged("half4 main(half4 color) { return half4(half2(1), half2(color.a)); }");
expectAlphaUnchanged("half4 main(half4 color) { return half4(color.a); }");
expectAlphaUnchanged("half4 main(half4 color) { return half4(float4(color.baba)); }");
-
+ expectAlphaUnchanged("half4 main(half4 color) { return color.r != color.g ? color :"
+ " color.000a; }");
+ expectAlphaUnchanged("half4 main(half4 color) { return color.a == color.r ? color.rrra : "
+ "color.g == color.b ? color.ggga : "
+ " color.bbba; }");
// These swizzles don't end in alpha.
expectAlphaChanged("half4 main(half4 color) { return color.argb; }");
expectAlphaChanged("half4 main(half4 color) { return color.rrrr; }");
@@ -1412,6 +1416,11 @@
// This splat constructor doesn't use alpha.
expectAlphaChanged("half4 main(half4 color) { return half4(color.r); }");
+ // These ternaries don't return alpha on both sides
+ expectAlphaChanged("half4 main(half4 color) { return color.a > 0 ? half4(0) : color; }");
+ expectAlphaChanged("half4 main(half4 color) { return color.g < 1 ? color.bgra : color.abgr; }");
+ expectAlphaChanged("half4 main(half4 color) { return color.b > 0.5 ? half4(0) : half4(1); }");
+
// Performing arithmetic on the input causes it to report as "alpha changed" even if the
// arithmetic is a no-op; we aren't smart enough to see through it.
expectAlphaChanged("half4 main(half4 color) { return color + half4(1,1,1,0); }");