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/gn/gpu.gni b/gn/gpu.gni
index 463b5ed..f2005e5 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -407,6 +407,8 @@
"$_src/gpu/gradients/GrLinearGradientLayout.h",
"$_src/gpu/gradients/GrRadialGradientLayout.cpp",
"$_src/gpu/gradients/GrRadialGradientLayout.h",
+ "$_src/gpu/gradients/GrSweepGradientLayout.cpp",
+ "$_src/gpu/gradients/GrSweepGradientLayout.h",
"$_src/gpu/gradients/GrClampedGradientEffect.cpp",
"$_src/gpu/gradients/GrClampedGradientEffect.h",
"$_src/gpu/gradients/GrTiledGradientEffect.cpp",
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 4ec691e..e5b2fe1 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -49,6 +49,7 @@
"$_src/gpu/gradients/GrSingleIntervalGradientColorizer.fp",
"$_src/gpu/gradients/GrLinearGradientLayout.fp",
"$_src/gpu/gradients/GrRadialGradientLayout.fp",
+ "$_src/gpu/gradients/GrSweepGradientLayout.fp",
"$_src/gpu/gradients/GrClampedGradientEffect.fp",
"$_src/gpu/gradients/GrTiledGradientEffect.fp",
]
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 0f5b11d..6f5225e 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -137,6 +137,7 @@
kGrSpecularLightingEffect_ClassID,
kGrSRGBEffect_ClassID,
kGrSweepGradient_ClassID,
+ kGrSweepGradientLayout_ClassID,
kGrTextureDomainEffect_ClassID,
kGrTiledGradientEffect_ClassID,
kGrUnpremulInputFragmentProcessor_ClassID,
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
diff --git a/src/shaders/gradients/SkSweepGradient.cpp b/src/shaders/gradients/SkSweepGradient.cpp
index 89c5cb1..a37dc8f 100644
--- a/src/shaders/gradients/SkSweepGradient.cpp
+++ b/src/shaders/gradients/SkSweepGradient.cpp
@@ -72,6 +72,8 @@
#include "gl/GrGLContext.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "gradients/GrGradientShader.h"
+
class GrSweepGradient : public GrGradientEffect {
public:
class GLSLSweepProcessor;
@@ -216,6 +218,13 @@
std::unique_ptr<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(
const GrFPArgs& args) const {
+
+ // Try to use new gradient system first
+ std::unique_ptr<GrFragmentProcessor> gradient = GrGradientShader::MakeSweep(*this, args);
+ if (gradient) {
+ return gradient;
+ }
+
SkMatrix matrix;
if (!this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
return nullptr;
diff --git a/src/shaders/gradients/SkSweepGradient.h b/src/shaders/gradients/SkSweepGradient.h
index a58c957..8957b47 100644
--- a/src/shaders/gradients/SkSweepGradient.h
+++ b/src/shaders/gradients/SkSweepGradient.h
@@ -20,6 +20,10 @@
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif
+ SkScalar getTBias() const { return fTBias; }
+
+ SkScalar getTScale() const { return fTScale; }
+
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSweepGradient)
protected:
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index f1c9ed6..bf9e5e1 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -136,6 +136,7 @@
CAP(mustEnableSpecificAdvBlendEqs);
CAP(mustDeclareFragmentShaderOutput);
CAP(mustDoOpBetweenFloorAndAbs);
+ CAP(atan2ImplementedAsAtanYOverX);
CAP(canUseAnyFunctionInShader);
CAP(floatIs32Bits);
CAP(integerSupport);
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index 1654562..b624b58 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -57,6 +57,10 @@
return k400_GrGLSLGeneration;
}
+ bool atan2ImplementedAsAtanYOverX() const {
+ return false;
+ }
+
bool canUseMinAndAbsTogether() const {
return true;
}