Remove symmetric three stop special case

Just let the general three-stop shader handle all three-stop gradients.
Also, pre-compute values derived from the middle stop to remove all
division (and actually convert computation to FMA form).

Bug: skia:
Change-Id: I1aae069d929d1a942c38aa2e2f3fd5fb7d9b2f10
Reviewed-on: https://skia-review.googlesource.com/45800
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index 45f25cd..9d95f99 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -1298,10 +1298,6 @@
 #include "glsl/GrGLSLUniformHandler.h"
 #include "SkGr.h"
 
-static inline bool close_to_one_half(const SkFixed& val) {
-    return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf);
-}
-
 static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) {
     switch (colorType) {
         case GrGradientEffect::kSingleHardStop_ColorType:
@@ -1312,7 +1308,6 @@
         case GrGradientEffect::kTwo_ColorType:
             return 2;
         case GrGradientEffect::kThree_ColorType:
-        case GrGradientEffect::kSymmetricThree_ColorType:
             return 3;
         case GrGradientEffect::kTexture_ColorType:
             return 0;
@@ -1350,8 +1345,7 @@
     if (2 == shader.fColorCount) {
         return kTwo_ColorType;
     } else if (3 == shader.fColorCount) {
-        return close_to_one_half(shader.getRecs()[1].fPos) ? kSymmetricThree_ColorType
-                                                           : kThree_ColorType;
+        return kThree_ColorType;
     }
 
     return kTexture_ColorType;
@@ -1366,8 +1360,8 @@
                                                      "Colors",
                                                      colorCount);
         if (kSingleHardStop_ColorType == ge.fColorType || kThree_ColorType == ge.fColorType) {
-            fExtraStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
-                                                     kDefault_GrSLPrecision, "ExtraStopT");
+            fExtraStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType,
+                                                     kHigh_GrSLPrecision, "ExtraStopT");
         }
     } else {
         fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
@@ -1470,12 +1464,16 @@
     switch (e.getColorType()) {
         case GrGradientEffect::kSingleHardStop_ColorType:
         case GrGradientEffect::kThree_ColorType:
-            pdman.set1f(fExtraStopT, e.fPositions[1]);
+            // ( t, 1/t, 1/(1-t), t/(1-t) )
+            // This lets us compute relative t on either side of the stop with at most a single FMA
+            pdman.set4f(fExtraStopT, e.fPositions[1],
+                                     1.0f / e.fPositions[1],
+                                     1.0f / (1.0f - e.fPositions[1]),
+                                     e.fPositions[1] / (1.0f - e.fPositions[1]));
             // fall through
         case GrGradientEffect::kHardStopLeftEdged_ColorType:
         case GrGradientEffect::kHardStopRightEdged_ColorType:
-        case GrGradientEffect::kTwo_ColorType:
-        case GrGradientEffect::kSymmetricThree_ColorType: {
+        case GrGradientEffect::kTwo_ColorType: {
             if (e.fColors4f.count() > 0) {
                 // Gamma-correct / color-space aware
                 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
@@ -1524,8 +1522,6 @@
         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()) {
@@ -1576,18 +1572,20 @@
     const char* colors = uniformHandler->getUniformCStr(fColorsUni);
     switch (ge.getColorType()) {
         case kSingleHardStop_ColorType: {
+            // (t, 1/t, 1/(1-t), t/(1-t))
             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("if (clamp_t < %s.x) {", stopT);
             fragBuilder->codeAppendf("    start = %s[0];", colors);
             fragBuilder->codeAppendf("    end   = %s[1];", colors);
-            fragBuilder->codeAppendf("    relative_t = clamp_t / %s;", stopT);
+            fragBuilder->codeAppendf("    relative_t = clamp_t * %s.y;", stopT);
             fragBuilder->codeAppend ("} else {");
             fragBuilder->codeAppendf("    start = %s[2];", colors);
             fragBuilder->codeAppendf("    end   = %s[3];", colors);
-            fragBuilder->codeAppendf("    relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT);
+            // Want: (t-s)/(1-s), but arrange it as: t/(1-s) - s/(1-s), for FMA form
+            fragBuilder->codeAppendf("    relative_t = (clamp_t * %s.z) - %s.w;", stopT, stopT);
             fragBuilder->codeAppend ("}");
             fragBuilder->codeAppend ("float4 colorTemp = mix(start, end, relative_t);");
 
@@ -1626,35 +1624,26 @@
         }
 
         case kThree_ColorType: {
+            // (t, 1/t, 1/(1-t), t/(1-t))
             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("if (clamp_t < %s.x) {", stopT);
             fragBuilder->codeAppendf("    start = %s[0];", colors);
             fragBuilder->codeAppendf("    end   = %s[1];", colors);
-            fragBuilder->codeAppendf("    relative_t = clamp_t / %s;", stopT);
+            fragBuilder->codeAppendf("    relative_t = clamp_t * %s.y;", 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);
+            // Want: (t-s)/(1-s), but arrange it as: t/(1-s) - s/(1-s), for FMA form
+            fragBuilder->codeAppendf("    relative_t = (clamp_t * %s.z) - %s.w;", 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);
-            fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];",
-                                     colors);
-            fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors);
-
-            break;
-        }
-
         default:
             SkASSERT(false);
             break;
@@ -1729,6 +1718,9 @@
 
         if (shader.fOrigPos) {
             fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount);
+        } else if (kThree_ColorType == fColorType) {
+            const SkScalar symmetricStops[] = { 0.0f, 0.5f, 1.0f };
+            fPositions = SkTDArray<SkScalar>(symmetricStops, 3);
         }
     }
 
@@ -1738,7 +1730,6 @@
         // 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: