Implement sweep gradient layout

Add an FP that implements the sweep gradient effect and updates
SkSweepGradient to use the new system if possible.

Bug: skia:
Change-Id: I3f65da01afafae54c45848a6a78fd758f65eb4a6
Reviewed-on: https://skia-review.googlesource.com/148806
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 c277997..50a4c8a 100644
--- a/src/gpu/gradients/GrGradientShader.cpp
+++ b/src/gpu/gradients/GrGradientShader.cpp
@@ -12,6 +12,7 @@
 
 #include "GrLinearGradientLayout.h"
 #include "GrRadialGradientLayout.h"
+#include "GrSweepGradientLayout.h"
 
 #include "GrSingleIntervalGradientColorizer.h"
 
@@ -137,4 +138,9 @@
     return make_gradient(shader,args, GrRadialGradientLayout::Make(shader, args));
 }
 
+std::unique_ptr<GrFragmentProcessor> MakeSweep(const SkSweepGradient& shader,
+                                               const GrFPArgs& args) {
+    return make_gradient(shader,args, GrSweepGradientLayout::Make(shader, args));
+}
+
 }
diff --git a/src/gpu/gradients/GrGradientShader.h b/src/gpu/gradients/GrGradientShader.h
index 22233fb..0a09ff7 100644
--- a/src/gpu/gradients/GrGradientShader.h
+++ b/src/gpu/gradients/GrGradientShader.h
@@ -12,6 +12,7 @@
 #include "SkGradientShaderPriv.h"
 #include "SkLinearGradient.h"
 #include "SkRadialGradient.h"
+#include "SkSweepGradient.h"
 
 namespace GrGradientShader {
     std::unique_ptr<GrFragmentProcessor> MakeLinear(const SkLinearGradient& shader,
@@ -19,6 +20,9 @@
 
     std::unique_ptr<GrFragmentProcessor> MakeRadial(const SkRadialGradient& shader,
                                                     const GrFPArgs& args);
+
+    std::unique_ptr<GrFragmentProcessor> MakeSweep(const SkSweepGradient& shader,
+                                                   const GrFPArgs& args);
 }
 
 #endif // GrGradientShader_DEFINE
diff --git a/src/gpu/gradients/GrSweepGradientLayout.cpp b/src/gpu/gradients/GrSweepGradientLayout.cpp
new file mode 100644
index 0000000..227ff5f
--- /dev/null
+++ b/src/gpu/gradients/GrSweepGradientLayout.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 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 GrSweepGradientLayout.fp; do not modify.
+ **************************************************************************************************/
+#include "GrSweepGradientLayout.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrTexture.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLSweepGradientLayout : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLSweepGradientLayout() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrSweepGradientLayout& _outer = args.fFp.cast<GrSweepGradientLayout>();
+        (void)_outer;
+        auto gradientMatrix = _outer.gradientMatrix();
+        (void)gradientMatrix;
+        auto bias = _outer.bias();
+        (void)bias;
+        auto scale = _outer.scale();
+        (void)scale;
+        fBiasVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                    kDefault_GrSLPrecision, "bias");
+        fScaleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                     kDefault_GrSLPrecision, "scale");
+        SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
+        fragBuilder->codeAppendf(
+                "half angle;\nif (sk_Caps.atan2ImplementedAsAtanYOverX) {\n    angle = half(2.0 * "
+                "atan(-%s.y, length(%s) - %s.x));\n} else {\n    angle = half(atan(-%s.y, "
+                "-%s.x));\n}\n%s = half4(((float(float(angle) * 0.15915494309180001) + 0.5) + %s) "
+                "* %s);\n",
+                sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str(),
+                sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str(),
+                sk_TransformedCoords2D_0.c_str(), args.fOutputColor,
+                args.fUniformHandler->getUniformCStr(fBiasVar),
+                args.fUniformHandler->getUniformCStr(fScaleVar));
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrSweepGradientLayout& _outer = _proc.cast<GrSweepGradientLayout>();
+        {
+            float biasValue = _outer.bias();
+            if (fBiasPrev != biasValue) {
+                fBiasPrev = biasValue;
+                pdman.set1f(fBiasVar, biasValue);
+            }
+            float scaleValue = _outer.scale();
+            if (fScalePrev != scaleValue) {
+                fScalePrev = scaleValue;
+                pdman.set1f(fScaleVar, scaleValue);
+            }
+        }
+    }
+    float fBiasPrev = SK_FloatNaN;
+    float fScalePrev = SK_FloatNaN;
+    UniformHandle fBiasVar;
+    UniformHandle fScaleVar;
+};
+GrGLSLFragmentProcessor* GrSweepGradientLayout::onCreateGLSLInstance() const {
+    return new GrGLSLSweepGradientLayout();
+}
+void GrSweepGradientLayout::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                                  GrProcessorKeyBuilder* b) const {}
+bool GrSweepGradientLayout::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrSweepGradientLayout& that = other.cast<GrSweepGradientLayout>();
+    (void)that;
+    if (fGradientMatrix != that.fGradientMatrix) return false;
+    if (fBias != that.fBias) return false;
+    if (fScale != that.fScale) return false;
+    return true;
+}
+GrSweepGradientLayout::GrSweepGradientLayout(const GrSweepGradientLayout& src)
+        : INHERITED(kGrSweepGradientLayout_ClassID, src.optimizationFlags())
+        , fGradientMatrix(src.fGradientMatrix)
+        , fBias(src.fBias)
+        , fScale(src.fScale)
+        , fCoordTransform0(src.fCoordTransform0) {
+    this->addCoordTransform(&fCoordTransform0);
+}
+std::unique_ptr<GrFragmentProcessor> GrSweepGradientLayout::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrSweepGradientLayout(*this));
+}
+
+std::unique_ptr<GrFragmentProcessor> GrSweepGradientLayout::Make(const SkSweepGradient& grad,
+                                                                 const GrFPArgs& args) {
+    SkMatrix matrix;
+    if (!grad.totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
+        return nullptr;
+    }
+    matrix.postConcat(grad.getGradientMatrix());
+    return std::unique_ptr<GrFragmentProcessor>(
+            new GrSweepGradientLayout(matrix, grad.getTBias(), grad.getTScale()));
+}
diff --git a/src/gpu/gradients/GrSweepGradientLayout.fp b/src/gpu/gradients/GrSweepGradientLayout.fp
new file mode 100644
index 0000000..7b98cb7
--- /dev/null
+++ b/src/gpu/gradients/GrSweepGradientLayout.fp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+in half4x4 gradientMatrix;
+
+layout(tracked) in uniform half bias;
+layout(tracked) in uniform half scale;
+
+@coordTransform {
+    gradientMatrix
+}
+
+void main() {
+    // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is
+    // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in (sqrt(x^2
+    // + y^2) + x) as the second parameter to atan2 in these cases. We let the device handle the
+    // undefined behavior of the second paramenter being 0 instead of doing the divide ourselves and
+    // using atan instead.
+    half angle;
+    if (sk_Caps.atan2ImplementedAsAtanYOverX) {
+        angle = 2 * atan(-sk_TransformedCoords2D[0].y,
+                         length(sk_TransformedCoords2D[0]) - sk_TransformedCoords2D[0].x);
+    } else {
+        angle = atan(-sk_TransformedCoords2D[0].y, -sk_TransformedCoords2D[0].x);
+    }
+
+    // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
+    sk_OutColor = half4((angle * 0.1591549430918 + 0.5 + bias) * scale);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+@header {
+    #include "SkSweepGradient.h"
+}
+
+@make {
+    static std::unique_ptr<GrFragmentProcessor> Make(const SkSweepGradient& gradient,
+                                                     const GrFPArgs& args);
+}
+
+@cppEnd {
+    std::unique_ptr<GrFragmentProcessor> GrSweepGradientLayout::Make(
+            const SkSweepGradient& grad, const GrFPArgs& args) {
+        SkMatrix matrix;
+        if (!grad.totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
+            return nullptr;
+        }
+        matrix.postConcat(grad.getGradientMatrix());
+        return std::unique_ptr<GrFragmentProcessor>(new GrSweepGradientLayout(
+                matrix, grad.getTBias(), grad.getTScale()));
+    }
+}
diff --git a/src/gpu/gradients/GrSweepGradientLayout.h b/src/gpu/gradients/GrSweepGradientLayout.h
new file mode 100644
index 0000000..ff4e143
--- /dev/null
+++ b/src/gpu/gradients/GrSweepGradientLayout.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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 GrSweepGradientLayout.fp; do not modify.
+ **************************************************************************************************/
+#ifndef GrSweepGradientLayout_DEFINED
+#define GrSweepGradientLayout_DEFINED
+#include "SkTypes.h"
+
+#include "SkSweepGradient.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+class GrSweepGradientLayout : public GrFragmentProcessor {
+public:
+    const SkMatrix44& gradientMatrix() const { return fGradientMatrix; }
+    float bias() const { return fBias; }
+    float scale() const { return fScale; }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(const SkSweepGradient& gradient,
+                                                     const GrFPArgs& args);
+    GrSweepGradientLayout(const GrSweepGradientLayout& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "SweepGradientLayout"; }
+
+private:
+    GrSweepGradientLayout(SkMatrix44 gradientMatrix, float bias, float scale)
+            : INHERITED(kGrSweepGradientLayout_ClassID, kNone_OptimizationFlags)
+            , fGradientMatrix(gradientMatrix)
+            , fBias(bias)
+            , fScale(scale)
+            , fCoordTransform0(gradientMatrix) {
+        this->addCoordTransform(&fCoordTransform0);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    SkMatrix44 fGradientMatrix;
+    float fBias;
+    float fScale;
+    GrCoordTransform fCoordTransform0;
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif