Report optimizations in master gradient effects

All of the FPs for the gradient components have had to be updated to
include the @optimizationFlags section. Layout FPs now can use the
opacity preserving optimization to report whether or not they might
reject a fragment (e.g. 2 point conical gradients).

The previous composition logic that handled ensuring the gradient shader
output a premul color was removing optimizations that should have been
valid for gradients, so the make premul logic has been inlined into
the top-level effect FPs.

Bug: skia:
Change-Id: I73e4224d8dc0e3420a215b0aa805d829b08f6c76
Reviewed-on: https://skia-review.googlesource.com/151547
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/gradients/GrGradientShader.cpp b/src/gpu/gradients/GrGradientShader.cpp
index 7e14025..b4d2b65 100644
--- a/src/gpu/gradients/GrGradientShader.cpp
+++ b/src/gpu/gradients/GrGradientShader.cpp
@@ -115,6 +115,7 @@
     // Convert all colors into destination space and into GrColor4fs, and handle
     // premul issues depending on the interpolation mode
     bool inputPremul = shader.getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag;
+    bool allOpaque = true;
     SkAutoSTMalloc<4, GrColor4f> colors(shader.fColorCount);
     SkColor4fXformer xformedColors(shader.fOrigColors4f, shader.fColorCount,
             shader.fColorSpace.get(), args.fDstColorSpaceInfo->colorSpace());
@@ -123,6 +124,9 @@
         if (inputPremul) {
             colors[i] = colors[i].premul();
         }
+        if (allOpaque && !SkScalarNearlyEqual(colors[i].fRGBA[3], 1.0)) {
+            allOpaque = false;
+        }
     }
 
     // SkGradientShader stores positions implicitly when they are evenly spaced, but the getPos()
@@ -148,16 +152,23 @@
         return nullptr;
     }
 
+    // The master effect has to export premul colors, but under certain conditions it doesn't need
+    // to do anything to achieve that: i.e. its interpolating already premul colors (inputPremul)
+    // or all the colors have a = 1, in which case premul is a no op. Note that this allOpaque
+    // check is more permissive than SkGradientShaderBase's isOpaque(), since we can optimize away
+    // the make-premul op for two point conical gradients (which report false for isOpaque).
+    bool makePremul = !inputPremul && !allOpaque;
+
     // All tile modes are supported (unless something was added to SkShader)
     std::unique_ptr<GrFragmentProcessor> master;
     switch(shader.getTileMode()) {
         case SkShader::kRepeat_TileMode:
             master = GrTiledGradientEffect::Make(std::move(colorizer), std::move(layout),
-                                                 /* mirror */ false);
+                                                 /* mirror */ false, makePremul, allOpaque);
             break;
         case SkShader::kMirror_TileMode:
             master = GrTiledGradientEffect::Make(std::move(colorizer), std::move(layout),
-                                                 /* mirror */ true);
+                                                 /* mirror */ true, makePremul, allOpaque);
             break;
         case SkShader::kClamp_TileMode:
             // For the clamped mode, the border colors are the first and last colors, corresponding
@@ -165,12 +176,14 @@
             // appropriate. If there is a hard stop, this grabs the expected outer colors for the
             // border.
             master = GrClampedGradientEffect::Make(std::move(colorizer), std::move(layout),
-                                                   colors[0], colors[shader.fColorCount - 1]);
+                    colors[0], colors[shader.fColorCount - 1], makePremul, allOpaque);
             break;
         case SkShader::kDecal_TileMode:
+            // Even if the gradient colors are opaque, the decal borders are transparent so
+            // disable that optimization
             master = GrClampedGradientEffect::Make(std::move(colorizer), std::move(layout),
-                                                   GrColor4f::TransparentBlack(),
-                                                   GrColor4f::TransparentBlack());
+                    GrColor4f::TransparentBlack(), GrColor4f::TransparentBlack(),
+                    makePremul, /* colorsAreOpaque */ false);
             break;
     }
 
@@ -179,14 +192,6 @@
         return nullptr;
     }
 
-    if (!inputPremul) {
-        // When interpolating unpremul colors, the output of the gradient
-        // effect fp's will also be unpremul, so wrap it to ensure its premul.
-        // - this is unnecessary when interpolating premul colors since the
-        //   output color is premul by nature
-        master = GrFragmentProcessor::PremulOutput(std::move(master));
-    }
-
     return GrFragmentProcessor::MulChildByInputAlpha(std::move(master));
 }