aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/gradients.cpp38
-rw-r--r--gm/tilemodes.cpp3
-rw-r--r--include/core/SkPicture.h3
-rw-r--r--include/effects/SkGradientShader.h65
-rw-r--r--src/core/SkReadBuffer.h1
-rw-r--r--src/shaders/gradients/SkGradientShader.cpp26
-rw-r--r--src/shaders/gradients/SkSweepGradient.cpp131
-rw-r--r--src/shaders/gradients/SkSweepGradient.h6
8 files changed, 206 insertions, 67 deletions
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
index 9abd6f0e9a..85ac6906da 100644
--- a/gm/gradients.cpp
+++ b/gm/gradients.cpp
@@ -1033,3 +1033,41 @@ DEF_SIMPLE_GM(fancy_gradients, canvas, 800, 300) {
SkBlendMode::kExclusion);
});
}
+
+DEF_SIMPLE_GM(sweep_tiling, canvas, 512, 512) {
+ static constexpr SkScalar size = 160;
+ static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorYELLOW, SK_ColorGREEN };
+ static constexpr SkScalar pos[] = { 0, .25f, .50f };
+ static_assert(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(pos), "size mismatch");
+
+ static constexpr SkShader::TileMode modes[] = { SkShader::kClamp_TileMode,
+ SkShader::kRepeat_TileMode,
+ SkShader::kMirror_TileMode };
+
+ static const struct {
+ SkScalar start, end;
+ } angles[] = {
+ { -330, -270 },
+ { 30, 90 },
+ { 390, 450 },
+ };
+
+ SkPaint p;
+ const SkRect r = SkRect::MakeWH(size, size);
+
+ for (auto mode : modes) {
+ {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ for (auto angle : angles) {
+ p.setShader(SkGradientShader::MakeSweep(size / 2, size / 2, colors, pos,
+ SK_ARRAY_COUNT(colors), mode,
+ angle.start, angle.end, 0, nullptr));
+
+ canvas->drawRect(r, p);
+ canvas->translate(size * 1.1f, 0);
+ }
+ }
+ canvas->translate(0, size * 1.1f);
+ }
+}
diff --git a/gm/tilemodes.cpp b/gm/tilemodes.cpp
index 390ce4adcd..f6bd362813 100644
--- a/gm/tilemodes.cpp
+++ b/gm/tilemodes.cpp
@@ -177,7 +177,8 @@ static sk_sp<SkShader> make_grad(SkShader::TileMode tx, SkShader::TileMode ty) {
case 1:
return SkGradientShader::MakeRadial(center, rad, colors, nullptr, SK_ARRAY_COUNT(colors), tx);
case 2:
- return SkGradientShader::MakeSweep(center.fX, center.fY, colors, nullptr, SK_ARRAY_COUNT(colors));
+ return SkGradientShader::MakeSweep(center.fX, center.fY, colors, nullptr,
+ SK_ARRAY_COUNT(colors), tx, 135, 225, 0, nullptr);
}
return nullptr;
}
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index bd4dc9a7de..891c11dae5 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -199,10 +199,11 @@ private:
// V54: ComposeShader can use a Mode or a Lerp
// V55: Drop blendmode[] from MergeImageFilter
// V56: Add TileMode in SkBlurImageFilter.
+ // V57: Sweep tiling info.
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 51; // Produced by Chrome ~M56.
- static const uint32_t CURRENT_PICTURE_VERSION = 56;
+ static const uint32_t CURRENT_PICTURE_VERSION = 57;
static bool IsValidPictInfo(const SkPictInfo& info);
static sk_sp<SkPicture> Forwardport(const SkPictInfo&,
diff --git a/include/effects/SkGradientShader.h b/include/effects/SkGradientShader.h
index 393749be65..a4408ad9c3 100644
--- a/include/effects/SkGradientShader.h
+++ b/include/effects/SkGradientShader.h
@@ -158,44 +158,69 @@ public:
/** Returns a shader that generates a sweep gradient given a center.
<p />
- @param cx The X coordinate of the center of the sweep
- @param cx The Y coordinate of the center of the sweep
- @param colors The array[count] of colors, to be distributed around the center.
- @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
- each corresponding color in the colors array. If this is NULL,
- the the colors are distributed evenly between the center and edge of the circle.
- If this is not null, the values must begin with 0, end with 1.0, and
- intermediate values must be strictly increasing.
- @param count Must be >= 2. The number of colors (and pos if not NULL) entries
+ @param cx The X coordinate of the center of the sweep
+ @param cx The Y coordinate of the center of the sweep
+ @param colors The array[count] of colors, to be distributed around the center, within
+ the gradient angle range.
+ @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative
+ position of each corresponding color in the colors array. If this is
+ NULL, then the colors are distributed evenly within the angular range.
+ If this is not null, the values must begin with 0, end with 1.0, and
+ intermediate values must be strictly increasing.
+ @param count Must be >= 2. The number of colors (and pos if not NULL) entries
+ @param mode Tiling mode: controls drawing outside of the gradient angular range.
+ @param startAngle Start of the angular range, corresponding to pos == 0.
+ @param endAngle End of the angular range, corresponding to pos == 1.
*/
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
const SkColor colors[], const SkScalar pos[], int count,
+ SkShader::TileMode mode,
+ SkScalar startAngle, SkScalar endAngle,
uint32_t flags, const SkMatrix* localMatrix);
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
+ const SkColor colors[], const SkScalar pos[], int count,
+ uint32_t flags, const SkMatrix* localMatrix) {
+ return MakeSweep(cx, cy, colors, pos, count, SkShader::kClamp_TileMode, 0, 360, flags,
+ localMatrix);
+ }
+ static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
const SkColor colors[], const SkScalar pos[], int count) {
- return MakeSweep(cx, cy, colors, pos, count, 0, NULL);
+ return MakeSweep(cx, cy, colors, pos, count, 0, nullptr);
}
/** Returns a shader that generates a sweep gradient given a center.
<p />
- @param cx The X coordinate of the center of the sweep
- @param cx The Y coordinate of the center of the sweep
- @param colors The array[count] of colors, to be distributed around the center.
- @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
- each corresponding color in the colors array. If this is NULL,
- the the colors are distributed evenly between the center and edge of the circle.
- If this is not null, the values must begin with 0, end with 1.0, and
- intermediate values must be strictly increasing.
- @param count Must be >= 2. The number of colors (and pos if not NULL) entries
+ @param cx The X coordinate of the center of the sweep
+ @param cx The Y coordinate of the center of the sweep
+ @param colors The array[count] of colors, to be distributed around the center, within
+ the gradient angle range.
+ @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative
+ position of each corresponding color in the colors array. If this is
+ NULL, then the colors are distributed evenly within the angular range.
+ If this is not null, the values must begin with 0, end with 1.0, and
+ intermediate values must be strictly increasing.
+ @param count Must be >= 2. The number of colors (and pos if not NULL) entries
+ @param mode Tiling mode: controls drawing outside of the gradient angular range.
+ @param startAngle Start of the angular range, corresponding to pos == 0.
+ @param endAngle End of the angular range, corresponding to pos == 1.
*/
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
const SkScalar pos[], int count,
+ SkShader::TileMode mode,
+ SkScalar startAngle, SkScalar endAngle,
uint32_t flags, const SkMatrix* localMatrix);
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count,
+ uint32_t flags, const SkMatrix* localMatrix) {
+ return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count,
+ SkShader::kClamp_TileMode, 0, 360, flags, localMatrix);
+ }
+ static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
const SkScalar pos[], int count) {
- return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, NULL);
+ return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, nullptr);
}
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index dd0484c450..0653ab6865 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -74,6 +74,7 @@ public:
kComposeShaderCanLerp_Version = 54,
kNoModesInMergeImageFilter_Verison = 55,
kTileModeInBlurImageFilter_Version = 56,
+ kTileInfoInSweepGradient_Version = 57,
};
/**
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index e2989e67f1..a203e88333 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -1228,11 +1228,14 @@ sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
const SkColor colors[],
const SkScalar pos[],
int colorCount,
+ SkShader::TileMode mode,
+ SkScalar startAngle,
+ SkScalar endAngle,
uint32_t flags,
const SkMatrix* localMatrix) {
ColorConverter converter(colors, colorCount);
- return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, flags,
- localMatrix);
+ return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount,
+ mode, startAngle, endAngle, flags, localMatrix);
}
sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
@@ -1240,26 +1243,39 @@ sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
sk_sp<SkColorSpace> colorSpace,
const SkScalar pos[],
int colorCount,
+ SkShader::TileMode mode,
+ SkScalar startAngle,
+ SkScalar endAngle,
uint32_t flags,
const SkMatrix* localMatrix) {
- if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
+ if (!valid_grad(colors, pos, colorCount, mode)) {
return nullptr;
}
if (1 == colorCount) {
return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
}
+ if (startAngle >= endAngle) {
+ return nullptr;
+ }
if (localMatrix && !localMatrix->invert(nullptr)) {
return nullptr;
}
- auto mode = SkShader::kClamp_TileMode;
+ if (startAngle <= 0 && endAngle >= 360) {
+ // If the t-range includes [0,1], then we can always use clamping (presumably faster).
+ mode = SkShader::kClamp_TileMode;
+ }
ColorStopOptimizer opt(colors, pos, colorCount, mode);
SkGradientShaderBase::Descriptor desc;
desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
localMatrix);
- return sk_make_sp<SkSweepGradient>(cx, cy, desc);
+
+ const SkScalar t0 = startAngle / 360,
+ t1 = endAngle / 360;
+
+ return sk_make_sp<SkSweepGradient>(SkPoint::Make(cx, cy), t0, t1, desc);
}
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
diff --git a/src/shaders/gradients/SkSweepGradient.cpp b/src/shaders/gradients/SkSweepGradient.cpp
index e70066a4d4..c4003bfd42 100644
--- a/src/shaders/gradients/SkSweepGradient.cpp
+++ b/src/shaders/gradients/SkSweepGradient.cpp
@@ -11,18 +11,14 @@
#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"
-static SkMatrix translate(SkScalar dx, SkScalar dy) {
- SkMatrix matrix;
- matrix.setTranslate(dx, dy);
- return matrix;
-}
-
-SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc)
- : SkGradientShaderBase(desc, translate(-cx, -cy))
- , fCenter(SkPoint::Make(cx, cy))
+SkSweepGradient::SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1,
+ const Descriptor& desc)
+ : SkGradientShaderBase(desc, SkMatrix::MakeTrans(-center.x(), -center.y()))
+ , fCenter(center)
+ , fTBias(-t0)
+ , fTScale(1 / (t1 - t0))
{
- // overwrite the tilemode to a canonical value (since sweep ignores it)
- fTileMode = SkShader::kClamp_TileMode;
+ SkASSERT(t0 < t1);
}
SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
@@ -39,14 +35,27 @@ sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
return nullptr;
}
const SkPoint center = buffer.readPoint();
+
+ SkScalar startAngle = 0,
+ endAngle = 360;
+ if (!buffer.isVersionLT(SkReadBuffer::kTileInfoInSweepGradient_Version)) {
+ const auto tBias = buffer.readScalar(),
+ tScale = buffer.readScalar();
+ startAngle = -tBias * 360;
+ endAngle = (1 / tScale - tBias) * 360;
+ }
+
return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
std::move(desc.fColorSpace), desc.fPos, desc.fCount,
+ desc.fTileMode, startAngle, endAngle,
desc.fGradFlags, desc.fLocalMatrix);
}
void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writePoint(fCenter);
+ buffer.writeScalar(fTBias);
+ buffer.writeScalar(fTScale);
}
/////////////////////////////////////////////////////////////////////
@@ -62,8 +71,9 @@ class GrSweepGradient : public GrGradientEffect {
public:
class GLSLSweepProcessor;
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
- auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args));
+ static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar tBias,
+ SkScalar tScale) {
+ auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args, tBias, tScale));
return processor->isValid() ? std::move(processor) : nullptr;
}
@@ -74,12 +84,17 @@ public:
}
private:
- explicit GrSweepGradient(const CreateArgs& args)
- : INHERITED(args, args.fShader->colorsAreOpaque()) {
+ explicit GrSweepGradient(const CreateArgs& args, SkScalar tBias, SkScalar tScale)
+ : INHERITED(args, args.fShader->colorsAreOpaque())
+ , fTBias(tBias)
+ , fTScale(tScale){
this->initClassID<GrSweepGradient>();
}
- explicit GrSweepGradient(const GrSweepGradient& that) : INHERITED(that) {
+ explicit GrSweepGradient(const GrSweepGradient& that)
+ : INHERITED(that)
+ , fTBias(that.fTBias)
+ , fTScale(that.fTScale) {
this->initClassID<GrSweepGradient>();
}
@@ -88,8 +103,18 @@ private:
virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const override;
+ bool onIsEqual(const GrFragmentProcessor& base) const override {
+ const GrSweepGradient& fp = base.cast<GrSweepGradient>();
+ return INHERITED::onIsEqual(base)
+ && fTBias == fp.fTBias
+ && fTScale == fp.fTScale;
+ }
+
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+ SkScalar fTBias;
+ SkScalar fTScale;
+
typedef GrGradientEffect INHERITED;
};
@@ -97,17 +122,38 @@ private:
class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor {
public:
- GLSLSweepProcessor(const GrProcessor&) {}
+ GLSLSweepProcessor(const GrProcessor&)
+ : fCachedTBias(SK_FloatNaN)
+ , fCachedTScale(SK_FloatNaN) {}
- virtual void emitCode(EmitArgs&) override;
+ void emitCode(EmitArgs&) override;
- static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
+ static void GenKey(const GrProcessor& processor, const GrShaderCaps&,
+ GrProcessorKeyBuilder* b) {
b->add32(GenBaseGradientKey(processor));
}
+protected:
+ void onSetData(const GrGLSLProgramDataManager& pdman,
+ const GrFragmentProcessor& processor) override {
+ INHERITED::onSetData(pdman, processor);
+ const GrSweepGradient& data = processor.cast<GrSweepGradient>();
+
+ if (fCachedTBias != data.fTBias || fCachedTScale != data.fTScale) {
+ fCachedTBias = data.fTBias;
+ fCachedTScale = data.fTScale;
+ pdman.set2f(fTBiasScaleUni, fCachedTBias, fCachedTScale);
+ }
+ }
+
private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
+ UniformHandle fTBiasScaleUni;
+
+ // Uploaded uniform values.
+ float fCachedTBias,
+ fCachedTScale;
+ typedef GrGradientEffect::GLSLProcessor INHERITED;
};
/////////////////////////////////////////////////////////////////////
@@ -147,22 +193,28 @@ sk_sp<GrFragmentProcessor> GrSweepGradient::TestCreate(GrProcessorTestData* d) {
void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) {
const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>();
- this->emitUniforms(args.fUniformHandler, ge);
- SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
- SkString t;
+ GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
+ this->emitUniforms(uniformHandler, ge);
+ fTBiasScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType,
+ kDefault_GrSLPrecision, "SweepFSParams");
+ const char* tBiasScaleV = uniformHandler->getUniformCStr(fTBiasScaleUni);
+
+ const SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
+
+ // 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.
+ const SkString atan = args.fShaderCaps->atan2ImplementedAsAtanYOverX()
+ ? SkStringPrintf("2.0 * atan(- %s.y, length(%s) - %s.x)",
+ coords2D.c_str(), coords2D.c_str(), coords2D.c_str())
+ : SkStringPrintf("atan(- %s.y, - %s.x)", coords2D.c_str(), coords2D.c_str());
+
// 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
- if (args.fShaderCaps->atan2ImplementedAsAtanYOverX()) {
- // 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.
- t.printf("(2.0 * atan(- %s.y, length(%s) - %s.x) * 0.1591549430918 + 0.5)",
- coords2D.c_str(), coords2D.c_str(), coords2D.c_str());
- } else {
- t.printf("(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5)",
- coords2D.c_str(), coords2D.c_str());
- }
+ const SkString t = SkStringPrintf("((%s * 0.1591549430918 + 0.5 + %s[0]) * %s[1])",
+ atan.c_str(), tBiasScaleV, tBiasScaleV);
+
this->emitColor(args.fFragBuilder,
args.fUniformHandler,
args.fShaderCaps,
@@ -192,8 +244,9 @@ sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs&
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
args.fDstColorSpace);
sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make(
- GrGradientEffect::CreateArgs(args.fContext, this, &matrix, SkShader::kClamp_TileMode,
- std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
+ GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
+ std::move(colorSpaceXform), SkToBool(args.fDstColorSpace)),
+ fTBias, fTScale));
if (!inner) {
return nullptr;
}
@@ -224,9 +277,11 @@ void SkSweepGradient::toString(SkString* str) const {
str->append(")");
}
-void SkSweepGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p,
+void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p,
SkRasterPipeline*) const {
p->append(SkRasterPipeline::xy_to_unit_angle);
+ p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeScale(fTScale, 1),
+ SkMatrix::MakeTrans(fTBias , 0)));
}
#endif
diff --git a/src/shaders/gradients/SkSweepGradient.h b/src/shaders/gradients/SkSweepGradient.h
index 647b454ab5..92d3411b01 100644
--- a/src/shaders/gradients/SkSweepGradient.h
+++ b/src/shaders/gradients/SkSweepGradient.h
@@ -12,7 +12,7 @@
class SkSweepGradient final : public SkGradientShaderBase {
public:
- SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&);
+ SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1, const Descriptor&);
GradientType asAGradient(GradientInfo* info) const override;
@@ -33,7 +33,9 @@ protected:
bool onIsRasterPipelineOnly() const override { return true; }
private:
- const SkPoint fCenter;
+ const SkPoint fCenter;
+ const SkScalar fTBias,
+ fTScale;
friend class SkGradientShader;
typedef SkGradientShaderBase INHERITED;