Tiling support for SkSweepGradient
Expand the sweep gradient definition to include a color stop angular range ([0, 360] by default). Color stop positions in [0,1] are mapped to this range, and drawing outside is controlled by a tile mode param. This is closer to the CSS gradients spec and allows us to use fewer color stops in Blink conic gradients. Impl-wise, the remapping is effected after t calculation, and before tiling. Change-Id: I5d71be01d134404d6eb9d7e2a904ec636b39f855 Reviewed-on: https://skia-review.googlesource.com/27704 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
ce06e261e6
commit
5a9a981edf
@ -1033,3 +1033,41 @@ DEF_SIMPLE_GM(fancy_gradients, canvas, 800, 300) {
|
|||||||
SkBlendMode::kExclusion);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -177,7 +177,8 @@ static sk_sp<SkShader> make_grad(SkShader::TileMode tx, SkShader::TileMode ty) {
|
|||||||
case 1:
|
case 1:
|
||||||
return SkGradientShader::MakeRadial(center, rad, colors, nullptr, SK_ARRAY_COUNT(colors), tx);
|
return SkGradientShader::MakeRadial(center, rad, colors, nullptr, SK_ARRAY_COUNT(colors), tx);
|
||||||
case 2:
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -199,10 +199,11 @@ private:
|
|||||||
// V54: ComposeShader can use a Mode or a Lerp
|
// V54: ComposeShader can use a Mode or a Lerp
|
||||||
// V55: Drop blendmode[] from MergeImageFilter
|
// V55: Drop blendmode[] from MergeImageFilter
|
||||||
// V56: Add TileMode in SkBlurImageFilter.
|
// V56: Add TileMode in SkBlurImageFilter.
|
||||||
|
// V57: Sweep tiling info.
|
||||||
|
|
||||||
// Only SKPs within the min/current picture version range (inclusive) can be read.
|
// 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 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 bool IsValidPictInfo(const SkPictInfo& info);
|
||||||
static sk_sp<SkPicture> Forwardport(const SkPictInfo&,
|
static sk_sp<SkPicture> Forwardport(const SkPictInfo&,
|
||||||
|
@ -158,44 +158,69 @@ public:
|
|||||||
|
|
||||||
/** Returns a shader that generates a sweep gradient given a center.
|
/** Returns a shader that generates a sweep gradient given a center.
|
||||||
<p />
|
<p />
|
||||||
@param cx The X coordinate of the center of the sweep
|
@param cx The X coordinate of the center of the sweep
|
||||||
@param cx The Y 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 colors The array[count] of colors, to be distributed around the center, within
|
||||||
@param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
|
the gradient angle range.
|
||||||
each corresponding color in the colors array. If this is NULL,
|
@param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative
|
||||||
the the colors are distributed evenly between the center and edge of the circle.
|
position of each corresponding color in the colors array. If this is
|
||||||
If this is not null, the values must begin with 0, end with 1.0, and
|
NULL, then the colors are distributed evenly within the angular range.
|
||||||
intermediate values must be strictly increasing.
|
If this is not null, the values must begin with 0, end with 1.0, and
|
||||||
@param count Must be >= 2. The number of colors (and pos if not NULL) entries
|
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,
|
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
|
||||||
const SkColor colors[], const SkScalar pos[], int count,
|
const SkColor colors[], const SkScalar pos[], int count,
|
||||||
|
SkShader::TileMode mode,
|
||||||
|
SkScalar startAngle, SkScalar endAngle,
|
||||||
uint32_t flags, const SkMatrix* localMatrix);
|
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,
|
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
|
||||||
const SkColor colors[], const SkScalar pos[], int count) {
|
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.
|
/** Returns a shader that generates a sweep gradient given a center.
|
||||||
<p />
|
<p />
|
||||||
@param cx The X coordinate of the center of the sweep
|
@param cx The X coordinate of the center of the sweep
|
||||||
@param cx The Y 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 colors The array[count] of colors, to be distributed around the center, within
|
||||||
@param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
|
the gradient angle range.
|
||||||
each corresponding color in the colors array. If this is NULL,
|
@param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative
|
||||||
the the colors are distributed evenly between the center and edge of the circle.
|
position of each corresponding color in the colors array. If this is
|
||||||
If this is not null, the values must begin with 0, end with 1.0, and
|
NULL, then the colors are distributed evenly within the angular range.
|
||||||
intermediate values must be strictly increasing.
|
If this is not null, the values must begin with 0, end with 1.0, and
|
||||||
@param count Must be >= 2. The number of colors (and pos if not NULL) entries
|
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,
|
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
|
||||||
const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
|
const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
|
||||||
const SkScalar pos[], int count,
|
const SkScalar pos[], int count,
|
||||||
|
SkShader::TileMode mode,
|
||||||
|
SkScalar startAngle, SkScalar endAngle,
|
||||||
uint32_t flags, const SkMatrix* localMatrix);
|
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,
|
static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
|
||||||
const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
|
const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
|
||||||
const SkScalar pos[], int count) {
|
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()
|
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
|
||||||
|
@ -74,6 +74,7 @@ public:
|
|||||||
kComposeShaderCanLerp_Version = 54,
|
kComposeShaderCanLerp_Version = 54,
|
||||||
kNoModesInMergeImageFilter_Verison = 55,
|
kNoModesInMergeImageFilter_Verison = 55,
|
||||||
kTileModeInBlurImageFilter_Version = 56,
|
kTileModeInBlurImageFilter_Version = 56,
|
||||||
|
kTileInfoInSweepGradient_Version = 57,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1228,11 +1228,14 @@ sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
|
|||||||
const SkColor colors[],
|
const SkColor colors[],
|
||||||
const SkScalar pos[],
|
const SkScalar pos[],
|
||||||
int colorCount,
|
int colorCount,
|
||||||
|
SkShader::TileMode mode,
|
||||||
|
SkScalar startAngle,
|
||||||
|
SkScalar endAngle,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
const SkMatrix* localMatrix) {
|
const SkMatrix* localMatrix) {
|
||||||
ColorConverter converter(colors, colorCount);
|
ColorConverter converter(colors, colorCount);
|
||||||
return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, flags,
|
return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount,
|
||||||
localMatrix);
|
mode, startAngle, endAngle, flags, localMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
|
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,
|
sk_sp<SkColorSpace> colorSpace,
|
||||||
const SkScalar pos[],
|
const SkScalar pos[],
|
||||||
int colorCount,
|
int colorCount,
|
||||||
|
SkShader::TileMode mode,
|
||||||
|
SkScalar startAngle,
|
||||||
|
SkScalar endAngle,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
const SkMatrix* localMatrix) {
|
const SkMatrix* localMatrix) {
|
||||||
if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
|
if (!valid_grad(colors, pos, colorCount, mode)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (1 == colorCount) {
|
if (1 == colorCount) {
|
||||||
return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
|
return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
|
||||||
}
|
}
|
||||||
|
if (startAngle >= endAngle) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
if (localMatrix && !localMatrix->invert(nullptr)) {
|
if (localMatrix && !localMatrix->invert(nullptr)) {
|
||||||
return 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);
|
ColorStopOptimizer opt(colors, pos, colorCount, mode);
|
||||||
|
|
||||||
SkGradientShaderBase::Descriptor desc;
|
SkGradientShaderBase::Descriptor desc;
|
||||||
desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
|
desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
|
||||||
localMatrix);
|
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)
|
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
|
||||||
|
@ -11,18 +11,14 @@
|
|||||||
#include "SkPM4fPriv.h"
|
#include "SkPM4fPriv.h"
|
||||||
#include "SkRasterPipeline.h"
|
#include "SkRasterPipeline.h"
|
||||||
|
|
||||||
static SkMatrix translate(SkScalar dx, SkScalar dy) {
|
SkSweepGradient::SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1,
|
||||||
SkMatrix matrix;
|
const Descriptor& desc)
|
||||||
matrix.setTranslate(dx, dy);
|
: SkGradientShaderBase(desc, SkMatrix::MakeTrans(-center.x(), -center.y()))
|
||||||
return matrix;
|
, fCenter(center)
|
||||||
}
|
, fTBias(-t0)
|
||||||
|
, fTScale(1 / (t1 - t0))
|
||||||
SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc)
|
|
||||||
: SkGradientShaderBase(desc, translate(-cx, -cy))
|
|
||||||
, fCenter(SkPoint::Make(cx, cy))
|
|
||||||
{
|
{
|
||||||
// overwrite the tilemode to a canonical value (since sweep ignores it)
|
SkASSERT(t0 < t1);
|
||||||
fTileMode = SkShader::kClamp_TileMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
|
SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
|
||||||
@ -39,14 +35,27 @@ sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const SkPoint center = buffer.readPoint();
|
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,
|
return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
|
||||||
std::move(desc.fColorSpace), desc.fPos, desc.fCount,
|
std::move(desc.fColorSpace), desc.fPos, desc.fCount,
|
||||||
|
desc.fTileMode, startAngle, endAngle,
|
||||||
desc.fGradFlags, desc.fLocalMatrix);
|
desc.fGradFlags, desc.fLocalMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
|
void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
|
||||||
this->INHERITED::flatten(buffer);
|
this->INHERITED::flatten(buffer);
|
||||||
buffer.writePoint(fCenter);
|
buffer.writePoint(fCenter);
|
||||||
|
buffer.writeScalar(fTBias);
|
||||||
|
buffer.writeScalar(fTScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
@ -62,8 +71,9 @@ class GrSweepGradient : public GrGradientEffect {
|
|||||||
public:
|
public:
|
||||||
class GLSLSweepProcessor;
|
class GLSLSweepProcessor;
|
||||||
|
|
||||||
static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
|
static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar tBias,
|
||||||
auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args));
|
SkScalar tScale) {
|
||||||
|
auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args, tBias, tScale));
|
||||||
return processor->isValid() ? std::move(processor) : nullptr;
|
return processor->isValid() ? std::move(processor) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,12 +84,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit GrSweepGradient(const CreateArgs& args)
|
explicit GrSweepGradient(const CreateArgs& args, SkScalar tBias, SkScalar tScale)
|
||||||
: INHERITED(args, args.fShader->colorsAreOpaque()) {
|
: INHERITED(args, args.fShader->colorsAreOpaque())
|
||||||
|
, fTBias(tBias)
|
||||||
|
, fTScale(tScale){
|
||||||
this->initClassID<GrSweepGradient>();
|
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>();
|
this->initClassID<GrSweepGradient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +103,18 @@ private:
|
|||||||
virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
|
virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
|
||||||
GrProcessorKeyBuilder* b) const override;
|
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
|
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
|
||||||
|
|
||||||
|
SkScalar fTBias;
|
||||||
|
SkScalar fTScale;
|
||||||
|
|
||||||
typedef GrGradientEffect INHERITED;
|
typedef GrGradientEffect INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,17 +122,38 @@ private:
|
|||||||
|
|
||||||
class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor {
|
class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor {
|
||||||
public:
|
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));
|
b->add32(GenBaseGradientKey(processor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
typedef GrGradientEffect::GLSLProcessor INHERITED;
|
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:
|
||||||
|
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) {
|
void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) {
|
||||||
const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>();
|
const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>();
|
||||||
this->emitUniforms(args.fUniformHandler, ge);
|
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
|
||||||
SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
|
this->emitUniforms(uniformHandler, ge);
|
||||||
SkString t;
|
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]
|
// 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
|
||||||
if (args.fShaderCaps->atan2ImplementedAsAtanYOverX()) {
|
const SkString t = SkStringPrintf("((%s * 0.1591549430918 + 0.5 + %s[0]) * %s[1])",
|
||||||
// On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is
|
atan.c_str(), tBiasScaleV, tBiasScaleV);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
this->emitColor(args.fFragBuilder,
|
this->emitColor(args.fFragBuilder,
|
||||||
args.fUniformHandler,
|
args.fUniformHandler,
|
||||||
args.fShaderCaps,
|
args.fShaderCaps,
|
||||||
@ -192,8 +244,9 @@ sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs&
|
|||||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
|
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
|
||||||
args.fDstColorSpace);
|
args.fDstColorSpace);
|
||||||
sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make(
|
sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make(
|
||||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, SkShader::kClamp_TileMode,
|
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
|
||||||
std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
|
std::move(colorSpaceXform), SkToBool(args.fDstColorSpace)),
|
||||||
|
fTBias, fTScale));
|
||||||
if (!inner) {
|
if (!inner) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -224,9 +277,11 @@ void SkSweepGradient::toString(SkString* str) const {
|
|||||||
str->append(")");
|
str->append(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkSweepGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p,
|
void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p,
|
||||||
SkRasterPipeline*) const {
|
SkRasterPipeline*) const {
|
||||||
p->append(SkRasterPipeline::xy_to_unit_angle);
|
p->append(SkRasterPipeline::xy_to_unit_angle);
|
||||||
|
p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeScale(fTScale, 1),
|
||||||
|
SkMatrix::MakeTrans(fTBias , 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
class SkSweepGradient final : public SkGradientShaderBase {
|
class SkSweepGradient final : public SkGradientShaderBase {
|
||||||
public:
|
public:
|
||||||
SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&);
|
SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1, const Descriptor&);
|
||||||
|
|
||||||
GradientType asAGradient(GradientInfo* info) const override;
|
GradientType asAGradient(GradientInfo* info) const override;
|
||||||
|
|
||||||
@ -33,7 +33,9 @@ protected:
|
|||||||
bool onIsRasterPipelineOnly() const override { return true; }
|
bool onIsRasterPipelineOnly() const override { return true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SkPoint fCenter;
|
const SkPoint fCenter;
|
||||||
|
const SkScalar fTBias,
|
||||||
|
fTScale;
|
||||||
|
|
||||||
friend class SkGradientShader;
|
friend class SkGradientShader;
|
||||||
typedef SkGradientShaderBase INHERITED;
|
typedef SkGradientShaderBase INHERITED;
|
||||||
|
Loading…
Reference in New Issue
Block a user