Avoid multiplication by alpha in fragment shader when known to be 1.

Implemented for image shaders, image draws, and gradient shaders.

Reimplement GrFragmentProcessor::OverrideInput as GrOverrideInputFragmentProcessor.fp.
It allows specification of whether the replacement input color should be
a literal in the shader code or a uniform. For above use case use with literal white.

Make key in variables in fp files work for 4f colors.

Fix issue in CPP code gen from .fp where when + key vars that pushed multiple values
into the shader key only skipped the first key value when the when condition is not
true.

Bug: skia:7722

Change-Id: Id7c865132d620e8cdea8b00f2a627103eef171ac
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/201985
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 3f8a8f9..1e4f50c 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -372,6 +372,8 @@
   "$_src/gpu/effects/generated/GrMagnifierEffect.h",
   "$_src/gpu/effects/generated/GrMixerEffect.cpp",
   "$_src/gpu/effects/generated/GrMixerEffect.h",
+  "$_src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp",
+  "$_src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h",
   "$_src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp",
   "$_src/gpu/effects/generated/GrPremulInputFragmentProcessor.h",
   "$_src/gpu/effects/generated/GrRectBlurEffect.cpp",
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 50ec8e7..891b84c 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -45,6 +45,7 @@
   "$_src/gpu/effects/GrLumaColorFilterEffect.fp",
   "$_src/gpu/effects/GrMagnifierEffect.fp",
   "$_src/gpu/effects/GrMixerEffect.fp",
+  "$_src/gpu/effects/GrOverrideInputFragmentProcessor.fp",
   "$_src/gpu/effects/GrPremulInputFragmentProcessor.fp",
   "$_src/gpu/effects/GrRectBlurEffect.fp",
   "$_src/gpu/effects/GrRRectBlurEffect.fp",
diff --git a/src/gpu/GrFPArgs.h b/src/gpu/GrFPArgs.h
index 94b26e6..43f2868 100644
--- a/src/gpu/GrFPArgs.h
+++ b/src/gpu/GrFPArgs.h
@@ -42,6 +42,9 @@
     const SkMatrix* fPreLocalMatrix  = nullptr;
     const SkMatrix* fPostLocalMatrix = nullptr;
 
+    // Make this SkAlphaType?
+    bool fInputColorIsOpaque = false;
+
     SkFilterQuality fFilterQuality;
     const GrColorSpaceInfo* fDstColorSpaceInfo;
 };
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 3d6ec03..4a4c4cb 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -9,9 +9,10 @@
 #include "GrCoordTransform.h"
 #include "GrPipeline.h"
 #include "GrProcessorAnalysis.h"
-#include "effects/generated/GrConstColorProcessor.h"
-#include "effects/generated/GrPremulInputFragmentProcessor.h"
 #include "effects/GrXfermodeFragmentProcessor.h"
+#include "effects/generated/GrConstColorProcessor.h"
+#include "effects/generated/GrOverrideInputFragmentProcessor.h"
+#include "effects/generated/GrPremulInputFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
@@ -282,93 +283,11 @@
 //////////////////////////////////////////////////////////////////////////////
 
 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
-        std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color) {
-    class ReplaceInputFragmentProcessor : public GrFragmentProcessor {
-    public:
-        static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child,
-                                                         const SkPMColor4f& color) {
-            return std::unique_ptr<GrFragmentProcessor>(
-                    new ReplaceInputFragmentProcessor(std::move(child), color));
-        }
-
-        const char* name() const override { return "Replace Color"; }
-
-        std::unique_ptr<GrFragmentProcessor> clone() const override {
-            return Make(this->childProcessor(0).clone(), fColor);
-        }
-
-    private:
-        GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
-            class GLFP : public GrGLSLFragmentProcessor {
-            public:
-                GLFP() : fHaveSetColor(false) {}
-                void emitCode(EmitArgs& args) override {
-                    const char* colorName;
-                    fColorUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
-                                                                 kHalf4_GrSLType,
-                                                                 "Color", &colorName);
-                    this->emitChild(0, colorName, args);
-                }
-
-            private:
-                void onSetData(const GrGLSLProgramDataManager& pdman,
-                               const GrFragmentProcessor& fp) override {
-                    SkPMColor4f color = fp.cast<ReplaceInputFragmentProcessor>().fColor;
-                    if (!fHaveSetColor || color != fPreviousColor) {
-                        pdman.set4fv(fColorUni, 1, color.vec());
-                        fPreviousColor = color;
-                        fHaveSetColor = true;
-                    }
-                }
-
-                GrGLSLProgramDataManager::UniformHandle fColorUni;
-                bool        fHaveSetColor;
-                SkPMColor4f fPreviousColor;
-            };
-
-            return new GLFP;
-        }
-
-        ReplaceInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child,
-                                      const SkPMColor4f& color)
-                : INHERITED(kReplaceInputFragmentProcessor_ClassID, OptFlags(child.get(), color))
-                , fColor(color) {
-            this->registerChildProcessor(std::move(child));
-        }
-
-        static OptimizationFlags OptFlags(const GrFragmentProcessor* child,
-                                          const SkPMColor4f& color) {
-            OptimizationFlags childFlags = child->optimizationFlags();
-            OptimizationFlags flags = kNone_OptimizationFlags;
-            if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
-                flags |= kConstantOutputForConstantInput_OptimizationFlag;
-            }
-            if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
-                flags |= kPreservesOpaqueInput_OptimizationFlag;
-            }
-            return flags;
-        }
-
-        void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override
-        {}
-
-        bool onIsEqual(const GrFragmentProcessor& that) const override {
-            return fColor == that.cast<ReplaceInputFragmentProcessor>().fColor;
-        }
-
-        SkPMColor4f constantOutputForConstantInput(const SkPMColor4f&) const override {
-            return ConstantOutputForConstantInput(this->childProcessor(0), fColor);
-        }
-
-        SkPMColor4f fColor;
-
-        typedef GrFragmentProcessor INHERITED;
-    };
-
+        std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color, bool useUniform) {
     if (!fp) {
         return nullptr;
     }
-    return ReplaceInputFragmentProcessor::Make(std::move(fp), color);
+    return GrOverrideInputFragmentProcessor::Make(std::move(fp), color, useUniform);
 }
 
 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h
index 5136243..fb8126e 100644
--- a/src/gpu/GrFragmentProcessor.h
+++ b/src/gpu/GrFragmentProcessor.h
@@ -63,7 +63,8 @@
      *  child.
      */
     static std::unique_ptr<GrFragmentProcessor> OverrideInput(std::unique_ptr<GrFragmentProcessor>,
-                                                              const SkPMColor4f&);
+                                                              const SkPMColor4f&,
+                                                              bool useUniform = true);
 
     /**
      *  Returns a fragment processor that premuls the input before calling the passed in fragment
@@ -293,6 +294,11 @@
         return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
     }
 
+    /** Useful when you can't call fp->optimizationFlags() on a base class object from a subclass.*/
+    static OptimizationFlags ProcessorOptimizationFlags(const GrFragmentProcessor* fp) {
+        return fp->optimizationFlags();
+    }
+
     /**
      * This allows one subclass to access another subclass's implementation of
      * constantOutputForConstantInput. It must only be called when
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 0e6d7bc..3c3a9ad 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -124,6 +124,7 @@
         kGrMorphologyEffect_ClassID,
         kGrMixerEffect_ClassID,
         kGrOverdrawFragmentProcessor_ClassID,
+        kGrOverrideInputFragmentProcessor_ClassID,
         kGrPathProcessor_ClassID,
         kGrPerlinNoise2Effect_ClassID,
         kGrPipelineDynamicStateTestProcessor_ClassID,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 388450f..e04c567 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1061,7 +1061,11 @@
     if (GrPixelConfigIsAlphaOnly(config)) {
         fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
     } else {
-        fp = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
+        if (paint.getColor4f().isOpaque()) {
+            fp = GrFragmentProcessor::OverrideInput(std::move(fp), SK_PMColor4fWHITE, false);
+        } else {
+            fp = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
+        }
     }
 
     GrPaint grPaint;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 5fc363b..ac195bb 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -355,12 +355,13 @@
     // Convert SkPaint color to 4f format in the destination color space
     SkColor4f origColor = SkColor4fPrepForDst(skPaint.getColor4f(), colorSpaceInfo);
 
-    const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
+    GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
 
     // Setup the initial color considering the shader, the SkPaint color, and the presence or not
     // of per-vertex colors.
     std::unique_ptr<GrFragmentProcessor> shaderFP;
     if (!primColorMode || blend_requires_shader(*primColorMode)) {
+        fpArgs.fInputColorIsOpaque = origColor.isOpaque();
         if (shaderProcessor) {
             shaderFP = std::move(*shaderProcessor);
         } else if (const auto* shader = as_SB(skPaint.getShader())) {
@@ -457,6 +458,8 @@
 
     SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter());
     if (maskFilter) {
+        // We may have set this before passing to the SkShader.
+        fpArgs.fInputColorIsOpaque = false;
         if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) {
             grPaint->addCoverageFragmentProcessor(std::move(mfFP));
         }
@@ -551,7 +554,11 @@
             shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
         }
     } else {
-        shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
+        if (paint.getColor4f().isOpaque()) {
+            shaderFP = GrFragmentProcessor::OverrideInput(std::move(fp), SK_PMColor4fWHITE, false);
+        } else {
+            shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
+        }
     }
 
     return SkPaintToGrPaintReplaceShader(context, colorSpaceInfo, paint, std::move(shaderFP),
diff --git a/src/gpu/effects/GrMixerEffect.fp b/src/gpu/effects/GrMixerEffect.fp
index cb0c979..9b6acf7 100644
--- a/src/gpu/effects/GrMixerEffect.fp
+++ b/src/gpu/effects/GrMixerEffect.fp
@@ -15,27 +15,11 @@
 
     static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
                                       const std::unique_ptr<GrFragmentProcessor>& fp1) {
-        auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
-            auto flags = kNone_OptimizationFlags;
-
-            if (fp->compatibleWithCoverageAsAlpha()) {
-                flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
-            }
-
-            if (fp->preservesOpaqueInput()) {
-                flags |= kPreservesOpaqueInput_OptimizationFlag;
-            }
-
-            if (fp->hasConstantOutputForConstantInput()) {
-                flags |= kConstantOutputForConstantInput_OptimizationFlag;
-            }
-
-            return flags;
-        };
-
-        const auto fp0_flags = get_flags(fp0);
-
-        return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
+        auto flags = ProcessorOptimizationFlags(fp0.get());
+        if (fp1) {
+            flags &= ProcessorOptimizationFlags(fp1.get());
+        }
+        return flags;
     }
 
     SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
diff --git a/src/gpu/effects/GrOverrideInputFragmentProcessor.fp b/src/gpu/effects/GrOverrideInputFragmentProcessor.fp
new file mode 100644
index 0000000..9f7ee9e
--- /dev/null
+++ b/src/gpu/effects/GrOverrideInputFragmentProcessor.fp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Ignores its own input color and invokes 'fp' with a constant color
+// The constant color can either be specified as a literal or as a
+// uniform, controlled by useUniform.
+
+in fragmentProcessor fp;
+layout(key) in bool useUniform;
+layout(when=useUniform, ctype=SkPMColor4f) in uniform half4 uniformColor;
+layout(when=!useUniform, key, ctype=SkPMColor4f) in half4 literalColor;
+
+@make {
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+                                                     const SkPMColor4f& color,
+                                                     bool useUniform = true) {
+        return std::unique_ptr<GrFragmentProcessor>(
+            new GrOverrideInputFragmentProcessor(std::move(fp), useUniform, color, color));
+    }
+}
+
+@class {
+    static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp,
+                                      const SkPMColor4f& color) {
+        auto childFlags = ProcessorOptimizationFlags(fp.get());
+        auto flags = kNone_OptimizationFlags;
+        if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
+            flags |= kConstantOutputForConstantInput_OptimizationFlag;
+        }
+        if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
+            flags |= kPreservesOpaqueInput_OptimizationFlag;
+        }
+        return flags;
+    }
+
+    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+        return ConstantOutputForConstantInput(this->childProcessor(0), uniformColor);
+    }
+}
+
+@optimizationFlags { OptFlags(fp, useUniform ? uniformColor : literalColor) }
+
+void main() {
+    half4 constColor;
+    @if(useUniform) {
+        constColor = uniformColor;
+    } else {
+        constColor = literalColor;
+    }
+    sk_OutColor = process(fp, constColor);
+}
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index e3064bf..b5730fb 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -326,17 +326,8 @@
             case SkBlendMode::kSrcIn:
             case SkBlendMode::kDstIn:
             case SkBlendMode::kModulate:
-                if (fp->compatibleWithCoverageAsAlpha()) {
-                    if (fp->preservesOpaqueInput()) {
-                        flags = kPreservesOpaqueInput_OptimizationFlag |
-                                kCompatibleWithCoverageAsAlpha_OptimizationFlag;
-                    } else {
-                        flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag;
-                    }
-                } else {
-                    flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
-                                                       : kNone_OptimizationFlags;
-                }
+                flags = ProcessorOptimizationFlags(fp) &
+                        ~kConstantOutputForConstantInput_OptimizationFlag;
                 break;
 
             // Produces zero when both are opaque, indeterminate if one is opaque.
diff --git a/src/gpu/effects/generated/GrMixerEffect.h b/src/gpu/effects/generated/GrMixerEffect.h
index d318285..4c30fba 100644
--- a/src/gpu/effects/generated/GrMixerEffect.h
+++ b/src/gpu/effects/generated/GrMixerEffect.h
@@ -17,27 +17,11 @@
 public:
     static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
                                       const std::unique_ptr<GrFragmentProcessor>& fp1) {
-        auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
-            auto flags = kNone_OptimizationFlags;
-
-            if (fp->compatibleWithCoverageAsAlpha()) {
-                flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
-            }
-
-            if (fp->preservesOpaqueInput()) {
-                flags |= kPreservesOpaqueInput_OptimizationFlag;
-            }
-
-            if (fp->hasConstantOutputForConstantInput()) {
-                flags |= kConstantOutputForConstantInput_OptimizationFlag;
-            }
-
-            return flags;
-        };
-
-        const auto fp0_flags = get_flags(fp0);
-
-        return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
+        auto flags = ProcessorOptimizationFlags(fp0.get());
+        if (fp1) {
+            flags &= ProcessorOptimizationFlags(fp1.get());
+        }
+        return flags;
     }
 
     SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
diff --git a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
new file mode 100644
index 0000000..c3d2d27
--- /dev/null
+++ b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**************************************************************************************************
+ *** This file was autogenerated from GrOverrideInputFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#include "GrOverrideInputFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLOverrideInputFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLOverrideInputFragmentProcessor() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrOverrideInputFragmentProcessor& _outer =
+                args.fFp.cast<GrOverrideInputFragmentProcessor>();
+        (void)_outer;
+        auto useUniform = _outer.useUniform;
+        (void)useUniform;
+        auto uniformColor = _outer.uniformColor;
+        (void)uniformColor;
+        auto literalColor = _outer.literalColor;
+        (void)literalColor;
+        if (useUniform) {
+            uniformColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
+                                                               kHalf4_GrSLType, "uniformColor");
+        }
+        fragBuilder->codeAppendf(
+                "half4 constColor;\n@if (%s) {\n    constColor = %s;\n} else {\n    constColor = "
+                "half4(%f, %f, %f, %f);\n}",
+                (_outer.useUniform ? "true" : "false"),
+                uniformColorVar.isValid() ? args.fUniformHandler->getUniformCStr(uniformColorVar)
+                                          : "half4(0)",
+                _outer.literalColor.fR, _outer.literalColor.fG, _outer.literalColor.fB,
+                _outer.literalColor.fA);
+        SkString _input0("constColor");
+        SkString _child0("_child0");
+        this->emitChild(_outer.fp_index, _input0.c_str(), &_child0, args);
+        fragBuilder->codeAppendf("\n%s = %s;\n", args.fOutputColor, _child0.c_str());
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrOverrideInputFragmentProcessor& _outer =
+                _proc.cast<GrOverrideInputFragmentProcessor>();
+        {
+            if (uniformColorVar.isValid()) {
+                pdman.set4fv(uniformColorVar, 1, (_outer.uniformColor).vec());
+            }
+        }
+    }
+    UniformHandle uniformColorVar;
+};
+GrGLSLFragmentProcessor* GrOverrideInputFragmentProcessor::onCreateGLSLInstance() const {
+    return new GrGLSLOverrideInputFragmentProcessor();
+}
+void GrOverrideInputFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                             GrProcessorKeyBuilder* b) const {
+    b->add32((int32_t)useUniform);
+    if (!useUniform) {
+        uint16_t red = SkFloatToHalf(literalColor.fR);
+        uint16_t green = SkFloatToHalf(literalColor.fG);
+        uint16_t blue = SkFloatToHalf(literalColor.fB);
+        uint16_t alpha = SkFloatToHalf(literalColor.fA);
+        b->add32(((uint32_t)red << 16) | green);
+        b->add32(((uint32_t)blue << 16) | alpha);
+    }
+}
+bool GrOverrideInputFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrOverrideInputFragmentProcessor& that = other.cast<GrOverrideInputFragmentProcessor>();
+    (void)that;
+    if (useUniform != that.useUniform) return false;
+    if (uniformColor != that.uniformColor) return false;
+    if (literalColor != that.literalColor) return false;
+    return true;
+}
+GrOverrideInputFragmentProcessor::GrOverrideInputFragmentProcessor(
+        const GrOverrideInputFragmentProcessor& src)
+        : INHERITED(kGrOverrideInputFragmentProcessor_ClassID, src.optimizationFlags())
+        , fp_index(src.fp_index)
+        , useUniform(src.useUniform)
+        , uniformColor(src.uniformColor)
+        , literalColor(src.literalColor) {
+    this->registerChildProcessor(src.childProcessor(fp_index).clone());
+}
+std::unique_ptr<GrFragmentProcessor> GrOverrideInputFragmentProcessor::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrOverrideInputFragmentProcessor(*this));
+}
diff --git a/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
new file mode 100644
index 0000000..d7cacee
--- /dev/null
+++ b/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**************************************************************************************************
+ *** This file was autogenerated from GrOverrideInputFragmentProcessor.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrOverrideInputFragmentProcessor_DEFINED
+#define GrOverrideInputFragmentProcessor_DEFINED
+#include "SkTypes.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrOverrideInputFragmentProcessor : public GrFragmentProcessor {
+public:
+    static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp,
+                                      const SkPMColor4f& color) {
+        auto childFlags = ProcessorOptimizationFlags(fp.get());
+        auto flags = kNone_OptimizationFlags;
+        if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
+            flags |= kConstantOutputForConstantInput_OptimizationFlag;
+        }
+        if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
+            flags |= kPreservesOpaqueInput_OptimizationFlag;
+        }
+        return flags;
+    }
+
+    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
+        return ConstantOutputForConstantInput(this->childProcessor(0), uniformColor);
+    }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+                                                     const SkPMColor4f& color,
+                                                     bool useUniform = true) {
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrOverrideInputFragmentProcessor(std::move(fp), useUniform, color, color));
+    }
+    GrOverrideInputFragmentProcessor(const GrOverrideInputFragmentProcessor& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "OverrideInputFragmentProcessor"; }
+    int fp_index = -1;
+    bool useUniform;
+    SkPMColor4f uniformColor;
+    SkPMColor4f literalColor;
+
+private:
+    GrOverrideInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp,
+                                     bool useUniform,
+                                     SkPMColor4f uniformColor,
+                                     SkPMColor4f literalColor)
+            : INHERITED(kGrOverrideInputFragmentProcessor_ClassID,
+                        (OptimizationFlags)OptFlags(fp, useUniform ? uniformColor : literalColor))
+            , useUniform(useUniform)
+            , uniformColor(uniformColor)
+            , literalColor(literalColor) {
+        SkASSERT(fp);
+        fp_index = this->numChildProcessors();
+        this->registerChildProcessor(std::move(fp));
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/gradients/GrGradientShader.cpp b/src/gpu/gradients/GrGradientShader.cpp
index ac60b21..d204f97 100644
--- a/src/gpu/gradients/GrGradientShader.cpp
+++ b/src/gpu/gradients/GrGradientShader.cpp
@@ -236,7 +236,9 @@
         // Unexpected tile mode
         return nullptr;
     }
-
+    if (args.fInputColorIsOpaque) {
+        return GrFragmentProcessor::OverrideInput(std::move(master), SK_PMColor4fWHITE, false);
+    }
     return GrFragmentProcessor::MulChildByInputAlpha(std::move(master));
 }
 
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index 581a310..c2e146c 100644
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -257,6 +257,8 @@
                                           args.fDstColorSpaceInfo->colorSpace());
     if (isAlphaOnly) {
         return inner;
+    } else if (args.fInputColorIsOpaque) {
+        return GrFragmentProcessor::OverrideInput(std::move(inner), SK_PMColor4fWHITE, false);
     }
     return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
 }
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index 570c5e8..c4f56b5 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -1106,7 +1106,7 @@
         switch (param->fModifiers.fLayout.fKey) {
             case Layout::kKey_Key:
                 if (param->fModifiers.fLayout.fWhen.size()) {
-                    this->writef("if (%s) ", param->fModifiers.fLayout.fWhen.c_str());
+                    this->writef("if (%s) {", param->fModifiers.fLayout.fWhen.c_str());
                 }
                 if (param->fType == *fContext.fFloat4x4_Type) {
                     ABORT("no automatic key handling for float4x4\n");
@@ -1124,10 +1124,24 @@
                                  HCodeGenerator::FieldName(name).c_str());
                     this->writef("    b->add32(%s.height());\n",
                                  HCodeGenerator::FieldName(name).c_str());
+                } else if (param->fType == *fContext.fHalf4_Type) {
+                    this->writef("    uint16_t red = SkFloatToHalf(%s.fR);\n",
+                                 HCodeGenerator::FieldName(name).c_str());
+                    this->writef("    uint16_t green = SkFloatToHalf(%s.fG);\n",
+                                 HCodeGenerator::FieldName(name).c_str());
+                    this->writef("    uint16_t blue = SkFloatToHalf(%s.fB);\n",
+                                 HCodeGenerator::FieldName(name).c_str());
+                    this->writef("    uint16_t alpha = SkFloatToHalf(%s.fA);\n",
+                                 HCodeGenerator::FieldName(name).c_str());
+                    this->write("    b->add32(((uint32_t)red << 16) | green);\n");
+                    this->write("    b->add32(((uint32_t)blue << 16) | alpha);\n");
                 } else {
                     this->writef("    b->add32((int32_t) %s);\n",
                                  HCodeGenerator::FieldName(name).c_str());
                 }
+                if (param->fModifiers.fLayout.fWhen.size()) {
+                    this->write("}");
+                }
                 break;
             case Layout::kIdentity_Key:
                 if (param->fType.kind() != Type::kMatrix_Kind) {