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/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