Add general three-stop analytic gradient shader
This fixes an Android rendering bug where radial gradients were being used
for "clipping" (via DstIn blend mode). The gradient stops were placed at
(0, 0.999, 1), which caused our table quantization to drop the last stop.
kThree_ColorType now means "0, any t, 1". The old (special-case)
kThree_ColorType is now called kSymmetricThree_ColorType.
Bug: skia:
Change-Id: I96a0b9e679f2d537862a3e097f7e3446474914ea
Reviewed-on: https://skia-review.googlesource.com/45260
Reviewed-by: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index 64d3b48..45f25cd 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -1312,6 +1312,7 @@
case GrGradientEffect::kTwo_ColorType:
return 2;
case GrGradientEffect::kThree_ColorType:
+ case GrGradientEffect::kSymmetricThree_ColorType:
return 3;
case GrGradientEffect::kTexture_ColorType:
return 0;
@@ -1348,9 +1349,9 @@
if (2 == shader.fColorCount) {
return kTwo_ColorType;
- } else if (3 == shader.fColorCount &&
- close_to_one_half(shader.getRecs()[1].fPos)) {
- return kThree_ColorType;
+ } else if (3 == shader.fColorCount) {
+ return close_to_one_half(shader.getRecs()[1].fPos) ? kSymmetricThree_ColorType
+ : kThree_ColorType;
}
return kTexture_ColorType;
@@ -1364,9 +1365,9 @@
kDefault_GrSLPrecision,
"Colors",
colorCount);
- if (ge.fColorType == kSingleHardStop_ColorType) {
- fHardStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
- kDefault_GrSLPrecision, "HardStopT");
+ if (kSingleHardStop_ColorType == ge.fColorType || kThree_ColorType == ge.fColorType) {
+ fExtraStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
+ kDefault_GrSLPrecision, "ExtraStopT");
}
} else {
fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
@@ -1468,12 +1469,13 @@
switch (e.getColorType()) {
case GrGradientEffect::kSingleHardStop_ColorType:
- pdman.set1f(fHardStopT, e.fPositions[1]);
+ case GrGradientEffect::kThree_ColorType:
+ pdman.set1f(fExtraStopT, e.fPositions[1]);
// fall through
case GrGradientEffect::kHardStopLeftEdged_ColorType:
case GrGradientEffect::kHardStopRightEdged_ColorType:
case GrGradientEffect::kTwo_ColorType:
- case GrGradientEffect::kThree_ColorType: {
+ case GrGradientEffect::kSymmetricThree_ColorType: {
if (e.fColors4f.count() > 0) {
// Gamma-correct / color-space aware
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
@@ -1522,6 +1524,8 @@
key |= kTwoColorKey;
} else if (GrGradientEffect::kThree_ColorType == e.getColorType()) {
key |= kThreeColorKey;
+ } else if (GrGradientEffect::kSymmetricThree_ColorType == e.getColorType()) {
+ key |= kSymmetricThreeColorKey;
} else if (GrGradientEffect::kSingleHardStop_ColorType == e.getColorType()) {
key |= kHardStopCenteredKey;
} else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) {
@@ -1572,7 +1576,7 @@
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
switch (ge.getColorType()) {
case kSingleHardStop_ColorType: {
- const char* stopT = uniformHandler->getUniformCStr(fHardStopT);
+ const char* stopT = uniformHandler->getUniformCStr(fExtraStopT);
fragBuilder->codeAppend ("float4 start, end;");
fragBuilder->codeAppend ("float relative_t;");
@@ -1622,6 +1626,25 @@
}
case kThree_ColorType: {
+ const char* stopT = uniformHandler->getUniformCStr(fExtraStopT);
+
+ fragBuilder->codeAppend("float4 start, end;");
+ fragBuilder->codeAppend("float relative_t;");
+ fragBuilder->codeAppendf("if (clamp_t < %s) {", stopT);
+ fragBuilder->codeAppendf(" start = %s[0];", colors);
+ fragBuilder->codeAppendf(" end = %s[1];", colors);
+ fragBuilder->codeAppendf(" relative_t = clamp_t / %s;", stopT);
+ fragBuilder->codeAppend("} else {");
+ fragBuilder->codeAppendf(" start = %s[1];", colors);
+ fragBuilder->codeAppendf(" end = %s[2];", colors);
+ fragBuilder->codeAppendf(" relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT);
+ fragBuilder->codeAppend("}");
+ fragBuilder->codeAppend("float4 colorTemp = mix(start, end, relative_t);");
+
+ break;
+ }
+
+ case kSymmetricThree_ColorType: {
fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * clamp_t);");
fragBuilder->codeAppendf("float4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];",
colors);
@@ -1715,6 +1738,7 @@
// The two and three color specializations do not currently support tiling.
case kTwo_ColorType:
case kThree_ColorType:
+ case kSymmetricThree_ColorType:
case kHardStopLeftEdged_ColorType:
case kHardStopRightEdged_ColorType:
case kSingleHardStop_ColorType:
@@ -1843,7 +1867,7 @@
return false;
}
} else {
- if (kSingleHardStop_ColorType == fColorType) {
+ if (kSingleHardStop_ColorType == fColorType || kThree_ColorType == fColorType) {
if (!SkScalarNearlyEqual(ge.fPositions[1], fPositions[1])) {
return false;
}