Port gradient unit tests over to new FPs
Previously, the GPU gradient tests were included in the SkXGradient
implementation and provided a processor factory that used the public
SkGradientShader::MakeX() end points to get at the final GrFragmentProcessor.
This factory approach is maintained as well, so there are no individual
tests for the specific colorizers. The tests are added to the layouts that
correspond to the public gradient constructor.
Bug: skia:
Change-Id: Iac74d8490efd0fb7395ad9fc0581906abb815742
Reviewed-on: https://skia-review.googlesource.com/151548
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index aafe1d8..17bed51 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -57,7 +57,7 @@
* we verify the count is as expected. If a new factory is added, then these numbers must be
* manually adjusted.
*/
-static const int kFPFactoryCount = 36;
+static const int kFPFactoryCount = 40;
static const int kGPFactoryCount = 14;
static const int kXPFactoryCount = 4;
diff --git a/src/gpu/gradients/GrGradientShader.cpp b/src/gpu/gradients/GrGradientShader.cpp
index b4d2b65..4dbadef 100644
--- a/src/gpu/gradients/GrGradientShader.cpp
+++ b/src/gpu/gradients/GrGradientShader.cpp
@@ -217,4 +217,42 @@
return make_gradient(shader, args, GrTwoPointConicalGradientLayout::Make(shader, args));
}
+#if GR_TEST_UTILS
+RandomParams::RandomParams(SkRandom* random) {
+ // Set color count to min of 2 so that we don't trigger the const color optimization and make
+ // a non-gradient processor.
+ fColorCount = random->nextRangeU(2, kMaxRandomGradientColors);
+ fUseColors4f = random->nextBool();
+
+ // if one color, omit stops, otherwise randomly decide whether or not to
+ if (fColorCount == 1 || (fColorCount >= 2 && random->nextBool())) {
+ fStops = nullptr;
+ } else {
+ fStops = fStopStorage;
+ }
+
+ // if using SkColor4f, attach a random (possibly null) color space (with linear gamma)
+ if (fUseColors4f) {
+ fColorSpace = GrTest::TestColorSpace(random);
+ }
+
+ SkScalar stop = 0.f;
+ for (int i = 0; i < fColorCount; ++i) {
+ if (fUseColors4f) {
+ fColors4f[i].fR = random->nextUScalar1();
+ fColors4f[i].fG = random->nextUScalar1();
+ fColors4f[i].fB = random->nextUScalar1();
+ fColors4f[i].fA = random->nextUScalar1();
+ } else {
+ fColors[i] = random->nextU();
+ }
+ if (fStops) {
+ fStops[i] = stop;
+ stop = i < fColorCount - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
+ }
+ }
+ fTileMode = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
+}
+#endif
+
}
diff --git a/src/gpu/gradients/GrGradientShader.h b/src/gpu/gradients/GrGradientShader.h
index 78888ae..28a0d4a 100644
--- a/src/gpu/gradients/GrGradientShader.h
+++ b/src/gpu/gradients/GrGradientShader.h
@@ -27,6 +27,30 @@
std::unique_ptr<GrFragmentProcessor> MakeConical(const SkTwoPointConicalGradient& shader,
const GrFPArgs& args);
+
+#if GR_TEST_UTILS
+ /** Helper struct that stores (and populates) parameters to construct a random gradient.
+ If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
+ fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
+ will be the number of color stops in either case, and fColors and fStops can be passed to
+ the gradient factory. (The constructor may decide not to use stops, in which case fStops
+ will be nullptr). */
+ struct RandomParams {
+ static constexpr int kMaxRandomGradientColors = 5;
+
+ RandomParams(SkRandom* r);
+
+ bool fUseColors4f;
+ SkColor fColors[kMaxRandomGradientColors];
+ SkColor4f fColors4f[kMaxRandomGradientColors];
+ sk_sp<SkColorSpace> fColorSpace;
+ SkScalar fStopStorage[kMaxRandomGradientColors];
+ SkShader::TileMode fTileMode;
+ int fColorCount;
+ SkScalar* fStops;
+ };
+#endif
+
}
#endif // GrGradientShader_DEFINE
diff --git a/src/gpu/gradients/GrLinearGradientLayout.cpp b/src/gpu/gradients/GrLinearGradientLayout.cpp
index 8a2b5e5..e28bd77 100644
--- a/src/gpu/gradients/GrLinearGradientLayout.cpp
+++ b/src/gpu/gradients/GrLinearGradientLayout.cpp
@@ -53,6 +53,25 @@
std::unique_ptr<GrFragmentProcessor> GrLinearGradientLayout::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrLinearGradientLayout(*this));
}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradientLayout);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrLinearGradientLayout::TestCreate(GrProcessorTestData* d) {
+ SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()},
+ {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}};
+
+ GrGradientShader::RandomParams params(d->fRandom);
+ auto shader = params.fUseColors4f
+ ? SkGradientShader::MakeLinear(points, params.fColors4f,
+ params.fColorSpace, params.fStops,
+ params.fColorCount, params.fTileMode)
+ : SkGradientShader::MakeLinear(points, params.fColors, params.fStops,
+ params.fColorCount, params.fTileMode);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+ GrAlwaysAssert(fp);
+ return fp;
+}
+#endif
std::unique_ptr<GrFragmentProcessor> GrLinearGradientLayout::Make(const SkLinearGradient& grad,
const GrFPArgs& args) {
diff --git a/src/gpu/gradients/GrLinearGradientLayout.fp b/src/gpu/gradients/GrLinearGradientLayout.fp
index 6eaf8b1..8e8647d 100644
--- a/src/gpu/gradients/GrLinearGradientLayout.fp
+++ b/src/gpu/gradients/GrLinearGradientLayout.fp
@@ -20,6 +20,7 @@
@header {
#include "SkLinearGradient.h"
+ #include "GrGradientShader.h"
}
// The linear gradient never rejects a pixel so it doesn't change opacity
@@ -43,3 +44,21 @@
return std::unique_ptr<GrFragmentProcessor>(new GrLinearGradientLayout(matrix));
}
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+@test(d) {
+ SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()},
+ {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}};
+
+ GrGradientShader::RandomParams params(d->fRandom);
+ auto shader = params.fUseColors4f ?
+ SkGradientShader::MakeLinear(points, params.fColors4f, params.fColorSpace, params.fStops,
+ params.fColorCount, params.fTileMode) :
+ SkGradientShader::MakeLinear(points, params.fColors, params.fStops,
+ params.fColorCount, params.fTileMode);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+ GrAlwaysAssert(fp);
+ return fp;
+}
diff --git a/src/gpu/gradients/GrLinearGradientLayout.h b/src/gpu/gradients/GrLinearGradientLayout.h
index f128f34..76ed59a 100644
--- a/src/gpu/gradients/GrLinearGradientLayout.h
+++ b/src/gpu/gradients/GrLinearGradientLayout.h
@@ -13,6 +13,7 @@
#include "SkTypes.h"
#include "SkLinearGradient.h"
+#include "GrGradientShader.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrLinearGradientLayout : public GrFragmentProcessor {
diff --git a/src/gpu/gradients/GrRadialGradientLayout.cpp b/src/gpu/gradients/GrRadialGradientLayout.cpp
index c00afd2..85aa065 100644
--- a/src/gpu/gradients/GrRadialGradientLayout.cpp
+++ b/src/gpu/gradients/GrRadialGradientLayout.cpp
@@ -53,6 +53,28 @@
std::unique_ptr<GrFragmentProcessor> GrRadialGradientLayout::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrRadialGradientLayout(*this));
}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadialGradientLayout);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrRadialGradientLayout::TestCreate(GrProcessorTestData* d) {
+ sk_sp<SkShader> shader;
+ do {
+ GrGradientShader::RandomParams params(d->fRandom);
+ SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+ SkScalar radius = d->fRandom->nextUScalar1();
+ shader = params.fUseColors4f
+ ? SkGradientShader::MakeRadial(center, radius, params.fColors4f,
+ params.fColorSpace, params.fStops,
+ params.fColorCount, params.fTileMode)
+ : SkGradientShader::MakeRadial(center, radius, params.fColors,
+ params.fStops, params.fColorCount,
+ params.fTileMode);
+ } while (!shader);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+ GrAlwaysAssert(fp);
+ return fp;
+}
+#endif
std::unique_ptr<GrFragmentProcessor> GrRadialGradientLayout::Make(const SkRadialGradient& grad,
const GrFPArgs& args) {
diff --git a/src/gpu/gradients/GrRadialGradientLayout.fp b/src/gpu/gradients/GrRadialGradientLayout.fp
index 7d6c5c8..6db6775 100644
--- a/src/gpu/gradients/GrRadialGradientLayout.fp
+++ b/src/gpu/gradients/GrRadialGradientLayout.fp
@@ -20,6 +20,7 @@
@header {
#include "SkRadialGradient.h"
+ #include "GrGradientShader.h"
}
// The radial gradient never rejects a pixel so it doesn't change opacity
@@ -43,3 +44,25 @@
return std::unique_ptr<GrFragmentProcessor>(new GrRadialGradientLayout(matrix));
}
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+@test(d) {
+ sk_sp<SkShader> shader;
+ do {
+ GrGradientShader::RandomParams params(d->fRandom);
+ SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+ SkScalar radius = d->fRandom->nextUScalar1();
+ shader = params.fUseColors4f
+ ? SkGradientShader::MakeRadial(center, radius, params.fColors4f,
+ params.fColorSpace, params.fStops,
+ params.fColorCount, params.fTileMode)
+ : SkGradientShader::MakeRadial(center, radius, params.fColors,
+ params.fStops, params.fColorCount,
+ params.fTileMode);
+ } while (!shader);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+ GrAlwaysAssert(fp);
+ return fp;
+}
diff --git a/src/gpu/gradients/GrRadialGradientLayout.h b/src/gpu/gradients/GrRadialGradientLayout.h
index 7af6a64..aeff4d5 100644
--- a/src/gpu/gradients/GrRadialGradientLayout.h
+++ b/src/gpu/gradients/GrRadialGradientLayout.h
@@ -13,6 +13,7 @@
#include "SkTypes.h"
#include "SkRadialGradient.h"
+#include "GrGradientShader.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrRadialGradientLayout : public GrFragmentProcessor {
diff --git a/src/gpu/gradients/GrSweepGradientLayout.cpp b/src/gpu/gradients/GrSweepGradientLayout.cpp
index d527f36..2d40252 100644
--- a/src/gpu/gradients/GrSweepGradientLayout.cpp
+++ b/src/gpu/gradients/GrSweepGradientLayout.cpp
@@ -90,6 +90,24 @@
std::unique_ptr<GrFragmentProcessor> GrSweepGradientLayout::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrSweepGradientLayout(*this));
}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradientLayout);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrSweepGradientLayout::TestCreate(GrProcessorTestData* d) {
+ SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+
+ GrGradientShader::RandomParams params(d->fRandom);
+ auto shader = params.fUseColors4f
+ ? SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors4f,
+ params.fColorSpace, params.fStops,
+ params.fColorCount)
+ : SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors,
+ params.fStops, params.fColorCount);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+ GrAlwaysAssert(fp);
+ return fp;
+}
+#endif
std::unique_ptr<GrFragmentProcessor> GrSweepGradientLayout::Make(const SkSweepGradient& grad,
const GrFPArgs& args) {
diff --git a/src/gpu/gradients/GrSweepGradientLayout.fp b/src/gpu/gradients/GrSweepGradientLayout.fp
index d704d9f..6698aa6 100644
--- a/src/gpu/gradients/GrSweepGradientLayout.fp
+++ b/src/gpu/gradients/GrSweepGradientLayout.fp
@@ -37,6 +37,7 @@
@header {
#include "SkSweepGradient.h"
+ #include "GrGradientShader.h"
}
// The sweep gradient never rejects a pixel so it doesn't change opacity
@@ -61,3 +62,20 @@
matrix, grad.getTBias(), grad.getTScale()));
}
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+@test(d) {
+ SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+
+ GrGradientShader::RandomParams params(d->fRandom);
+ auto shader = params.fUseColors4f ?
+ SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors4f, params.fColorSpace,
+ params.fStops, params.fColorCount) :
+ SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors,
+ params.fStops, params.fColorCount);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+ GrAlwaysAssert(fp);
+ return fp;
+}
diff --git a/src/gpu/gradients/GrSweepGradientLayout.h b/src/gpu/gradients/GrSweepGradientLayout.h
index 293ada1..c0ceef3 100644
--- a/src/gpu/gradients/GrSweepGradientLayout.h
+++ b/src/gpu/gradients/GrSweepGradientLayout.h
@@ -13,6 +13,7 @@
#include "SkTypes.h"
#include "SkSweepGradient.h"
+#include "GrGradientShader.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrSweepGradientLayout : public GrFragmentProcessor {
diff --git a/src/gpu/gradients/GrTwoPointConicalGradientLayout.cpp b/src/gpu/gradients/GrTwoPointConicalGradientLayout.cpp
index cd67661..291c867 100644
--- a/src/gpu/gradients/GrTwoPointConicalGradientLayout.cpp
+++ b/src/gpu/gradients/GrTwoPointConicalGradientLayout.cpp
@@ -146,6 +146,80 @@
std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrTwoPointConicalGradientLayout(*this));
}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTwoPointConicalGradientLayout);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::TestCreate(
+ GrProcessorTestData* d) {
+ SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+ SkPoint center2 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+ SkScalar radius1 = d->fRandom->nextUScalar1();
+ SkScalar radius2 = d->fRandom->nextUScalar1();
+
+ constexpr int kTestTypeMask = (1 << 2) - 1, kTestNativelyFocalBit = (1 << 2),
+ kTestFocalOnCircleBit = (1 << 3), kTestSwappedBit = (1 << 4);
+ // We won't treat isWellDefined and isRadiusIncreasing specially because they
+ // should have high probability to be turned on and off as we're getting random
+ // radii and centers.
+
+ int mask = d->fRandom->nextU();
+ int type = mask & kTestTypeMask;
+ if (type == static_cast<int>(Type::kRadial)) {
+ center2 = center1;
+ // Make sure that the radii are different
+ if (SkScalarNearlyZero(radius1 - radius2)) {
+ radius2 += .1f;
+ }
+ } else if (type == static_cast<int>(Type::kStrip)) {
+ radius1 = SkTMax(radius1, .1f); // Make sure that the radius is non-zero
+ radius2 = radius1;
+ // Make sure that the centers are different
+ if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) {
+ center2.fX += .1f;
+ }
+ } else { // kFocal_Type
+ // Make sure that the centers are different
+ if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) {
+ center2.fX += .1f;
+ }
+
+ if (kTestNativelyFocalBit & mask) {
+ radius1 = 0;
+ }
+ if (kTestFocalOnCircleBit & mask) {
+ radius2 = radius1 + SkPoint::Distance(center1, center2);
+ }
+ if (kTestSwappedBit & mask) {
+ std::swap(radius1, radius2);
+ radius2 = 0;
+ }
+
+ // Make sure that the radii are different
+ if (SkScalarNearlyZero(radius1 - radius2)) {
+ radius2 += .1f;
+ }
+ }
+
+ if (SkScalarNearlyZero(radius1 - radius2) &&
+ SkScalarNearlyZero(SkPoint::Distance(center1, center2))) {
+ radius2 += .1f; // make sure that we're not degenerated
+ }
+
+ GrGradientShader::RandomParams params(d->fRandom);
+ auto shader = params.fUseColors4f
+ ? SkGradientShader::MakeTwoPointConical(
+ center1, radius1, center2, radius2, params.fColors4f,
+ params.fColorSpace, params.fStops, params.fColorCount,
+ params.fTileMode)
+ : SkGradientShader::MakeTwoPointConical(
+ center1, radius1, center2, radius2, params.fColors,
+ params.fStops, params.fColorCount, params.fTileMode);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+
+ GrAlwaysAssert(fp);
+ return fp;
+}
+#endif
// .fp files do not let you reference outside enum definitions, so we have to explicitly map
// between the two compatible enum defs
diff --git a/src/gpu/gradients/GrTwoPointConicalGradientLayout.fp b/src/gpu/gradients/GrTwoPointConicalGradientLayout.fp
index 3aebd3b..f7d9860 100644
--- a/src/gpu/gradients/GrTwoPointConicalGradientLayout.fp
+++ b/src/gpu/gradients/GrTwoPointConicalGradientLayout.fp
@@ -120,6 +120,7 @@
@header {
#include "SkTwoPointConicalGradient.h"
+ #include "GrGradientShader.h"
}
// The 2 point conical gradient can reject a pixel so it does change opacity
@@ -214,3 +215,77 @@
isSwapped, isNativelyFocal, focalParams));
}
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+@test(d) {
+ SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+ SkPoint center2 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
+ SkScalar radius1 = d->fRandom->nextUScalar1();
+ SkScalar radius2 = d->fRandom->nextUScalar1();
+
+ constexpr int kTestTypeMask = (1 << 2) - 1,
+ kTestNativelyFocalBit = (1 << 2),
+ kTestFocalOnCircleBit = (1 << 3),
+ kTestSwappedBit = (1 << 4);
+ // We won't treat isWellDefined and isRadiusIncreasing specially because they
+ // should have high probability to be turned on and off as we're getting random
+ // radii and centers.
+
+ int mask = d->fRandom->nextU();
+ int type = mask & kTestTypeMask;
+ if (type == static_cast<int>(Type::kRadial)) {
+ center2 = center1;
+ // Make sure that the radii are different
+ if (SkScalarNearlyZero(radius1 - radius2)) {
+ radius2 += .1f;
+ }
+ } else if (type == static_cast<int>(Type::kStrip)) {
+ radius1 = SkTMax(radius1, .1f); // Make sure that the radius is non-zero
+ radius2 = radius1;
+ // Make sure that the centers are different
+ if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) {
+ center2.fX += .1f;
+ }
+ } else { // kFocal_Type
+ // Make sure that the centers are different
+ if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) {
+ center2.fX += .1f;
+ }
+
+ if (kTestNativelyFocalBit & mask) {
+ radius1 = 0;
+ }
+ if (kTestFocalOnCircleBit & mask) {
+ radius2 = radius1 + SkPoint::Distance(center1, center2);
+ }
+ if (kTestSwappedBit & mask) {
+ std::swap(radius1, radius2);
+ radius2 = 0;
+ }
+
+ // Make sure that the radii are different
+ if (SkScalarNearlyZero(radius1 - radius2)) {
+ radius2 += .1f;
+ }
+ }
+
+ if (SkScalarNearlyZero(radius1 - radius2) &&
+ SkScalarNearlyZero(SkPoint::Distance(center1, center2))) {
+ radius2 += .1f; // make sure that we're not degenerated
+ }
+
+ GrGradientShader::RandomParams params(d->fRandom);
+ auto shader = params.fUseColors4f ?
+ SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
+ params.fColors4f, params.fColorSpace, params.fStops,
+ params.fColorCount, params.fTileMode) :
+ SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
+ params.fColors, params.fStops,
+ params.fColorCount, params.fTileMode);
+ GrTest::TestAsFPArgs asFPArgs(d);
+ std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
+
+ GrAlwaysAssert(fp);
+ return fp;
+}
diff --git a/src/gpu/gradients/GrTwoPointConicalGradientLayout.h b/src/gpu/gradients/GrTwoPointConicalGradientLayout.h
index 0c1233c..ab833d4 100644
--- a/src/gpu/gradients/GrTwoPointConicalGradientLayout.h
+++ b/src/gpu/gradients/GrTwoPointConicalGradientLayout.h
@@ -13,6 +13,7 @@
#include "SkTypes.h"
#include "SkTwoPointConicalGradient.h"
+#include "GrGradientShader.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrTwoPointConicalGradientLayout : public GrFragmentProcessor {