aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/shaders/gradients
diff options
context:
space:
mode:
authorGravatar Stan Iliev <stani@google.com>2017-05-25 22:07:16 +0000
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-25 22:30:19 +0000
commitd8872be505c5c9c48072fe62c244e53e9b7334f1 (patch)
treeef6ae54d394f1bf0794393c42129811b93d0f6be /src/shaders/gradients
parent5b474d36238e38642add8d4b54cb9ac80935262b (diff)
Revert "Relocate shaders to own dir"
This reverts commit fabe0b26d05624ce7374f6ca89bd66df6142534e. Reason for revert: Last android roll failed with "external/skia/src/effects/SkGaussianEdgeShader.h:11:10: fatal error: 'SkShaderBase.h' file not found" Original change's description: > Relocate shaders to own dir > > Consolidate all shader impls under src/shaders/. > > Change-Id: I450e37541214704c1ad9e379d9d753b7cc62fac3 > Reviewed-on: https://skia-review.googlesource.com/17927 > Commit-Queue: Florin Malita <fmalita@chromium.org> > Reviewed-by: Herb Derby <herb@google.com> > TBR=mtklein@google.com,herb@google.com,fmalita@chromium.org,reed@google.com No-Presubmit: true No-Tree-Checks: true No-Try: true Change-Id: Idbb2b75053969df1dad9d8ce0217cd39189b9ddb Reviewed-on: https://skia-review.googlesource.com/18020 Reviewed-by: Stan Iliev <stani@google.com> Commit-Queue: Stan Iliev <stani@google.com>
Diffstat (limited to 'src/shaders/gradients')
-rw-r--r--src/shaders/gradients/Sk4fGradientBase.cpp451
-rw-r--r--src/shaders/gradients/Sk4fGradientBase.h97
-rw-r--r--src/shaders/gradients/Sk4fGradientPriv.h194
-rw-r--r--src/shaders/gradients/Sk4fLinearGradient.cpp528
-rw-r--r--src/shaders/gradients/Sk4fLinearGradient.h51
-rw-r--r--src/shaders/gradients/SkClampRange.cpp178
-rw-r--r--src/shaders/gradients/SkClampRange.h62
-rw-r--r--src/shaders/gradients/SkGradientBitmapCache.cpp154
-rw-r--r--src/shaders/gradients/SkGradientBitmapCache.h48
-rw-r--r--src/shaders/gradients/SkGradientShader.cpp2004
-rw-r--r--src/shaders/gradients/SkGradientShaderPriv.h540
-rw-r--r--src/shaders/gradients/SkLinearGradient.cpp804
-rw-r--r--src/shaders/gradients/SkLinearGradient.h87
-rw-r--r--src/shaders/gradients/SkRadialGradient.cpp405
-rw-r--r--src/shaders/gradients/SkRadialGradient.h53
-rw-r--r--src/shaders/gradients/SkSweepGradient.cpp225
-rw-r--r--src/shaders/gradients/SkSweepGradient.h43
-rw-r--r--src/shaders/gradients/SkTwoPointConicalGradient.cpp421
-rw-r--r--src/shaders/gradients/SkTwoPointConicalGradient.h93
-rw-r--r--src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp1341
-rw-r--r--src/shaders/gradients/SkTwoPointConicalGradient_gpu.h24
21 files changed, 0 insertions, 7803 deletions
diff --git a/src/shaders/gradients/Sk4fGradientBase.cpp b/src/shaders/gradients/Sk4fGradientBase.cpp
deleted file mode 100644
index e20f5f4702..0000000000
--- a/src/shaders/gradients/Sk4fGradientBase.cpp
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Sk4fGradientBase.h"
-
-#include <functional>
-
-namespace {
-
-Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) {
- const SkColor4f c4f = SkColor4f::FromColor(c);
- const Sk4f pm4f = premul
- ? c4f.premul().to4f()
- : Sk4f{c4f.fR, c4f.fG, c4f.fB, c4f.fA};
-
- return pm4f * component_scale;
-}
-
-class IntervalIterator {
-public:
- IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse)
- : fColors(colors)
- , fPos(pos)
- , fCount(count)
- , fFirstPos(reverse ? SK_Scalar1 : 0)
- , fBegin(reverse ? count - 1 : 0)
- , fAdvance(reverse ? -1 : 1) {
- SkASSERT(colors);
- SkASSERT(count > 0);
- }
-
- void iterate(std::function<void(SkColor, SkColor, SkScalar, SkScalar)> func) const {
- if (!fPos) {
- this->iterateImplicitPos(func);
- return;
- }
-
- const int end = fBegin + fAdvance * (fCount - 1);
- const SkScalar lastPos = 1 - fFirstPos;
- int prev = fBegin;
- SkScalar prevPos = fFirstPos;
-
- do {
- const int curr = prev + fAdvance;
- SkASSERT(curr >= 0 && curr < fCount);
-
- // TODO: this sanitization should be done in SkGradientShaderBase
- const SkScalar currPos = (fAdvance > 0)
- ? SkTPin(fPos[curr], prevPos, lastPos)
- : SkTPin(fPos[curr], lastPos, prevPos);
-
- if (currPos != prevPos) {
- SkASSERT((currPos - prevPos > 0) == (fAdvance > 0));
- func(fColors[prev], fColors[curr], prevPos, currPos);
- }
-
- prev = curr;
- prevPos = currPos;
- } while (prev != end);
- }
-
-private:
- void iterateImplicitPos(std::function<void(SkColor, SkColor, SkScalar, SkScalar)> func) const {
- // When clients don't provide explicit color stop positions (fPos == nullptr),
- // the color stops are distributed evenly across the unit interval
- // (implicit positioning).
- const SkScalar dt = fAdvance * SK_Scalar1 / (fCount - 1);
- const int end = fBegin + fAdvance * (fCount - 2);
- int prev = fBegin;
- SkScalar prevPos = fFirstPos;
-
- while (prev != end) {
- const int curr = prev + fAdvance;
- SkASSERT(curr >= 0 && curr < fCount);
-
- const SkScalar currPos = prevPos + dt;
- func(fColors[prev], fColors[curr], prevPos, currPos);
- prev = curr;
- prevPos = currPos;
- }
-
- // emit the last interval with a pinned end position, to avoid precision issues
- func(fColors[prev], fColors[prev + fAdvance], prevPos, 1 - fFirstPos);
- }
-
- const SkColor* fColors;
- const SkScalar* fPos;
- const int fCount;
- const SkScalar fFirstPos;
- const int fBegin;
- const int fAdvance;
-};
-
-void addMirrorIntervals(const SkColor colors[],
- const SkScalar pos[], int count,
- const Sk4f& componentScale,
- bool premulColors, bool reverse,
- Sk4fGradientIntervalBuffer::BufferType* buffer) {
- const IntervalIterator iter(colors, pos, count, reverse);
- iter.iterate([&] (SkColor c0, SkColor c1, SkScalar t0, SkScalar t1) {
- SkASSERT(buffer->empty() || buffer->back().fT1 == 2 - t0);
-
- const auto mirror_t0 = 2 - t0;
- const auto mirror_t1 = 2 - t1;
- // mirror_p1 & mirror_p1 may collapse for very small values - recheck to avoid
- // triggering Interval asserts.
- if (mirror_t0 != mirror_t1) {
- buffer->emplace_back(pack_color(c0, premulColors, componentScale), mirror_t0,
- pack_color(c1, premulColors, componentScale), mirror_t1);
- }
- });
-}
-
-} // anonymous namespace
-
-Sk4fGradientInterval::Sk4fGradientInterval(const Sk4f& c0, SkScalar t0,
- const Sk4f& c1, SkScalar t1)
- : fT0(t0)
- , fT1(t1) {
- SkASSERT(t0 != t1);
- // Either p0 or p1 can be (-)inf for synthetic clamp edge intervals.
- SkASSERT(SkScalarIsFinite(t0) || SkScalarIsFinite(t1));
-
- const auto dt = t1 - t0;
-
- // Clamp edge intervals are always zero-ramp.
- SkASSERT(SkScalarIsFinite(dt) || (c0 == c1).allTrue());
- SkASSERT(SkScalarIsFinite(t0) || (c0 == c1).allTrue());
- const Sk4f dc = SkScalarIsFinite(dt) ? (c1 - c0) / dt : 0;
- const Sk4f bias = c0 - (SkScalarIsFinite(t0) ? t0 * dc : 0);
-
- bias.store(&fCb.fVec);
- dc.store(&fCg.fVec);
-}
-
-void Sk4fGradientIntervalBuffer::init(const SkColor colors[], const SkScalar pos[], int count,
- SkShader::TileMode tileMode, bool premulColors,
- SkScalar alpha, bool reverse) {
- // The main job here is to build a specialized interval list: a different
- // representation of the color stops data, optimized for efficient scan line
- // access during shading.
- //
- // [{P0,C0} , {P1,C1}) [{P1,C2} , {P2,c3}) ... [{Pn,C2n} , {Pn+1,C2n+1})
- //
- // The list may be inverted when requested (such that e.g. points are sorted
- // in increasing x order when dx < 0).
- //
- // Note: the current representation duplicates pos data; we could refactor to
- // avoid this if interval storage size becomes a concern.
- //
- // Aside from reordering, we also perform two more pre-processing steps at
- // this stage:
- //
- // 1) scale the color components depending on paint alpha and the requested
- // interpolation space (note: the interval color storage is SkPM4f, but
- // that doesn't necessarily mean the colors are premultiplied; that
- // property is tracked in fColorsArePremul)
- //
- // 2) inject synthetic intervals to support tiling.
- //
- // * for kRepeat, no extra intervals are needed - the iterator just
- // wraps around at the end:
- //
- // ->[P0,P1)->..[Pn-1,Pn)->
- //
- // * for kClamp, we add two "infinite" intervals before/after:
- //
- // [-/+inf , P0)->[P0 , P1)->..[Pn-1 , Pn)->[Pn , +/-inf)
- //
- // (the iterator should never run off the end in this mode)
- //
- // * for kMirror, we extend the range to [0..2] and add a flipped
- // interval series - then the iterator operates just as in the
- // kRepeat case:
- //
- // ->[P0,P1)->..[Pn-1,Pn)->[2 - Pn,2 - Pn-1)->..[2 - P1,2 - P0)->
- //
- // TODO: investigate collapsing intervals << 1px.
-
- SkASSERT(count > 0);
- SkASSERT(colors);
-
- fIntervals.reset();
-
- const Sk4f componentScale = premulColors
- ? Sk4f(alpha)
- : Sk4f(1.0f, 1.0f, 1.0f, alpha);
- const int first_index = reverse ? count - 1 : 0;
- const int last_index = count - 1 - first_index;
- const SkScalar first_pos = reverse ? SK_Scalar1 : 0;
- const SkScalar last_pos = SK_Scalar1 - first_pos;
-
- if (tileMode == SkShader::kClamp_TileMode) {
- // synthetic edge interval: -/+inf .. P0
- const Sk4f clamp_color = pack_color(colors[first_index],
- premulColors, componentScale);
- const SkScalar clamp_pos = reverse ? SK_ScalarInfinity : SK_ScalarNegativeInfinity;
- fIntervals.emplace_back(clamp_color, clamp_pos,
- clamp_color, first_pos);
- } else if (tileMode == SkShader::kMirror_TileMode && reverse) {
- // synthetic mirror intervals injected before main intervals: (2 .. 1]
- addMirrorIntervals(colors, pos, count, componentScale, premulColors, false, &fIntervals);
- }
-
- const IntervalIterator iter(colors, pos, count, reverse);
- iter.iterate([&] (SkColor c0, SkColor c1, SkScalar t0, SkScalar t1) {
- SkASSERT(fIntervals.empty() || fIntervals.back().fT1 == t0);
-
- fIntervals.emplace_back(pack_color(c0, premulColors, componentScale), t0,
- pack_color(c1, premulColors, componentScale), t1);
- });
-
- if (tileMode == SkShader::kClamp_TileMode) {
- // synthetic edge interval: Pn .. +/-inf
- const Sk4f clamp_color = pack_color(colors[last_index], premulColors, componentScale);
- const SkScalar clamp_pos = reverse ? SK_ScalarNegativeInfinity : SK_ScalarInfinity;
- fIntervals.emplace_back(clamp_color, last_pos,
- clamp_color, clamp_pos);
- } else if (tileMode == SkShader::kMirror_TileMode && !reverse) {
- // synthetic mirror intervals injected after main intervals: [1 .. 2)
- addMirrorIntervals(colors, pos, count, componentScale, premulColors, true, &fIntervals);
- }
-}
-
-const Sk4fGradientInterval* Sk4fGradientIntervalBuffer::find(SkScalar t) const {
- // Binary search.
- const auto* i0 = fIntervals.begin();
- const auto* i1 = fIntervals.end() - 1;
-
- while (i0 != i1) {
- SkASSERT(i0 < i1);
- SkASSERT(t >= i0->fT0 && t <= i1->fT1);
-
- const auto* i = i0 + ((i1 - i0) >> 1);
-
- if (t > i->fT1) {
- i0 = i + 1;
- } else {
- i1 = i;
- }
- }
-
- SkASSERT(i0->contains(t));
- return i0;
-}
-
-const Sk4fGradientInterval* Sk4fGradientIntervalBuffer::findNext(
- SkScalar t, const Sk4fGradientInterval* prev, bool increasing) const {
-
- SkASSERT(!prev->contains(t));
- SkASSERT(prev >= fIntervals.begin() && prev < fIntervals.end());
- SkASSERT(t >= fIntervals.front().fT0 && t <= fIntervals.back().fT1);
-
- const auto* i = prev;
-
- // Use the |increasing| signal to figure which direction we should search for
- // the next interval, then perform a linear search.
- if (increasing) {
- do {
- i += 1;
- if (i >= fIntervals.end()) {
- i = fIntervals.begin();
- }
- } while (!i->contains(t));
- } else {
- do {
- i -= 1;
- if (i < fIntervals.begin()) {
- i = fIntervals.end() - 1;
- }
- } while (!i->contains(t));
- }
-
- return i;
-}
-
-SkGradientShaderBase::
-GradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderBase& shader,
- const ContextRec& rec)
- : INHERITED(shader, rec)
- , fFlags(this->INHERITED::getFlags())
-#ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING
- , fDither(true)
-#else
- , fDither(rec.fPaint->isDither())
-#endif
-{
- const SkMatrix& inverse = this->getTotalInverse();
- fDstToPos.setConcat(shader.fPtsToUnit, inverse);
- fDstToPosProc = fDstToPos.getMapXYProc();
- fDstToPosClass = static_cast<uint8_t>(INHERITED::ComputeMatrixClass(fDstToPos));
-
- if (shader.fColorsAreOpaque && this->getPaintAlpha() == SK_AlphaOPAQUE) {
- fFlags |= kOpaqueAlpha_Flag;
- }
-
- fColorsArePremul =
- (shader.fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag)
- || shader.fColorsAreOpaque;
-}
-
-bool SkGradientShaderBase::
-GradientShaderBase4fContext::isValid() const {
- return fDstToPos.isFinite();
-}
-
-void SkGradientShaderBase::
-GradientShaderBase4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
- if (fColorsArePremul) {
- this->shadePremulSpan<DstType::L32, ApplyPremul::False>(x, y, dst, count);
- } else {
- this->shadePremulSpan<DstType::L32, ApplyPremul::True>(x, y, dst, count);
- }
-}
-
-void SkGradientShaderBase::
-GradientShaderBase4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
- if (fColorsArePremul) {
- this->shadePremulSpan<DstType::F32, ApplyPremul::False>(x, y, dst, count);
- } else {
- this->shadePremulSpan<DstType::F32, ApplyPremul::True>(x, y, dst, count);
- }
-}
-
-template<DstType dstType, ApplyPremul premul>
-void SkGradientShaderBase::
-GradientShaderBase4fContext::shadePremulSpan(int x, int y,
- typename DstTraits<dstType, premul>::Type dst[],
- int count) const {
- const SkGradientShaderBase& shader =
- static_cast<const SkGradientShaderBase&>(fShader);
-
- switch (shader.fTileMode) {
- case kClamp_TileMode:
- this->shadeSpanInternal<dstType,
- premul,
- kClamp_TileMode>(x, y, dst, count);
- break;
- case kRepeat_TileMode:
- this->shadeSpanInternal<dstType,
- premul,
- kRepeat_TileMode>(x, y, dst, count);
- break;
- case kMirror_TileMode:
- this->shadeSpanInternal<dstType,
- premul,
- kMirror_TileMode>(x, y, dst, count);
- break;
- }
-}
-
-template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
-void SkGradientShaderBase::
-GradientShaderBase4fContext::shadeSpanInternal(int x, int y,
- typename DstTraits<dstType, premul>::Type dst[],
- int count) const {
- static const int kBufSize = 128;
- SkScalar ts[kBufSize];
- TSampler<dstType, premul, tileMode> sampler(*this);
-
- SkASSERT(count > 0);
- do {
- const int n = SkTMin(kBufSize, count);
- this->mapTs(x, y, ts, n);
- for (int i = 0; i < n; ++i) {
- const Sk4f c = sampler.sample(ts[i]);
- DstTraits<dstType, premul>::store(c, dst++);
- }
- x += n;
- count -= n;
- } while (count > 0);
-}
-
-template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
-class SkGradientShaderBase::GradientShaderBase4fContext::TSampler {
-public:
- TSampler(const GradientShaderBase4fContext& ctx)
- : fCtx(ctx)
- , fInterval(nullptr) {
- switch (tileMode) {
- case kClamp_TileMode:
- fLargestIntervalValue = SK_ScalarInfinity;
- break;
- case kRepeat_TileMode:
- fLargestIntervalValue = nextafterf(1, 0);
- break;
- case kMirror_TileMode:
- fLargestIntervalValue = nextafterf(2.0f, 0);
- break;
- }
- }
-
- Sk4f sample(SkScalar t) {
- const auto tiled_t = tileProc(t);
-
- if (!fInterval) {
- // Very first sample => locate the initial interval.
- // TODO: maybe do this in ctor to remove a branch?
- fInterval = fCtx.fIntervals.find(tiled_t);
- this->loadIntervalData(fInterval);
- } else if (!fInterval->contains(tiled_t)) {
- fInterval = fCtx.fIntervals.findNext(tiled_t, fInterval, t >= fPrevT);
- this->loadIntervalData(fInterval);
- }
-
- fPrevT = t;
- return lerp(tiled_t);
- }
-
-private:
- SkScalar tileProc(SkScalar t) const {
- switch (tileMode) {
- case kClamp_TileMode:
- // synthetic clamp-mode edge intervals allow for a free-floating t:
- // [-inf..0)[0..1)[1..+inf)
- return t;
- case kRepeat_TileMode:
- // t % 1 (intervals range: [0..1))
- // Due to the extra arithmetic, we must clamp to ensure the value remains less than 1.
- return SkTMin(t - SkScalarFloorToScalar(t), fLargestIntervalValue);
- case kMirror_TileMode:
- // t % 2 (synthetic mirror intervals expand the range to [0..2)
- // Due to the extra arithmetic, we must clamp to ensure the value remains less than 2.
- return SkTMin(t - SkScalarFloorToScalar(t / 2) * 2, fLargestIntervalValue);
- }
-
- SK_ABORT("Unhandled tile mode.");
- return 0;
- }
-
- Sk4f lerp(SkScalar t) {
- SkASSERT(fInterval->contains(t));
- return fCb + fCg * t;
- }
-
- void loadIntervalData(const Sk4fGradientInterval* i) {
- fCb = DstTraits<dstType, premul>::load(i->fCb);
- fCg = DstTraits<dstType, premul>::load(i->fCg);
- }
-
- const GradientShaderBase4fContext& fCtx;
- const Sk4fGradientInterval* fInterval;
- SkScalar fPrevT;
- SkScalar fLargestIntervalValue;
- Sk4f fCb;
- Sk4f fCg;
-};
diff --git a/src/shaders/gradients/Sk4fGradientBase.h b/src/shaders/gradients/Sk4fGradientBase.h
deleted file mode 100644
index a660d6bde5..0000000000
--- a/src/shaders/gradients/Sk4fGradientBase.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef Sk4fGradientBase_DEFINED
-#define Sk4fGradientBase_DEFINED
-
-#include "Sk4fGradientPriv.h"
-#include "SkColor.h"
-#include "SkGradientShaderPriv.h"
-#include "SkMatrix.h"
-#include "SkNx.h"
-#include "SkPM4f.h"
-#include "SkShaderBase.h"
-#include "SkTArray.h"
-
-struct Sk4fGradientInterval {
- Sk4fGradientInterval(const Sk4f& c0, SkScalar t0,
- const Sk4f& c1, SkScalar t1);
-
- bool contains(SkScalar t) const {
- // True if t is in [p0,p1]. Note: this helper assumes a
- // natural/increasing interval - so it's not usable in Sk4fLinearGradient.
- SkASSERT(fT0 < fT1);
- return t >= fT0 && t <= fT1;
- }
-
- // Color bias and color gradient, such that for a t in this interval
- //
- // C = fCb + t * fCg;
- SkPM4f fCb, fCg;
- SkScalar fT0, fT1;
-};
-
-class Sk4fGradientIntervalBuffer {
-public:
- void init(const SkColor colors[], const SkScalar pos[], int count,
- SkShader::TileMode tileMode, bool premulColors, SkScalar alpha, bool reverse);
-
- const Sk4fGradientInterval* find(SkScalar t) const;
- const Sk4fGradientInterval* findNext(SkScalar t, const Sk4fGradientInterval* prev,
- bool increasing) const;
-
- using BufferType = SkSTArray<8, Sk4fGradientInterval, true>;
-
- const BufferType* operator->() const { return &fIntervals; }
-
-private:
- BufferType fIntervals;
-};
-
-class SkGradientShaderBase::
-GradientShaderBase4fContext : public Context {
-public:
- GradientShaderBase4fContext(const SkGradientShaderBase&,
- const ContextRec&);
-
- uint32_t getFlags() const override { return fFlags; }
-
- void shadeSpan(int x, int y, SkPMColor dst[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f dst[], int count) override;
-
- bool isValid() const;
-
-protected:
- virtual void mapTs(int x, int y, SkScalar ts[], int count) const = 0;
-
- Sk4fGradientIntervalBuffer fIntervals;
- SkMatrix fDstToPos;
- SkMatrix::MapXYProc fDstToPosProc;
- uint8_t fDstToPosClass;
- uint8_t fFlags;
- bool fDither;
- bool fColorsArePremul;
-
-private:
- using INHERITED = Context;
-
- void addMirrorIntervals(const SkGradientShaderBase&,
- const Sk4f& componentScale, bool reverse);
-
- template<DstType, ApplyPremul, SkShader::TileMode tileMode>
- class TSampler;
-
- template <DstType dstType, ApplyPremul premul>
- void shadePremulSpan(int x, int y, typename DstTraits<dstType, premul>::Type[],
- int count) const;
-
- template <DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
- void shadeSpanInternal(int x, int y, typename DstTraits<dstType, premul>::Type[],
- int count) const;
-};
-
-#endif // Sk4fGradientBase_DEFINED
diff --git a/src/shaders/gradients/Sk4fGradientPriv.h b/src/shaders/gradients/Sk4fGradientPriv.h
deleted file mode 100644
index b8f4bcaee1..0000000000
--- a/src/shaders/gradients/Sk4fGradientPriv.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef Sk4fGradientPriv_DEFINED
-#define Sk4fGradientPriv_DEFINED
-
-#include "SkColor.h"
-#include "SkHalf.h"
-#include "SkImageInfo.h"
-#include "SkNx.h"
-#include "SkPM4f.h"
-#include "SkPM4fPriv.h"
-#include "SkUtils.h"
-
-// Templates shared by various 4f gradient flavors.
-
-namespace {
-
-enum class ApplyPremul { True, False };
-
-enum class DstType {
- L32, // Linear 32bit. Used for both shader/blitter paths.
- S32, // SRGB 32bit. Used for the blitter path only.
- F16, // Linear half-float. Used for blitters only.
- F32, // Linear float. Used for shaders only.
-};
-
-template <ApplyPremul>
-struct PremulTraits;
-
-template <>
-struct PremulTraits<ApplyPremul::False> {
- static Sk4f apply(const Sk4f& c) { return c; }
-};
-
-template <>
-struct PremulTraits<ApplyPremul::True> {
- static Sk4f apply(const Sk4f& c) {
- const float alpha = c[SkPM4f::A];
- // FIXME: portable swizzle?
- return c * Sk4f(alpha, alpha, alpha, 1);
- }
-};
-
-// Struct encapsulating various dest-dependent ops:
-//
-// - load() Load a SkPM4f value into Sk4f. Normally called once per interval
-// advance. Also applies a scale and swizzle suitable for DstType.
-//
-// - store() Store one Sk4f to dest. Optionally handles premul, color space
-// conversion, etc.
-//
-// - store(count) Store the Sk4f value repeatedly to dest, count times.
-//
-// - store4x() Store 4 Sk4f values to dest (opportunistic optimization).
-//
-template <DstType, ApplyPremul premul>
-struct DstTraits;
-
-template <ApplyPremul premul>
-struct DstTraits<DstType::L32, premul> {
- using PM = PremulTraits<premul>;
- using Type = SkPMColor;
-
- // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed.
- static Sk4f load(const SkPM4f& c) {
- return premul == ApplyPremul::False
- ? c.to4f_pmorder() * Sk4f(255)
- : c.to4f_pmorder();
- }
-
- static void store(const Sk4f& c, Type* dst) {
- if (premul == ApplyPremul::False) {
- // c is prescaled by 255, just store.
- SkNx_cast<uint8_t>(c).store(dst);
- } else {
- *dst = Sk4f_toL32(PM::apply(c));
- }
- }
-
- static void store(const Sk4f& c, Type* dst, int n) {
- Type pmc;
- store(c, &pmc);
- sk_memset32(dst, pmc, n);
- }
-
- static void store4x(const Sk4f& c0, const Sk4f& c1,
- const Sk4f& c2, const Sk4f& c3,
- Type* dst) {
- if (premul == ApplyPremul::False) {
- Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3);
- } else {
- store(c0, dst + 0);
- store(c1, dst + 1);
- store(c2, dst + 2);
- store(c3, dst + 3);
- }
- }
-};
-
-template <ApplyPremul premul>
-struct DstTraits<DstType::S32, premul> {
- using PM = PremulTraits<premul>;
- using Type = SkPMColor;
-
- static Sk4f load(const SkPM4f& c) {
- return c.to4f_pmorder();
- }
-
- static void store(const Sk4f& c, Type* dst) {
- // FIXME: this assumes opaque colors. Handle unpremultiplication.
- *dst = Sk4f_toS32(PM::apply(c));
- }
-
- static void store(const Sk4f& c, Type* dst, int n) {
- sk_memset32(dst, Sk4f_toS32(PM::apply(c)), n);
- }
-
- static void store4x(const Sk4f& c0, const Sk4f& c1,
- const Sk4f& c2, const Sk4f& c3,
- Type* dst) {
- store(c0, dst + 0);
- store(c1, dst + 1);
- store(c2, dst + 2);
- store(c3, dst + 3);
- }
-};
-
-template <ApplyPremul premul>
-struct DstTraits<DstType::F16, premul> {
- using PM = PremulTraits<premul>;
- using Type = uint64_t;
-
- static Sk4f load(const SkPM4f& c) {
- return c.to4f();
- }
-
- static void store(const Sk4f& c, Type* dst) {
- SkFloatToHalf_finite_ftz(PM::apply(c)).store(dst);
- }
-
- static void store(const Sk4f& c, Type* dst, int n) {
- uint64_t color;
- SkFloatToHalf_finite_ftz(PM::apply(c)).store(&color);
- sk_memset64(dst, color, n);
- }
-
- static void store4x(const Sk4f& c0, const Sk4f& c1,
- const Sk4f& c2, const Sk4f& c3,
- Type* dst) {
- store(c0, dst + 0);
- store(c1, dst + 1);
- store(c2, dst + 2);
- store(c3, dst + 3);
- }
-};
-
-template <ApplyPremul premul>
-struct DstTraits<DstType::F32, premul> {
- using PM = PremulTraits<premul>;
- using Type = SkPM4f;
-
- static Sk4f load(const SkPM4f& c) {
- return c.to4f();
- }
-
- static void store(const Sk4f& c, Type* dst) {
- PM::apply(c).store(dst->fVec);
- }
-
- static void store(const Sk4f& c, Type* dst, int n) {
- const Sk4f pmc = PM::apply(c);
- for (int i = 0; i < n; ++i) {
- pmc.store(dst[i].fVec);
- }
- }
-
- static void store4x(const Sk4f& c0, const Sk4f& c1,
- const Sk4f& c2, const Sk4f& c3,
- Type* dst) {
- store(c0, dst + 0);
- store(c1, dst + 1);
- store(c2, dst + 2);
- store(c3, dst + 3);
- }
-};
-
-} // anonymous namespace
-
-#endif // Sk4fGradientPriv_DEFINED
diff --git a/src/shaders/gradients/Sk4fLinearGradient.cpp b/src/shaders/gradients/Sk4fLinearGradient.cpp
deleted file mode 100644
index 49b98fd86e..0000000000
--- a/src/shaders/gradients/Sk4fLinearGradient.cpp
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Sk4fLinearGradient.h"
-#include "Sk4x4f.h"
-
-#include <cmath>
-
-namespace {
-
-template<DstType dstType, ApplyPremul premul>
-void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits<dstType, premul>::Type dst[], int n) {
- SkASSERT(n > 0);
-
- const Sk4f dc2 = dc + dc;
- const Sk4f dc4 = dc2 + dc2;
-
- Sk4f c0 = c ;
- Sk4f c1 = c + dc;
- Sk4f c2 = c0 + dc2;
- Sk4f c3 = c1 + dc2;
-
- while (n >= 4) {
- DstTraits<dstType, premul>::store4x(c0, c1, c2, c3, dst);
- dst += 4;
-
- c0 = c0 + dc4;
- c1 = c1 + dc4;
- c2 = c2 + dc4;
- c3 = c3 + dc4;
- n -= 4;
- }
- if (n & 2) {
- DstTraits<dstType, premul>::store(c0, dst++);
- DstTraits<dstType, premul>::store(c1, dst++);
- c0 = c0 + dc2;
- }
- if (n & 1) {
- DstTraits<dstType, premul>::store(c0, dst);
- }
-}
-
-// Planar version of ramp (S32 no-premul only).
-template<>
-void ramp<DstType::S32, ApplyPremul::False>(const Sk4f& c, const Sk4f& dc, SkPMColor dst[], int n) {
- SkASSERT(n > 0);
-
- const Sk4f dc4 = dc * 4;
- const Sk4x4f dc4x = { Sk4f(dc4[0]), Sk4f(dc4[1]), Sk4f(dc4[2]), Sk4f(dc4[3]) };
- Sk4x4f c4x = Sk4x4f::Transpose(c, c + dc, c + dc * 2, c + dc * 3);
-
- while (n >= 4) {
- ( sk_linear_to_srgb(c4x.r) << 0
- | sk_linear_to_srgb(c4x.g) << 8
- | sk_linear_to_srgb(c4x.b) << 16
- | Sk4f_round(255.0f*c4x.a) << 24).store(dst);
-
- c4x.r += dc4x.r;
- c4x.g += dc4x.g;
- c4x.b += dc4x.b;
- c4x.a += dc4x.a;
-
- dst += 4;
- n -= 4;
- }
-
- if (n & 2) {
- DstTraits<DstType::S32, ApplyPremul::False>
- ::store(Sk4f(c4x.r[0], c4x.g[0], c4x.b[0], c4x.a[0]), dst++);
- DstTraits<DstType::S32, ApplyPremul::False>
- ::store(Sk4f(c4x.r[1], c4x.g[1], c4x.b[1], c4x.a[1]), dst++);
- }
-
- if (n & 1) {
- DstTraits<DstType::S32, ApplyPremul::False>
- ::store(Sk4f(c4x.r[n & 2], c4x.g[n & 2], c4x.b[n & 2], c4x.a[n & 2]), dst);
- }
-}
-
-template<SkShader::TileMode>
-SkScalar pinFx(SkScalar);
-
-template<>
-SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) {
- return fx;
-}
-
-template<>
-SkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
- SkScalar f = SkScalarFraction(fx);
- if (f < 0) {
- f = SkTMin(f + 1, nextafterf(1, 0));
- }
- SkASSERT(f >= 0);
- SkASSERT(f < 1.0f);
- return f;
-}
-
-template<>
-SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
- SkScalar f = SkScalarMod(fx, 2.0f);
- if (f < 0) {
- f = SkTMin(f + 2, nextafterf(2, 0));
- }
- SkASSERT(f >= 0);
- SkASSERT(f < 2.0f);
- return f;
-}
-
-// true when x is in [k1,k2], or [k2, k1] when the interval is reversed.
-// TODO(fmalita): hoist the reversed interval check out of this helper.
-bool in_range(SkScalar x, SkScalar k1, SkScalar k2) {
- SkASSERT(k1 != k2);
- return (k1 < k2)
- ? (x >= k1 && x <= k2)
- : (x >= k2 && x <= k1);
-}
-
-} // anonymous namespace
-
-SkLinearGradient::
-LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
- const ContextRec& rec)
- : INHERITED(shader, rec) {
-
- // Our fast path expects interval points to be monotonically increasing in x.
- const bool reverseIntervals = this->isFast() && std::signbit(fDstToPos.getScaleX());
- fIntervals.init(shader.fOrigColors, shader.fOrigPos, shader.fColorCount, shader.fTileMode,
- fColorsArePremul, rec.fPaint->getAlpha() * (1.0f / 255), reverseIntervals);
-
- SkASSERT(fIntervals->count() > 0);
- fCachedInterval = fIntervals->begin();
-}
-
-const Sk4fGradientInterval*
-SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const {
- SkASSERT(in_range(fx, fIntervals->front().fT0, fIntervals->back().fT1));
-
- if (1) {
- // Linear search, using the last scanline interval as a starting point.
- SkASSERT(fCachedInterval >= fIntervals->begin());
- SkASSERT(fCachedInterval < fIntervals->end());
- const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1;
- while (!in_range(fx, fCachedInterval->fT0, fCachedInterval->fT1)) {
- fCachedInterval += search_dir;
- if (fCachedInterval >= fIntervals->end()) {
- fCachedInterval = fIntervals->begin();
- } else if (fCachedInterval < fIntervals->begin()) {
- fCachedInterval = fIntervals->end() - 1;
- }
- }
- return fCachedInterval;
- } else {
- // Binary search. Seems less effective than linear + caching.
- const auto* i0 = fIntervals->begin();
- const auto* i1 = fIntervals->end() - 1;
-
- while (i0 != i1) {
- SkASSERT(i0 < i1);
- SkASSERT(in_range(fx, i0->fT0, i1->fT1));
-
- const auto* i = i0 + ((i1 - i0) >> 1);
-
- if (in_range(fx, i0->fT0, i->fT1)) {
- i1 = i;
- } else {
- SkASSERT(in_range(fx, i->fT1, i1->fT1));
- i0 = i + 1;
- }
- }
-
- SkASSERT(in_range(fx, i0->fT0, i0->fT1));
- return i0;
- }
-}
-
-void SkLinearGradient::
-LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
- if (!this->isFast()) {
- this->INHERITED::shadeSpan(x, y, dst, count);
- return;
- }
-
- // TODO: plumb dithering
- SkASSERT(count > 0);
- if (fColorsArePremul) {
- this->shadePremulSpan<DstType::L32,
- ApplyPremul::False>(x, y, dst, count);
- } else {
- this->shadePremulSpan<DstType::L32,
- ApplyPremul::True>(x, y, dst, count);
- }
-}
-
-void SkLinearGradient::
-LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
- if (!this->isFast()) {
- this->INHERITED::shadeSpan4f(x, y, dst, count);
- return;
- }
-
- // TONOTDO: plumb dithering
- SkASSERT(count > 0);
- if (fColorsArePremul) {
- this->shadePremulSpan<DstType::F32,
- ApplyPremul::False>(x, y, dst, count);
- } else {
- this->shadePremulSpan<DstType::F32,
- ApplyPremul::True>(x, y, dst, count);
- }
-}
-
-template<DstType dstType, ApplyPremul premul>
-void SkLinearGradient::
-LinearGradient4fContext::shadePremulSpan(int x, int y,
- typename DstTraits<dstType, premul>::Type dst[],
- int count) const {
- const SkLinearGradient& shader =
- static_cast<const SkLinearGradient&>(fShader);
- switch (shader.fTileMode) {
- case kClamp_TileMode:
- this->shadeSpanInternal<dstType,
- premul,
- kClamp_TileMode>(x, y, dst, count);
- break;
- case kRepeat_TileMode:
- this->shadeSpanInternal<dstType,
- premul,
- kRepeat_TileMode>(x, y, dst, count);
- break;
- case kMirror_TileMode:
- this->shadeSpanInternal<dstType,
- premul,
- kMirror_TileMode>(x, y, dst, count);
- break;
- }
-}
-
-template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
-void SkLinearGradient::
-LinearGradient4fContext::shadeSpanInternal(int x, int y,
- typename DstTraits<dstType, premul>::Type dst[],
- int count) const {
- SkPoint pt;
- fDstToPosProc(fDstToPos,
- x + SK_ScalarHalf,
- y + SK_ScalarHalf,
- &pt);
- const SkScalar fx = pinFx<tileMode>(pt.x());
- const SkScalar dx = fDstToPos.getScaleX();
- LinearIntervalProcessor<dstType, premul, tileMode> proc(fIntervals->begin(),
- fIntervals->end() - 1,
- this->findInterval(fx),
- fx,
- dx,
- SkScalarNearlyZero(dx * count));
- while (count > 0) {
- // What we really want here is SkTPin(advance, 1, count)
- // but that's a significant perf hit for >> stops; investigate.
- const int n = SkScalarTruncToInt(
- SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count)));
-
- // The current interval advance can be +inf (e.g. when reaching
- // the clamp mode end intervals) - when that happens, we expect to
- // a) consume all remaining count in one swoop
- // b) return a zero color gradient
- SkASSERT(SkScalarIsFinite(proc.currentAdvance())
- || (n == count && proc.currentRampIsZero()));
-
- if (proc.currentRampIsZero()) {
- DstTraits<dstType, premul>::store(proc.currentColor(),
- dst, n);
- } else {
- ramp<dstType, premul>(proc.currentColor(),
- proc.currentColorGrad(),
- dst, n);
- }
-
- proc.advance(SkIntToScalar(n));
- count -= n;
- dst += n;
- }
-}
-
-template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
-class SkLinearGradient::
-LinearGradient4fContext::LinearIntervalProcessor {
-public:
- LinearIntervalProcessor(const Sk4fGradientInterval* firstInterval,
- const Sk4fGradientInterval* lastInterval,
- const Sk4fGradientInterval* i,
- SkScalar fx,
- SkScalar dx,
- bool is_vertical)
- : fAdvX(is_vertical ? SK_ScalarInfinity : (i->fT1 - fx) / dx)
- , fFirstInterval(firstInterval)
- , fLastInterval(lastInterval)
- , fInterval(i)
- , fDx(dx)
- , fIsVertical(is_vertical)
- {
- SkASSERT(fAdvX >= 0);
- SkASSERT(firstInterval <= lastInterval);
-
- if (tileMode != kClamp_TileMode && !is_vertical) {
- const auto spanX = (lastInterval->fT1 - firstInterval->fT0) / dx;
- SkASSERT(spanX >= 0);
-
- // If we're in a repeating tile mode and the whole gradient is compressed into a
- // fraction of a pixel, we just use the average color in zero-ramp mode.
- // This also avoids cases where we make no progress due to interval advances being
- // close to zero.
- static constexpr SkScalar kMinSpanX = .25f;
- if (spanX < kMinSpanX) {
- this->init_average_props();
- return;
- }
- }
-
- this->compute_interval_props(fx);
- }
-
- SkScalar currentAdvance() const {
- SkASSERT(fAdvX >= 0);
- SkASSERT(fAdvX <= (fInterval->fT1 - fInterval->fT0) / fDx || !std::isfinite(fAdvX));
- return fAdvX;
- }
-
- bool currentRampIsZero() const { return fZeroRamp; }
- const Sk4f& currentColor() const { return fCc; }
- const Sk4f& currentColorGrad() const { return fDcDx; }
-
- void advance(SkScalar advX) {
- SkASSERT(advX > 0);
- SkASSERT(fAdvX >= 0);
-
- if (advX >= fAdvX) {
- advX = this->advance_interval(advX);
- }
- SkASSERT(advX < fAdvX);
-
- fCc = fCc + fDcDx * Sk4f(advX);
- fAdvX -= advX;
- }
-
-private:
- void compute_interval_props(SkScalar t) {
- SkASSERT(in_range(t, fInterval->fT0, fInterval->fT1));
-
- const Sk4f dc = DstTraits<dstType, premul>::load(fInterval->fCg);
- fCc = DstTraits<dstType, premul>::load(fInterval->fCb) + dc * Sk4f(t);
- fDcDx = dc * fDx;
- fZeroRamp = fIsVertical || (dc == 0).allTrue();
- }
-
- void init_average_props() {
- fAdvX = SK_ScalarInfinity;
- fZeroRamp = true;
- fDcDx = 0;
- fCc = Sk4f(0);
-
- // TODO: precompute the average at interval setup time?
- for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) {
- // Each interval contributes its average color to the total/weighted average:
- //
- // C = (c0 + c1) / 2 = (Cb + Cg * t0 + Cb + Cg * t1) / 2 = Cb + Cg *(t0 + t1) / 2
- //
- // Avg += C * (t1 - t0)
- //
- const auto c = DstTraits<dstType, premul>::load(i->fCb)
- + DstTraits<dstType, premul>::load(i->fCg) * (i->fT0 + i->fT1) * 0.5f;
- fCc = fCc + c * (i->fT1 - i->fT0);
- }
- }
-
- const Sk4fGradientInterval* next_interval(const Sk4fGradientInterval* i) const {
- SkASSERT(i >= fFirstInterval);
- SkASSERT(i <= fLastInterval);
- i++;
-
- if (tileMode == kClamp_TileMode) {
- SkASSERT(i <= fLastInterval);
- return i;
- }
-
- return (i <= fLastInterval) ? i : fFirstInterval;
- }
-
- SkScalar advance_interval(SkScalar advX) {
- SkASSERT(advX >= fAdvX);
-
- do {
- advX -= fAdvX;
- fInterval = this->next_interval(fInterval);
- fAdvX = (fInterval->fT1 - fInterval->fT0) / fDx;
- SkASSERT(fAdvX > 0);
- } while (advX >= fAdvX);
-
- compute_interval_props(fInterval->fT0);
-
- SkASSERT(advX >= 0);
- return advX;
- }
-
- // Current interval properties.
- Sk4f fDcDx; // dst color gradient (dc/dx)
- Sk4f fCc; // current color, interpolated in dst
- SkScalar fAdvX; // remaining interval advance in dst
- bool fZeroRamp; // current interval color grad is 0
-
- const Sk4fGradientInterval* fFirstInterval;
- const Sk4fGradientInterval* fLastInterval;
- const Sk4fGradientInterval* fInterval; // current interval
- const SkScalar fDx; // 'dx' for consistency with other impls; actually dt/dx
- const bool fIsVertical;
-};
-
-void SkLinearGradient::
-LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const {
- SkASSERT(count > 0);
- SkASSERT(fDstToPosClass != kLinear_MatrixClass);
-
- SkScalar sx = x + SK_ScalarHalf;
- const SkScalar sy = y + SK_ScalarHalf;
- SkPoint pt;
-
- if (fDstToPosClass != kPerspective_MatrixClass) {
- // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanline
- const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x();
- fDstToPosProc(fDstToPos, sx, sy, &pt);
-
- const Sk4f dtdx4 = Sk4f(4 * dtdx);
- Sk4f t4 = Sk4f(pt.x() + 0 * dtdx,
- pt.x() + 1 * dtdx,
- pt.x() + 2 * dtdx,
- pt.x() + 3 * dtdx);
-
- while (count >= 4) {
- t4.store(ts);
- t4 = t4 + dtdx4;
- ts += 4;
- count -= 4;
- }
-
- if (count & 2) {
- *ts++ = t4[0];
- *ts++ = t4[1];
- t4 = SkNx_shuffle<2, 0, 1, 3>(t4);
- }
-
- if (count & 1) {
- *ts++ = t4[0];
- }
- } else {
- for (int i = 0; i < count; ++i) {
- fDstToPosProc(fDstToPos, sx, sy, &pt);
- // Perspective may yield NaN values.
- // Short of a better idea, drop to 0.
- ts[i] = SkScalarIsNaN(pt.x()) ? 0 : pt.x();
- sx += SK_Scalar1;
- }
- }
-}
-
-bool SkLinearGradient::LinearGradient4fContext::onChooseBlitProcs(const SkImageInfo& info,
- BlitState* state) {
- if (state->fMode != SkBlendMode::kSrc &&
- !(state->fMode == SkBlendMode::kSrcOver && (fFlags & kOpaqueAlpha_Flag))) {
- return false;
- }
-
- switch (info.colorType()) {
- case kN32_SkColorType:
- state->fBlitBW = D32_BlitBW;
- return true;
- case kRGBA_F16_SkColorType:
- state->fBlitBW = D64_BlitBW;
- return true;
- default:
- return false;
- }
-}
-
-void SkLinearGradient::
-LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
- int count) {
- // FIXME: ignoring coverage for now
- const LinearGradient4fContext* ctx =
- static_cast<const LinearGradient4fContext*>(state->fCtx);
-
- if (!dst.info().gammaCloseToSRGB()) {
- if (ctx->fColorsArePremul) {
- ctx->shadePremulSpan<DstType::L32, ApplyPremul::False>(
- x, y, dst.writable_addr32(x, y), count);
- } else {
- ctx->shadePremulSpan<DstType::L32, ApplyPremul::True>(
- x, y, dst.writable_addr32(x, y), count);
- }
- } else {
- if (ctx->fColorsArePremul) {
- ctx->shadePremulSpan<DstType::S32, ApplyPremul::False>(
- x, y, dst.writable_addr32(x, y), count);
- } else {
- ctx->shadePremulSpan<DstType::S32, ApplyPremul::True>(
- x, y, dst.writable_addr32(x, y), count);
- }
- }
-}
-
-void SkLinearGradient::
-LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
- int count) {
- // FIXME: ignoring coverage for now
- const LinearGradient4fContext* ctx =
- static_cast<const LinearGradient4fContext*>(state->fCtx);
-
- if (ctx->fColorsArePremul) {
- ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>(
- x, y, dst.writable_addr64(x, y), count);
- } else {
- ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>(
- x, y, dst.writable_addr64(x, y), count);
- }
-}
diff --git a/src/shaders/gradients/Sk4fLinearGradient.h b/src/shaders/gradients/Sk4fLinearGradient.h
deleted file mode 100644
index eebd30fbf5..0000000000
--- a/src/shaders/gradients/Sk4fLinearGradient.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef Sk4fLinearGradient_DEFINED
-#define Sk4fLinearGradient_DEFINED
-
-#include "Sk4fGradientBase.h"
-#include "SkLinearGradient.h"
-
-class SkLinearGradient::
-LinearGradient4fContext final : public GradientShaderBase4fContext {
-public:
- LinearGradient4fContext(const SkLinearGradient&, const ContextRec&);
-
- void shadeSpan(int x, int y, SkPMColor dst[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f dst[], int count) override;
-
-protected:
- void mapTs(int x, int y, SkScalar ts[], int count) const override;
-
- bool onChooseBlitProcs(const SkImageInfo&, BlitState*) override;
-
-private:
- using INHERITED = GradientShaderBase4fContext;
-
- template<DstType, ApplyPremul, TileMode>
- class LinearIntervalProcessor;
-
- template <DstType dstType, ApplyPremul premul>
- void shadePremulSpan(int x, int y, typename DstTraits<dstType, premul>::Type[],
- int count) const;
-
- template <DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
- void shadeSpanInternal(int x, int y, typename DstTraits<dstType, premul>::Type[],
- int count) const;
-
- const Sk4fGradientInterval* findInterval(SkScalar fx) const;
-
- bool isFast() const { return fDstToPosClass == kLinear_MatrixClass; }
-
- static void D32_BlitBW(BlitState*, int x, int y, const SkPixmap& dst, int count);
- static void D64_BlitBW(BlitState*, int x, int y, const SkPixmap& dst, int count);
-
- mutable const Sk4fGradientInterval* fCachedInterval;
-};
-
-#endif // Sk4fLinearGradient_DEFINED
diff --git a/src/shaders/gradients/SkClampRange.cpp b/src/shaders/gradients/SkClampRange.cpp
deleted file mode 100644
index efc93959d1..0000000000
--- a/src/shaders/gradients/SkClampRange.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkClampRange.h"
-#include "SkMathPriv.h"
-
-static int SkCLZ64(uint64_t value) {
- int count = 0;
- if (value >> 32) {
- value >>= 32;
- } else {
- count += 32;
- }
- return count + SkCLZ(SkToU32(value));
-}
-
-static bool sk_64_smul_check(int64_t count, int64_t dx, int64_t* result) {
- // Do it the slow way until we have some assembly.
- if (dx == std::numeric_limits<int64_t>::min()) {
- return false; // SkTAbs overflow
- }
-
- SkASSERT(count >= 0);
- uint64_t ucount = static_cast<uint64_t>(count);
- uint64_t udx = static_cast<uint64_t>(SkTAbs(dx));
- int zeros = SkCLZ64(ucount) + SkCLZ64(udx);
- // this is a conservative check: it may return false when in fact it would not have overflowed.
- // Hackers Delight uses 34 as its convervative check, but that is for 32x32 multiplies.
- // Since we are looking at 64x64 muls, we add 32 to the check.
- if (zeros < (32 + 34)) {
- return false;
- }
- *result = count * dx;
- return true;
-}
-
-static bool sk_64_sadd_check(int64_t a, int64_t b, int64_t* result) {
- if (a > 0) {
- if (b > std::numeric_limits<int64_t>::max() - a) {
- return false;
- }
- } else {
- if (b < std::numeric_limits<int64_t>::min() - a) {
- return false;
- }
- }
-
- *result = a + b;
- return true;
-}
-
-
-/*
- * returns [0..count] for the number of steps (<= count) for which x0 <= edge
- * given each step is followed by x0 += dx
- */
-static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
- SkASSERT(dx > 0);
- SkASSERT(count >= 0);
-
- if (x0 >= edge) {
- return 0;
- }
- if (x1 <= edge) {
- return count;
- }
- int64_t n = (edge - x0 + dx - 1) / dx;
- SkASSERT(n >= 0);
- SkASSERT(n <= count);
- return (int)n;
-}
-
-void SkClampRange::initFor1(SkGradFixed fx) {
- fCount0 = fCount1 = fCount2 = 0;
- if (fx <= 0) {
- fCount0 = 1;
- } else if (fx < kFracMax_SkGradFixed) {
- fCount1 = 1;
- fFx1 = fx;
- } else {
- fCount2 = 1;
- }
-}
-
-void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
- SkASSERT(count > 0);
-
- fV0 = v0;
- fV1 = v1;
-
- // special case 1 == count, as it is slightly common for skia
- // and avoids us ever calling divide or 64bit multiply
- if (1 == count) {
- this->initFor1(fx0);
- return;
- }
-
- int64_t fx = fx0;
- int64_t dx = dx0;
-
- // start with ex equal to the last computed value
- int64_t count_times_dx, ex;
- if (!sk_64_smul_check(count - 1, dx, &count_times_dx) ||
- !sk_64_sadd_check(fx, count_times_dx, &ex)) {
- // we can't represent the computed end in 32.32, so just draw something (first color)
- fCount1 = fCount2 = 0;
- fCount0 = count;
- return;
- }
-
- if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
- fCount0 = fCount2 = 0;
- fCount1 = count;
- fFx1 = fx0;
- return;
- }
- if (fx <= 0 && ex <= 0) {
- fCount1 = fCount2 = 0;
- fCount0 = count;
- return;
- }
- if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
- fCount0 = fCount1 = 0;
- fCount2 = count;
- return;
- }
-
- // now make ex be 1 past the last computed value
- ex += dx;
-
- bool doSwap = dx < 0;
-
- if (doSwap) {
- ex -= dx;
- fx -= dx;
- SkTSwap(fx, ex);
- dx = -dx;
- }
-
-
- fCount0 = chop(fx, 0, ex, dx, count);
- SkASSERT(fCount0 >= 0);
- SkASSERT(fCount0 <= count);
- count -= fCount0;
- fx += fCount0 * dx;
- SkASSERT(fx >= 0);
- SkASSERT(fCount0 == 0 || (fx - dx) < 0);
- fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
- SkASSERT(fCount1 >= 0);
- SkASSERT(fCount1 <= count);
- count -= fCount1;
- fCount2 = count;
-
-#ifdef SK_DEBUG
- fx += fCount1 * dx;
- SkASSERT(fx <= ex);
- if (fCount2 > 0) {
- SkASSERT(fx >= kFracMax_SkGradFixed);
- if (fCount1 > 0) {
- SkASSERT(fx - dx < kFracMax_SkGradFixed);
- }
- }
-#endif
-
- if (doSwap) {
- SkTSwap(fCount0, fCount2);
- SkTSwap(fV0, fV1);
- dx = -dx;
- }
-
- if (fCount1 > 0) {
- fFx1 = fx0 + fCount0 * dx;
- }
-}
diff --git a/src/shaders/gradients/SkClampRange.h b/src/shaders/gradients/SkClampRange.h
deleted file mode 100644
index 8a22e72d38..0000000000
--- a/src/shaders/gradients/SkClampRange.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkClampRange_DEFINED
-#define SkClampRange_DEFINED
-
-#include "SkFixed.h"
-#include "SkScalar.h"
-
-#define SkGradFixed SkFixed3232
-
-// We want the largest 32.32 value representable as a float. (float)0x7FFFFFFF
-// becomes too big, due to limited mantissa on the float and its rounding rules, so
-// we have to manually compute the next smaller value (aka nextafter).
-
-// #define SkGradFixedMaxScalar nextafterf(SkFixed3232ToFloat(SkFixed3232Max), 0)
-// #define SkGradFixedMinScalar nextafterf(SkFixed3232ToFloat(SkFixed3232Min), 0)
-#define SkGradFixedMaxScalar ( 2147483520.0f)
-#define SkGradFixedMinScalar (-2147483520.0f)
-#define SkScalarPinToGradFixed(x) SkScalarToFixed3232(SkTPin(x, \
- SkGradFixedMinScalar,\
- SkGradFixedMaxScalar))
-#define SkFixedToGradFixed(x) SkFixedToFixed3232(x)
-#define SkGradFixedToFixed(x) (SkFixed)((x) >> 16)
-#define kFracMax_SkGradFixed 0xFFFFFFFFLL
-
-/**
- * Iteration fixed fx by dx, clamping as you go to [0..kFracMax_SkGradFixed], this class
- * computes the (up to) 3 spans there are:
- *
- * range0: use constant value V0
- * range1: iterate as usual fx += dx
- * range2: use constant value V1
- */
-struct SkClampRange {
- int fCount0; // count for fV0
- int fCount1; // count for interpolating (fV0...fV1)
- int fCount2; // count for fV1
- SkGradFixed fFx1; // initial fx value for the fCount1 range.
- // only valid if fCount1 > 0
- int fV0, fV1;
-
- void init(SkGradFixed fx, SkGradFixed dx, int count, int v0, int v1);
-
- void validate(int count) const {
-#ifdef SK_DEBUG
- SkASSERT(fCount0 >= 0);
- SkASSERT(fCount1 >= 0);
- SkASSERT(fCount2 >= 0);
- SkASSERT(fCount0 + fCount1 + fCount2 == count);
-#endif
- }
-
-private:
- void initFor1(SkGradFixed fx);
-};
-
-#endif
diff --git a/src/shaders/gradients/SkGradientBitmapCache.cpp b/src/shaders/gradients/SkGradientBitmapCache.cpp
deleted file mode 100644
index 06b2d8c3fe..0000000000
--- a/src/shaders/gradients/SkGradientBitmapCache.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkGradientBitmapCache.h"
-
-#include "SkMalloc.h"
-
-struct SkGradientBitmapCache::Entry {
- Entry* fPrev;
- Entry* fNext;
-
- void* fBuffer;
- size_t fSize;
- SkBitmap fBitmap;
-
- Entry(const void* buffer, size_t size, const SkBitmap& bm)
- : fPrev(nullptr),
- fNext(nullptr),
- fBitmap(bm) {
- fBuffer = sk_malloc_throw(size);
- fSize = size;
- memcpy(fBuffer, buffer, size);
- }
-
- ~Entry() { sk_free(fBuffer); }
-
- bool equals(const void* buffer, size_t size) const {
- return (fSize == size) && !memcmp(fBuffer, buffer, size);
- }
-};
-
-SkGradientBitmapCache::SkGradientBitmapCache(int max) : fMaxEntries(max) {
- fEntryCount = 0;
- fHead = fTail = nullptr;
-
- this->validate();
-}
-
-SkGradientBitmapCache::~SkGradientBitmapCache() {
- this->validate();
-
- Entry* entry = fHead;
- while (entry) {
- Entry* next = entry->fNext;
- delete entry;
- entry = next;
- }
-}
-
-SkGradientBitmapCache::Entry* SkGradientBitmapCache::release(Entry* entry) const {
- if (entry->fPrev) {
- SkASSERT(fHead != entry);
- entry->fPrev->fNext = entry->fNext;
- } else {
- SkASSERT(fHead == entry);
- fHead = entry->fNext;
- }
- if (entry->fNext) {
- SkASSERT(fTail != entry);
- entry->fNext->fPrev = entry->fPrev;
- } else {
- SkASSERT(fTail == entry);
- fTail = entry->fPrev;
- }
- return entry;
-}
-
-void SkGradientBitmapCache::attachToHead(Entry* entry) const {
- entry->fPrev = nullptr;
- entry->fNext = fHead;
- if (fHead) {
- fHead->fPrev = entry;
- } else {
- fTail = entry;
- }
- fHead = entry;
-}
-
-bool SkGradientBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const {
- AutoValidate av(this);
-
- Entry* entry = fHead;
- while (entry) {
- if (entry->equals(buffer, size)) {
- if (bm) {
- *bm = entry->fBitmap;
- }
- // move to the head of our list, so we purge it last
- this->release(entry);
- this->attachToHead(entry);
- return true;
- }
- entry = entry->fNext;
- }
- return false;
-}
-
-void SkGradientBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) {
- AutoValidate av(this);
-
- if (fEntryCount == fMaxEntries) {
- SkASSERT(fTail);
- delete this->release(fTail);
- fEntryCount -= 1;
- }
-
- Entry* entry = new Entry(buffer, len, bm);
- this->attachToHead(entry);
- fEntryCount += 1;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef SK_DEBUG
-
-void SkGradientBitmapCache::validate() const {
- SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries);
-
- if (fEntryCount > 0) {
- SkASSERT(nullptr == fHead->fPrev);
- SkASSERT(nullptr == fTail->fNext);
-
- if (fEntryCount == 1) {
- SkASSERT(fHead == fTail);
- } else {
- SkASSERT(fHead != fTail);
- }
-
- Entry* entry = fHead;
- int count = 0;
- while (entry) {
- count += 1;
- entry = entry->fNext;
- }
- SkASSERT(count == fEntryCount);
-
- entry = fTail;
- while (entry) {
- count -= 1;
- entry = entry->fPrev;
- }
- SkASSERT(0 == count);
- } else {
- SkASSERT(nullptr == fHead);
- SkASSERT(nullptr == fTail);
- }
-}
-
-#endif
diff --git a/src/shaders/gradients/SkGradientBitmapCache.h b/src/shaders/gradients/SkGradientBitmapCache.h
deleted file mode 100644
index 0dcd32272e..0000000000
--- a/src/shaders/gradients/SkGradientBitmapCache.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef SkGradientBitmapCache_DEFINED
-#define SkGradientBitmapCache_DEFINED
-
-#include "SkBitmap.h"
-
-class SkGradientBitmapCache : SkNoncopyable {
-public:
- SkGradientBitmapCache(int maxEntries);
- ~SkGradientBitmapCache();
-
- bool find(const void* buffer, size_t len, SkBitmap*) const;
- void add(const void* buffer, size_t len, const SkBitmap&);
-
-private:
- int fEntryCount;
- const int fMaxEntries;
-
- struct Entry;
- mutable Entry* fHead;
- mutable Entry* fTail;
-
- inline Entry* release(Entry*) const;
- inline void attachToHead(Entry*) const;
-
-#ifdef SK_DEBUG
- void validate() const;
-#else
- void validate() const {}
-#endif
-
- class AutoValidate : SkNoncopyable {
- public:
- AutoValidate(const SkGradientBitmapCache* bc) : fBC(bc) { bc->validate(); }
- ~AutoValidate() { fBC->validate(); }
- private:
- const SkGradientBitmapCache* fBC;
- };
-};
-
-#endif
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
deleted file mode 100644
index 137da84d0c..0000000000
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ /dev/null
@@ -1,2004 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <algorithm>
-#include "Sk4fLinearGradient.h"
-#include "SkColorSpace_XYZ.h"
-#include "SkGradientShaderPriv.h"
-#include "SkHalf.h"
-#include "SkLinearGradient.h"
-#include "SkMallocPixelRef.h"
-#include "SkRadialGradient.h"
-#include "SkSweepGradient.h"
-#include "SkTwoPointConicalGradient.h"
-#include "../../jumper/SkJumper.h"
-
-
-enum GradientSerializationFlags {
- // Bits 29:31 used for various boolean flags
- kHasPosition_GSF = 0x80000000,
- kHasLocalMatrix_GSF = 0x40000000,
- kHasColorSpace_GSF = 0x20000000,
-
- // Bits 12:28 unused
-
- // Bits 8:11 for fTileMode
- kTileModeShift_GSF = 8,
- kTileModeMask_GSF = 0xF,
-
- // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
- kGradFlagsShift_GSF = 0,
- kGradFlagsMask_GSF = 0xFF,
-};
-
-void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
- uint32_t flags = 0;
- if (fPos) {
- flags |= kHasPosition_GSF;
- }
- if (fLocalMatrix) {
- flags |= kHasLocalMatrix_GSF;
- }
- sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr;
- if (colorSpaceData) {
- flags |= kHasColorSpace_GSF;
- }
- SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF);
- flags |= (fTileMode << kTileModeShift_GSF);
- SkASSERT(fGradFlags <= kGradFlagsMask_GSF);
- flags |= (fGradFlags << kGradFlagsShift_GSF);
-
- buffer.writeUInt(flags);
-
- buffer.writeColor4fArray(fColors, fCount);
- if (colorSpaceData) {
- buffer.writeDataAsByteArray(colorSpaceData.get());
- }
- if (fPos) {
- buffer.writeScalarArray(fPos, fCount);
- }
- if (fLocalMatrix) {
- buffer.writeMatrix(*fLocalMatrix);
- }
-}
-
-bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
- if (buffer.isVersionLT(SkReadBuffer::kGradientShaderFloatColor_Version)) {
- fCount = buffer.getArrayCount();
- if (fCount > kStorageCount) {
- size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount;
- fDynamicStorage.reset(allocSize);
- fColors = (SkColor4f*)fDynamicStorage.get();
- fPos = (SkScalar*)(fColors + fCount);
- } else {
- fColors = fColorStorage;
- fPos = fPosStorage;
- }
-
- // Old gradients serialized SkColor. Read that to a temporary location, then convert.
- SkSTArray<2, SkColor, true> colors;
- colors.resize_back(fCount);
- if (!buffer.readColorArray(colors.begin(), fCount)) {
- return false;
- }
- for (int i = 0; i < fCount; ++i) {
- mutableColors()[i] = SkColor4f::FromColor(colors[i]);
- }
-
- if (buffer.readBool()) {
- if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) {
- return false;
- }
- } else {
- fPos = nullptr;
- }
-
- fColorSpace = nullptr;
- fTileMode = (SkShader::TileMode)buffer.read32();
- fGradFlags = buffer.read32();
-
- if (buffer.readBool()) {
- fLocalMatrix = &fLocalMatrixStorage;
- buffer.readMatrix(&fLocalMatrixStorage);
- } else {
- fLocalMatrix = nullptr;
- }
- } else {
- // New gradient format. Includes floating point color, color space, densely packed flags
- uint32_t flags = buffer.readUInt();
-
- fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF);
- fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF;
-
- fCount = buffer.getArrayCount();
- if (fCount > kStorageCount) {
- size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount;
- fDynamicStorage.reset(allocSize);
- fColors = (SkColor4f*)fDynamicStorage.get();
- fPos = (SkScalar*)(fColors + fCount);
- } else {
- fColors = fColorStorage;
- fPos = fPosStorage;
- }
- if (!buffer.readColor4fArray(mutableColors(), fCount)) {
- return false;
- }
- if (SkToBool(flags & kHasColorSpace_GSF)) {
- sk_sp<SkData> data = buffer.readByteArrayAsData();
- fColorSpace = SkColorSpace::Deserialize(data->data(), data->size());
- } else {
- fColorSpace = nullptr;
- }
- if (SkToBool(flags & kHasPosition_GSF)) {
- if (!buffer.readScalarArray(mutablePos(), fCount)) {
- return false;
- }
- } else {
- fPos = nullptr;
- }
- if (SkToBool(flags & kHasLocalMatrix_GSF)) {
- fLocalMatrix = &fLocalMatrixStorage;
- buffer.readMatrix(&fLocalMatrixStorage);
- } else {
- fLocalMatrix = nullptr;
- }
- }
- return buffer.isValid();
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-
-SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
- : INHERITED(desc.fLocalMatrix)
- , fPtsToUnit(ptsToUnit)
-{
- fPtsToUnit.getType(); // Precache so reads are threadsafe.
- SkASSERT(desc.fCount > 1);
-
- fGradFlags = static_cast<uint8_t>(desc.fGradFlags);
-
- SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
- SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
- fTileMode = desc.fTileMode;
- fTileProc = gTileProcs[desc.fTileMode];
-
- /* Note: we let the caller skip the first and/or last position.
- i.e. pos[0] = 0.3, pos[1] = 0.7
- In these cases, we insert dummy entries to ensure that the final data
- will be bracketed by [0, 1].
- i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
-
- Thus colorCount (the caller's value, and fColorCount (our value) may
- differ by up to 2. In the above example:
- colorCount = 2
- fColorCount = 4
- */
- fColorCount = desc.fCount;
- // check if we need to add in dummy start and/or end position/colors
- bool dummyFirst = false;
- bool dummyLast = false;
- if (desc.fPos) {
- dummyFirst = desc.fPos[0] != 0;
- dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
- fColorCount += dummyFirst + dummyLast;
- }
-
- if (fColorCount > kColorStorageCount) {
- size_t size = sizeof(SkColor) + sizeof(SkColor4f) + sizeof(Rec);
- if (desc.fPos) {
- size += sizeof(SkScalar);
- }
- fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(size * fColorCount));
- }
- else {
- fOrigColors = fStorage;
- }
-
- fOrigColors4f = (SkColor4f*)(fOrigColors + fColorCount);
-
- // Now copy over the colors, adding the dummies as needed
- SkColor4f* origColors = fOrigColors4f;
- if (dummyFirst) {
- *origColors++ = desc.fColors[0];
- }
- memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor4f));
- if (dummyLast) {
- origColors += desc.fCount;
- *origColors = desc.fColors[desc.fCount - 1];
- }
-
- // Convert our SkColor4f colors to SkColor as well. Note that this is incorrect if the
- // source colors are not in sRGB gamut. We would need to do a gamut transformation, but
- // SkColorSpaceXform can't do that (yet). GrColorSpaceXform can, but we may not have GPU
- // support compiled in here. For the common case (sRGB colors), this does the right thing.
- for (int i = 0; i < fColorCount; ++i) {
- fOrigColors[i] = fOrigColors4f[i].toSkColor();
- }
-
- if (!desc.fColorSpace) {
- // This happens if we were constructed from SkColors, so our colors are really sRGB
- fColorSpace = SkColorSpace::MakeSRGBLinear();
- } else {
- // The color space refers to the float colors, so it must be linear gamma
- SkASSERT(desc.fColorSpace->gammaIsLinear());
- fColorSpace = desc.fColorSpace;
- }
-
- if (desc.fPos && fColorCount) {
- fOrigPos = (SkScalar*)(fOrigColors4f + fColorCount);
- fRecs = (Rec*)(fOrigPos + fColorCount);
- } else {
- fOrigPos = nullptr;
- fRecs = (Rec*)(fOrigColors4f + fColorCount);
- }
-
- if (fColorCount > 2) {
- Rec* recs = fRecs;
- recs->fPos = 0;
- // recs->fScale = 0; // unused;
- recs += 1;
- if (desc.fPos) {
- SkScalar* origPosPtr = fOrigPos;
- *origPosPtr++ = 0;
-
- /* We need to convert the user's array of relative positions into
- fixed-point positions and scale factors. We need these results
- to be strictly monotonic (no two values equal or out of order).
- Hence this complex loop that just jams a zero for the scale
- value if it sees a segment out of order, and it assures that
- we start at 0 and end at 1.0
- */
- SkScalar prev = 0;
- int startIndex = dummyFirst ? 0 : 1;
- int count = desc.fCount + dummyLast;
- for (int i = startIndex; i < count; i++) {
- // force the last value to be 1.0
- SkScalar curr;
- if (i == desc.fCount) { // we're really at the dummyLast
- curr = 1;
- } else {
- curr = SkScalarPin(desc.fPos[i], 0, 1);
- }
- *origPosPtr++ = curr;
-
- recs->fPos = SkScalarToFixed(curr);
- SkFixed diff = SkScalarToFixed(curr - prev);
- if (diff > 0) {
- recs->fScale = (1 << 24) / diff;
- } else {
- recs->fScale = 0; // ignore this segment
- }
- // get ready for the next value
- prev = curr;
- recs += 1;
- }
- } else { // assume even distribution
- fOrigPos = nullptr;
-
- SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
- SkFixed p = dp;
- SkFixed scale = (desc.fCount - 1) << 8; // (1 << 24) / dp
- for (int i = 1; i < desc.fCount - 1; i++) {
- recs->fPos = p;
- recs->fScale = scale;
- recs += 1;
- p += dp;
- }
- recs->fPos = SK_Fixed1;
- recs->fScale = scale;
- }
- } else if (desc.fPos) {
- SkASSERT(2 == fColorCount);
- fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1);
- fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1);
- if (0 == fOrigPos[0] && 1 == fOrigPos[1]) {
- fOrigPos = nullptr;
- }
- }
- this->initCommon();
-}
-
-SkGradientShaderBase::~SkGradientShaderBase() {
- if (fOrigColors != fStorage) {
- sk_free(fOrigColors);
- }
-}
-
-void SkGradientShaderBase::initCommon() {
- unsigned colorAlpha = 0xFF;
- for (int i = 0; i < fColorCount; i++) {
- colorAlpha &= SkColorGetA(fOrigColors[i]);
- }
- fColorsAreOpaque = colorAlpha == 0xFF;
-}
-
-void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
- Descriptor desc;
- desc.fColors = fOrigColors4f;
- desc.fColorSpace = fColorSpace;
- desc.fPos = fOrigPos;
- desc.fCount = fColorCount;
- desc.fTileMode = fTileMode;
- desc.fGradFlags = fGradFlags;
-
- const SkMatrix& m = this->getLocalMatrix();
- desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
- desc.flatten(buffer);
-}
-
-void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
- SkColor* colorSrc, Rec* recSrc,
- int count) {
- SkAutoSTArray<8, SkColor> colorsTemp(count);
- for (int i = 0; i < count; ++i) {
- int offset = count - i - 1;
- colorsTemp[i] = colorSrc[offset];
- }
- if (count > 2) {
- SkAutoSTArray<8, Rec> recsTemp(count);
- for (int i = 0; i < count; ++i) {
- int offset = count - i - 1;
- recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos;
- recsTemp[i].fScale = recSrc[offset].fScale;
- }
- memcpy(recDst, recsTemp.get(), count * sizeof(Rec));
- }
- memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
-}
-
-static void add_stop_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f Fs, SkPM4f Bs) {
- (ctx->fs[0])[stop] = Fs.r();
- (ctx->fs[1])[stop] = Fs.g();
- (ctx->fs[2])[stop] = Fs.b();
- (ctx->fs[3])[stop] = Fs.a();
- (ctx->bs[0])[stop] = Bs.r();
- (ctx->bs[1])[stop] = Bs.g();
- (ctx->bs[2])[stop] = Bs.b();
- (ctx->bs[3])[stop] = Bs.a();
-}
-
-static void add_const_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f color) {
- add_stop_color(ctx, stop, SkPM4f::FromPremulRGBA(0,0,0,0), color);
-}
-
-// Calculate a factor F and a bias B so that color = F*t + B when t is in range of
-// the stop. Assume that the distance between stops is 1/gapCount.
-static void init_stop_evenly(
- SkJumper_GradientCtx* ctx, float gapCount, size_t stop, SkPM4f c_l, SkPM4f c_r) {
- // Clankium's GCC 4.9 targeting ARMv7 is barfing when we use Sk4f math here, so go scalar...
- SkPM4f Fs = {{
- (c_r.r() - c_l.r()) * gapCount,
- (c_r.g() - c_l.g()) * gapCount,
- (c_r.b() - c_l.b()) * gapCount,
- (c_r.a() - c_l.a()) * gapCount,
- }};
- SkPM4f Bs = {{
- c_l.r() - Fs.r()*(stop/gapCount),
- c_l.g() - Fs.g()*(stop/gapCount),
- c_l.b() - Fs.b()*(stop/gapCount),
- c_l.a() - Fs.a()*(stop/gapCount),
- }};
- add_stop_color(ctx, stop, Fs, Bs);
-}
-
-// For each stop we calculate a bias B and a scale factor F, such that
-// for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
-static void init_stop_pos(
- SkJumper_GradientCtx* ctx, size_t stop, float t_l, float t_r, SkPM4f c_l, SkPM4f c_r) {
- // See note about Clankium's old compiler in init_stop_evenly().
- SkPM4f Fs = {{
- (c_r.r() - c_l.r()) / (t_r - t_l),
- (c_r.g() - c_l.g()) / (t_r - t_l),
- (c_r.b() - c_l.b()) / (t_r - t_l),
- (c_r.a() - c_l.a()) / (t_r - t_l),
- }};
- SkPM4f Bs = {{
- c_l.r() - Fs.r()*t_l,
- c_l.g() - Fs.g()*t_l,
- c_l.b() - Fs.b()*t_l,
- c_l.a() - Fs.a()*t_l,
- }};
- ctx->ts[stop] = t_l;
- add_stop_color(ctx, stop, Fs, Bs);
-}
-
-bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dstCS,
- SkArenaAlloc* alloc,
- const SkMatrix& ctm,
- const SkPaint& paint,
- const SkMatrix* localM) const {
- SkMatrix matrix;
- if (!this->computeTotalInverse(ctm, localM, &matrix)) {
- return false;
- }
-
- SkRasterPipeline_<256> subclass;
- if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &subclass)) {
- return false;
- }
-
- auto* m = alloc->makeArrayDefault<float>(9);
- if (matrix.asAffine(m)) {
- p->append(SkRasterPipeline::matrix_2x3, m);
- } else {
- matrix.get9(m);
- p->append(SkRasterPipeline::matrix_perspective, m);
- }
-
- p->extend(subclass);
-
- switch(fTileMode) {
- case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x_1); break;
- case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x_1); break;
- case kClamp_TileMode:
- if (!fOrigPos) {
- // We clamp only when the stops are evenly spaced.
- // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1.
- // In that case, we must make sure we're using the general "gradient" stage,
- // which is the only stage that will correctly handle unclamped t.
- p->append(SkRasterPipeline::clamp_x_1);
- }
- }
-
- const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
- auto prepareColor = [premulGrad, dstCS, this](int i) {
- SkColor4f c = dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS)
- : SkColor4f_from_SkColor(fOrigColors[i], nullptr);
- return premulGrad ? c.premul()
- : SkPM4f::From4f(Sk4f::Load(&c));
- };
-
- // The two-stop case with stops at 0 and 1.
- if (fColorCount == 2 && fOrigPos == nullptr) {
- const SkPM4f c_l = prepareColor(0),
- c_r = prepareColor(1);
-
- // See F and B below.
- auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2);
- f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f());
- f_and_b[1] = c_l;
-
- p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, f_and_b);
- } else {
- auto* ctx = alloc->make<SkJumper_GradientCtx>();
-
- // Note: In order to handle clamps in search, the search assumes a stop conceptully placed
- // at -inf. Therefore, the max number of stops is fColorCount+1.
- for (int i = 0; i < 4; i++) {
- // Allocate at least at for the AVX2 gather from a YMM register.
- ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
- ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
- }
-
- if (fOrigPos == nullptr) {
- // Handle evenly distributed stops.
-
- size_t stopCount = fColorCount;
- float gapCount = stopCount - 1;
-
- SkPM4f c_l = prepareColor(0);
- for (size_t i = 0; i < stopCount - 1; i++) {
- SkPM4f c_r = prepareColor(i + 1);
- init_stop_evenly(ctx, gapCount, i, c_l, c_r);
- c_l = c_r;
- }
- add_const_color(ctx, stopCount - 1, c_l);
-
- ctx->stopCount = stopCount;
- p->append(SkRasterPipeline::evenly_spaced_gradient, ctx);
- } else {
- // Handle arbitrary stops.
-
- ctx->ts = alloc->makeArray<float>(fColorCount+1);
-
- // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
- // because they are naturally handled by the search method.
- int firstStop;
- int lastStop;
- if (fColorCount > 2) {
- firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
- lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
- ? fColorCount - 1 : fColorCount - 2;
- } else {
- firstStop = 0;
- lastStop = 1;
- }
-
- size_t stopCount = 0;
- float t_l = fOrigPos[firstStop];
- SkPM4f c_l = prepareColor(firstStop);
- add_const_color(ctx, stopCount++, c_l);
- // N.B. lastStop is the index of the last stop, not one after.
- for (int i = firstStop; i < lastStop; i++) {
- float t_r = fOrigPos[i + 1];
- SkPM4f c_r = prepareColor(i + 1);
- if (t_l < t_r) {
- init_stop_pos(ctx, stopCount, t_l, t_r, c_l, c_r);
- stopCount += 1;
- }
- t_l = t_r;
- c_l = c_r;
- }
-
- ctx->ts[stopCount] = t_l;
- add_const_color(ctx, stopCount++, c_l);
-
- ctx->stopCount = stopCount;
- p->append(SkRasterPipeline::gradient, ctx);
- }
- }
-
- if (!premulGrad && !this->colorsAreOpaque()) {
- p->append(SkRasterPipeline::premul);
- }
-
- return true;
-}
-
-
-bool SkGradientShaderBase::isOpaque() const {
- return fColorsAreOpaque;
-}
-
-static unsigned rounded_divide(unsigned numer, unsigned denom) {
- return (numer + (denom >> 1)) / denom;
-}
-
-bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
- // we just compute an average color.
- // possibly we could weight this based on the proportional width for each color
- // assuming they are not evenly distributed in the fPos array.
- int r = 0;
- int g = 0;
- int b = 0;
- const int n = fColorCount;
- for (int i = 0; i < n; ++i) {
- SkColor c = fOrigColors[i];
- r += SkColorGetR(c);
- g += SkColorGetG(c);
- b += SkColorGetB(c);
- }
- *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
- return true;
-}
-
-SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
- const SkGradientShaderBase& shader, const ContextRec& rec)
- : INHERITED(shader, rec)
-#ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING
- , fDither(true)
-#else
- , fDither(rec.fPaint->isDither())
-#endif
- , fCache(shader.refCache(getPaintAlpha(), fDither))
-{
- const SkMatrix& inverse = this->getTotalInverse();
-
- fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
-
- fDstToIndexProc = fDstToIndex.getMapXYProc();
- fDstToIndexClass = (uint8_t)SkShaderBase::Context::ComputeMatrixClass(fDstToIndex);
-
- // now convert our colors in to PMColors
- unsigned paintAlpha = this->getPaintAlpha();
-
- fFlags = this->INHERITED::getFlags();
- if (shader.fColorsAreOpaque && paintAlpha == 0xFF) {
- fFlags |= kOpaqueAlpha_Flag;
- }
-}
-
-bool SkGradientShaderBase::GradientShaderBaseContext::isValid() const {
- return fDstToIndex.isFinite();
-}
-
-SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
- U8CPU alpha, bool dither, const SkGradientShaderBase& shader)
- : fCacheAlpha(alpha)
- , fCacheDither(dither)
- , fShader(shader)
-{
- // Only initialize the cache in getCache32.
- fCache32 = nullptr;
-}
-
-SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {}
-
-/*
- * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
- * release builds, we saw a compiler error where the 0xFF parameter in
- * SkPackARGB32() was being totally ignored whenever it was called with
- * a non-zero add (e.g. 0x8000).
- *
- * We found two work-arounds:
- * 1. change r,g,b to unsigned (or just one of them)
- * 2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
- * of using |
- *
- * We chose #1 just because it was more localized.
- * See http://code.google.com/p/skia/issues/detail?id=1113
- *
- * The type SkUFixed encapsulate this need for unsigned, but logically Fixed.
- */
-typedef uint32_t SkUFixed;
-
-void SkGradientShaderBase::GradientShaderCache::Build32bitCache(
- SkPMColor cache[], SkColor c0, SkColor c1,
- int count, U8CPU paintAlpha, uint32_t gradFlags, bool dither) {
- SkASSERT(count > 1);
-
- // need to apply paintAlpha to our two endpoints
- uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
- uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
-
-
- const bool interpInPremul = SkToBool(gradFlags &
- SkGradientShader::kInterpolateColorsInPremul_Flag);
-
- uint32_t r0 = SkColorGetR(c0);
- uint32_t g0 = SkColorGetG(c0);
- uint32_t b0 = SkColorGetB(c0);
-
- uint32_t r1 = SkColorGetR(c1);
- uint32_t g1 = SkColorGetG(c1);
- uint32_t b1 = SkColorGetB(c1);
-
- if (interpInPremul) {
- r0 = SkMulDiv255Round(r0, a0);
- g0 = SkMulDiv255Round(g0, a0);
- b0 = SkMulDiv255Round(b0, a0);
-
- r1 = SkMulDiv255Round(r1, a1);
- g1 = SkMulDiv255Round(g1, a1);
- b1 = SkMulDiv255Round(b1, a1);
- }
-
- SkFixed da = SkIntToFixed(a1 - a0) / (count - 1);
- SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1);
- SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1);
- SkFixed db = SkIntToFixed(b1 - b0) / (count - 1);
-
- /* We pre-add 1/8 to avoid having to add this to our [0] value each time
- in the loop. Without this, the bias for each would be
- 0x2000 0xA000 0xE000 0x6000
- With this trick, we can add 0 for the first (no-op) and just adjust the
- others.
- */
- const SkUFixed bias0 = dither ? 0x2000 : 0x8000;
- const SkUFixed bias1 = dither ? 0x8000 : 0;
- const SkUFixed bias2 = dither ? 0xC000 : 0;
- const SkUFixed bias3 = dither ? 0x4000 : 0;
-
- SkUFixed a = SkIntToFixed(a0) + bias0;
- SkUFixed r = SkIntToFixed(r0) + bias0;
- SkUFixed g = SkIntToFixed(g0) + bias0;
- SkUFixed b = SkIntToFixed(b0) + bias0;
-
- /*
- * Our dither-cell (spatially) is
- * 0 2
- * 3 1
- * Where
- * [0] -> [-1/8 ... 1/8 ) values near 0
- * [1] -> [ 1/8 ... 3/8 ) values near 1/4
- * [2] -> [ 3/8 ... 5/8 ) values near 1/2
- * [3] -> [ 5/8 ... 7/8 ) values near 3/4
- */
-
- if (0xFF == a0 && 0 == da) {
- do {
- cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0 ) >> 16,
- (g + 0 ) >> 16,
- (b + 0 ) >> 16);
- cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + bias1) >> 16,
- (g + bias1) >> 16,
- (b + bias1) >> 16);
- cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + bias2) >> 16,
- (g + bias2) >> 16,
- (b + bias2) >> 16);
- cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + bias3) >> 16,
- (g + bias3) >> 16,
- (b + bias3) >> 16);
- cache += 1;
- r += dr;
- g += dg;
- b += db;
- } while (--count != 0);
- } else if (interpInPremul) {
- do {
- cache[kCache32Count*0] = SkPackARGB32((a + 0 ) >> 16,
- (r + 0 ) >> 16,
- (g + 0 ) >> 16,
- (b + 0 ) >> 16);
- cache[kCache32Count*1] = SkPackARGB32((a + bias1) >> 16,
- (r + bias1) >> 16,
- (g + bias1) >> 16,
- (b + bias1) >> 16);
- cache[kCache32Count*2] = SkPackARGB32((a + bias2) >> 16,
- (r + bias2) >> 16,
- (g + bias2) >> 16,
- (b + bias2) >> 16);
- cache[kCache32Count*3] = SkPackARGB32((a + bias3) >> 16,
- (r + bias3) >> 16,
- (g + bias3) >> 16,
- (b + bias3) >> 16);
- cache += 1;
- a += da;
- r += dr;
- g += dg;
- b += db;
- } while (--count != 0);
- } else { // interpolate in unpreml space
- do {
- cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0 ) >> 16,
- (r + 0 ) >> 16,
- (g + 0 ) >> 16,
- (b + 0 ) >> 16);
- cache[kCache32Count*1] = SkPremultiplyARGBInline((a + bias1) >> 16,
- (r + bias1) >> 16,
- (g + bias1) >> 16,
- (b + bias1) >> 16);
- cache[kCache32Count*2] = SkPremultiplyARGBInline((a + bias2) >> 16,
- (r + bias2) >> 16,
- (g + bias2) >> 16,
- (b + bias2) >> 16);
- cache[kCache32Count*3] = SkPremultiplyARGBInline((a + bias3) >> 16,
- (r + bias3) >> 16,
- (g + bias3) >> 16,
- (b + bias3) >> 16);
- cache += 1;
- a += da;
- r += dr;
- g += dg;
- b += db;
- } while (--count != 0);
- }
-}
-
-static inline int SkFixedToFFFF(SkFixed x) {
- SkASSERT((unsigned)x <= SK_Fixed1);
- return x - (x >> 16);
-}
-
-const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
- fCache32InitOnce(SkGradientShaderBase::GradientShaderCache::initCache32, this);
- SkASSERT(fCache32);
- return fCache32;
-}
-
-void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) {
- const int kNumberOfDitherRows = 4;
- const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows);
-
- SkASSERT(nullptr == cache->fCache32PixelRef);
- cache->fCache32PixelRef = SkMallocPixelRef::MakeAllocate(info, 0, nullptr);
- cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->pixels();
- if (cache->fShader.fColorCount == 2) {
- Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0],
- cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha,
- cache->fShader.fGradFlags, cache->fCacheDither);
- } else {
- Rec* rec = cache->fShader.fRecs;
- int prevIndex = 0;
- for (int i = 1; i < cache->fShader.fColorCount; i++) {
- int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
- SkASSERT(nextIndex < kCache32Count);
-
- if (nextIndex > prevIndex)
- Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1],
- cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
- cache->fCacheAlpha, cache->fShader.fGradFlags, cache->fCacheDither);
- prevIndex = nextIndex;
- }
- }
-}
-
-void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap) const {
- const bool interpInPremul = SkToBool(fGradFlags &
- SkGradientShader::kInterpolateColorsInPremul_Flag);
- SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels());
- uint32_t* pixelsS32 = reinterpret_cast<uint32_t*>(bitmap->getPixels());
-
- typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t;
-
- pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) {
- Sk4h c = SkFloatToHalf_finite_ftz(x);
- pixelsF16[4*index+0] = c[0];
- pixelsF16[4*index+1] = c[1];
- pixelsF16[4*index+2] = c[2];
- pixelsF16[4*index+3] = c[3];
- };
- pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) {
- pixelsS32[index] = Sk4f_toS32(c);
- };
-
- pixelWriteFn_t writeSizedPixel =
- (kRGBA_F16_SkColorType == bitmap->colorType()) ? writeF16Pixel : writeS32Pixel;
- pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) {
- writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index);
- };
-
- pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel;
-
- int prevIndex = 0;
- for (int i = 1; i < fColorCount; i++) {
- int nextIndex = (fColorCount == 2) ? (kCache32Count - 1)
- : SkFixedToFFFF(fRecs[i].fPos) >> kCache32Shift;
- SkASSERT(nextIndex < kCache32Count);
-
- if (nextIndex > prevIndex) {
- Sk4f c0 = Sk4f::Load(fOrigColors4f[i - 1].vec());
- Sk4f c1 = Sk4f::Load(fOrigColors4f[i].vec());
- if (interpInPremul) {
- c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f);
- c1 = c1 * Sk4f(c1[3], c1[3], c1[3], 1.0f);
- }
-
- Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex));
- Sk4f delta = (c1 - c0) * step;
-
- for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) {
- writePixel(c0, curIndex);
- c0 += delta;
- }
- }
- prevIndex = nextIndex;
- }
- SkASSERT(prevIndex == kCache32Count - 1);
-}
-
-/*
- * The gradient holds a cache for the most recent value of alpha. Successive
- * callers with the same alpha value will share the same cache.
- */
-sk_sp<SkGradientShaderBase::GradientShaderCache> SkGradientShaderBase::refCache(U8CPU alpha,
- bool dither) const {
- SkAutoMutexAcquire ama(fCacheMutex);
- if (!fCache || fCache->getAlpha() != alpha || fCache->getDither() != dither) {
- fCache.reset(new GradientShaderCache(alpha, dither, *this));
- }
- // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
- // Otherwise, the pointer may have been overwritten on a different thread before the object's
- // ref count was incremented.
- return fCache;
-}
-
-SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
-/*
- * Because our caller might rebuild the same (logically the same) gradient
- * over and over, we'd like to return exactly the same "bitmap" if possible,
- * allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
- * To do that, we maintain a private cache of built-bitmaps, based on our
- * colors and positions. Note: we don't try to flatten the fMapper, so if one
- * is present, we skip the cache for now.
- */
-void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap,
- GradientBitmapType bitmapType) const {
- // our caller assumes no external alpha, so we ensure that our cache is built with 0xFF
- sk_sp<GradientShaderCache> cache(this->refCache(0xFF, true));
-
- // build our key: [numColors + colors[] + {positions[]} + flags + colorType ]
- int count = 1 + fColorCount + 1 + 1;
- if (fColorCount > 2) {
- count += fColorCount - 1; // fRecs[].fPos
- }
-
- SkAutoSTMalloc<16, int32_t> storage(count);
- int32_t* buffer = storage.get();
-
- *buffer++ = fColorCount;
- memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
- buffer += fColorCount;
- if (fColorCount > 2) {
- for (int i = 1; i < fColorCount; i++) {
- *buffer++ = fRecs[i].fPos;
- }
- }
- *buffer++ = fGradFlags;
- *buffer++ = static_cast<int32_t>(bitmapType);
- SkASSERT(buffer - storage.get() == count);
-
- ///////////////////////////////////
-
- static SkGradientBitmapCache* gCache;
- // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp
- static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
- SkAutoMutexAcquire ama(gGradientCacheMutex);
-
- if (nullptr == gCache) {
- gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
- }
- size_t size = count * sizeof(int32_t);
-
- if (!gCache->find(storage.get(), size, bitmap)) {
- if (GradientBitmapType::kLegacy == bitmapType) {
- // force our cache32pixelref to be built
- (void)cache->getCache32();
- bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
- bitmap->setPixelRef(sk_ref_sp(cache->getCache32PixelRef()), 0, 0);
- } else {
- // For these cases we use the bitmap cache, but not the GradientShaderCache. So just
- // allocate and populate the bitmap's data directly.
-
- SkImageInfo info;
- switch (bitmapType) {
- case GradientBitmapType::kSRGB:
- info = SkImageInfo::Make(kCache32Count, 1, kRGBA_8888_SkColorType,
- kPremul_SkAlphaType,
- SkColorSpace::MakeSRGB());
- break;
- case GradientBitmapType::kHalfFloat:
- info = SkImageInfo::Make(
- kCache32Count, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeSRGBLinear());
- break;
- default:
- SkFAIL("Unexpected bitmap type");
- return;
- }
- bitmap->allocPixels(info);
- this->initLinearBitmap(bitmap);
- }
- gCache->add(storage.get(), size, *bitmap);
- }
-}
-
-void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const {
- if (info) {
- if (info->fColorCount >= fColorCount) {
- SkColor* colorLoc;
- Rec* recLoc;
- SkAutoSTArray<8, SkColor> colorStorage;
- SkAutoSTArray<8, Rec> recStorage;
- if (flipGrad && (info->fColors || info->fColorOffsets)) {
- colorStorage.reset(fColorCount);
- recStorage.reset(fColorCount);
- colorLoc = colorStorage.get();
- recLoc = recStorage.get();
- FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount);
- } else {
- colorLoc = fOrigColors;
- recLoc = fRecs;
- }
- if (info->fColors) {
- memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor));
- }
- if (info->fColorOffsets) {
- if (fColorCount == 2) {
- info->fColorOffsets[0] = 0;
- info->fColorOffsets[1] = SK_Scalar1;
- } else if (fColorCount > 2) {
- for (int i = 0; i < fColorCount; ++i) {
- info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos);
- }
- }
- }
- }
- info->fColorCount = fColorCount;
- info->fTileMode = fTileMode;
- info->fGradientFlags = fGradFlags;
- }
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkGradientShaderBase::toString(SkString* str) const {
-
- str->appendf("%d colors: ", fColorCount);
-
- for (int i = 0; i < fColorCount; ++i) {
- str->appendHex(fOrigColors[i], 8);
- if (i < fColorCount-1) {
- str->append(", ");
- }
- }
-
- if (fColorCount > 2) {
- str->append(" points: (");
- for (int i = 0; i < fColorCount; ++i) {
- str->appendScalar(SkFixedToScalar(fRecs[i].fPos));
- if (i < fColorCount-1) {
- str->append(", ");
- }
- }
- str->append(")");
- }
-
- static const char* gTileModeName[SkShader::kTileModeCount] = {
- "clamp", "repeat", "mirror"
- };
-
- str->append(" ");
- str->append(gTileModeName[fTileMode]);
-
- this->INHERITED::toString(str);
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-// Return true if these parameters are valid/legal/safe to construct a gradient
-//
-static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count,
- unsigned tileMode) {
- return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
-}
-
-static void desc_init(SkGradientShaderBase::Descriptor* desc,
- const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
- const SkScalar pos[], int colorCount,
- SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
- SkASSERT(colorCount > 1);
-
- desc->fColors = colors;
- desc->fColorSpace = std::move(colorSpace);
- desc->fPos = pos;
- desc->fCount = colorCount;
- desc->fTileMode = mode;
- desc->fGradFlags = flags;
- desc->fLocalMatrix = localMatrix;
-}
-
-// assumes colors is SkColor4f* and pos is SkScalar*
-#define EXPAND_1_COLOR(count) \
- SkColor4f tmp[2]; \
- do { \
- if (1 == count) { \
- tmp[0] = tmp[1] = colors[0]; \
- colors = tmp; \
- pos = nullptr; \
- count = 2; \
- } \
- } while (0)
-
-struct ColorStopOptimizer {
- ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos,
- int count, SkShader::TileMode mode)
- : fColors(colors)
- , fPos(pos)
- , fCount(count) {
-
- if (!pos || count != 3) {
- return;
- }
-
- if (SkScalarNearlyEqual(pos[0], 0.0f) &&
- SkScalarNearlyEqual(pos[1], 0.0f) &&
- SkScalarNearlyEqual(pos[2], 1.0f)) {
-
- if (SkShader::kRepeat_TileMode == mode ||
- SkShader::kMirror_TileMode == mode ||
- colors[0] == colors[1]) {
-
- // Ignore the leftmost color/pos.
- fColors += 1;
- fPos += 1;
- fCount = 2;
- }
- } else if (SkScalarNearlyEqual(pos[0], 0.0f) &&
- SkScalarNearlyEqual(pos[1], 1.0f) &&
- SkScalarNearlyEqual(pos[2], 1.0f)) {
-
- if (SkShader::kRepeat_TileMode == mode ||
- SkShader::kMirror_TileMode == mode ||
- colors[1] == colors[2]) {
-
- // Ignore the rightmost color/pos.
- fCount = 2;
- }
- }
- }
-
- const SkColor4f* fColors;
- const SkScalar* fPos;
- int fCount;
-};
-
-struct ColorConverter {
- ColorConverter(const SkColor* colors, int count) {
- for (int i = 0; i < count; ++i) {
- fColors4f.push_back(SkColor4f::FromColor(colors[i]));
- }
- }
-
- SkSTArray<2, SkColor4f, true> fColors4f;
-};
-
-sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
- const SkColor colors[],
- const SkScalar pos[], int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- ColorConverter converter(colors, colorCount);
- return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
- localMatrix);
-}
-
-sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
- const SkColor4f colors[],
- sk_sp<SkColorSpace> colorSpace,
- const SkScalar pos[], int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
- return nullptr;
- }
- if (!valid_grad(colors, pos, colorCount, mode)) {
- return nullptr;
- }
- if (1 == colorCount) {
- return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
- }
- if (localMatrix && !localMatrix->invert(nullptr)) {
- return nullptr;
- }
-
- 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<SkLinearGradient>(pts, desc);
-}
-
-sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
- const SkColor colors[],
- const SkScalar pos[], int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- ColorConverter converter(colors, colorCount);
- return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode,
- flags, localMatrix);
-}
-
-sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
- const SkColor4f colors[],
- sk_sp<SkColorSpace> colorSpace,
- const SkScalar pos[], int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- if (radius <= 0) {
- return nullptr;
- }
- if (!valid_grad(colors, pos, colorCount, mode)) {
- return nullptr;
- }
- if (1 == colorCount) {
- return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
- }
- if (localMatrix && !localMatrix->invert(nullptr)) {
- return nullptr;
- }
-
- 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<SkRadialGradient>(center, radius, desc);
-}
-
-sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
- SkScalar startRadius,
- const SkPoint& end,
- SkScalar endRadius,
- const SkColor colors[],
- const SkScalar pos[],
- int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- ColorConverter converter(colors, colorCount);
- return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(),
- nullptr, pos, colorCount, mode, flags, localMatrix);
-}
-
-sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
- SkScalar startRadius,
- const SkPoint& end,
- SkScalar endRadius,
- const SkColor4f colors[],
- sk_sp<SkColorSpace> colorSpace,
- const SkScalar pos[],
- int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- if (startRadius < 0 || endRadius < 0) {
- return nullptr;
- }
- if (!valid_grad(colors, pos, colorCount, mode)) {
- return nullptr;
- }
- if (startRadius == endRadius) {
- if (start == end || startRadius == 0) {
- return SkShader::MakeEmptyShader();
- }
- }
- if (localMatrix && !localMatrix->invert(nullptr)) {
- return nullptr;
- }
- EXPAND_1_COLOR(colorCount);
-
- ColorStopOptimizer opt(colors, pos, colorCount, mode);
-
- bool flipGradient = startRadius > endRadius;
-
- SkGradientShaderBase::Descriptor desc;
-
- if (!flipGradient) {
- desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
- localMatrix);
- return sk_make_sp<SkTwoPointConicalGradient>(start, startRadius, end, endRadius,
- flipGradient, desc);
- } else {
- SkAutoSTArray<8, SkColor4f> colorsNew(opt.fCount);
- SkAutoSTArray<8, SkScalar> posNew(opt.fCount);
- for (int i = 0; i < opt.fCount; ++i) {
- colorsNew[i] = opt.fColors[opt.fCount - i - 1];
- }
-
- if (pos) {
- for (int i = 0; i < opt.fCount; ++i) {
- posNew[i] = 1 - opt.fPos[opt.fCount - i - 1];
- }
- desc_init(&desc, colorsNew.get(), std::move(colorSpace), posNew.get(), opt.fCount, mode,
- flags, localMatrix);
- } else {
- desc_init(&desc, colorsNew.get(), std::move(colorSpace), nullptr, opt.fCount, mode,
- flags, localMatrix);
- }
-
- return sk_make_sp<SkTwoPointConicalGradient>(end, endRadius, start, startRadius,
- flipGradient, desc);
- }
-}
-
-sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
- const SkColor colors[],
- const SkScalar pos[],
- int colorCount,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- ColorConverter converter(colors, colorCount);
- return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, flags,
- localMatrix);
-}
-
-sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
- const SkColor4f colors[],
- sk_sp<SkColorSpace> colorSpace,
- const SkScalar pos[],
- int colorCount,
- uint32_t flags,
- const SkMatrix* localMatrix) {
- if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
- return nullptr;
- }
- if (1 == colorCount) {
- return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
- }
- if (localMatrix && !localMatrix->invert(nullptr)) {
- return nullptr;
- }
-
- auto 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);
-}
-
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "GrContext.h"
-#include "GrShaderCaps.h"
-#include "GrTextureStripAtlas.h"
-#include "gl/GrGLContext.h"
-#include "glsl/GrGLSLColorSpaceXformHelper.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramDataManager.h"
-#include "glsl/GrGLSLUniformHandler.h"
-#include "SkGr.h"
-
-static inline bool close_to_one_half(const SkFixed& val) {
- return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf);
-}
-
-static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) {
- switch (colorType) {
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- case GrGradientEffect::kSingleHardStop_ColorType:
- return 4;
- case GrGradientEffect::kHardStopLeftEdged_ColorType:
- case GrGradientEffect::kHardStopRightEdged_ColorType:
- return 3;
-#endif
- case GrGradientEffect::kTwo_ColorType:
- return 2;
- case GrGradientEffect::kThree_ColorType:
- return 3;
- case GrGradientEffect::kTexture_ColorType:
- return 0;
- }
-
- SkDEBUGFAIL("Unhandled ColorType in color_type_to_color_count()");
- return -1;
-}
-
-GrGradientEffect::ColorType GrGradientEffect::determineColorType(
- const SkGradientShaderBase& shader) {
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- if (shader.fOrigPos) {
- if (4 == shader.fColorCount) {
- if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
- SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2]) &&
- SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) {
-
- return kSingleHardStop_ColorType;
- }
- } else if (3 == shader.fColorCount) {
- if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
- SkScalarNearlyEqual(shader.fOrigPos[1], 0.0f) &&
- SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
-
- return kHardStopLeftEdged_ColorType;
- } else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
- SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) &&
- SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
-
- return kHardStopRightEdged_ColorType;
- }
- }
- }
-#endif
-
- if (SkShader::kClamp_TileMode == shader.getTileMode()) {
- if (2 == shader.fColorCount) {
- return kTwo_ColorType;
- } else if (3 == shader.fColorCount &&
- close_to_one_half(shader.getRecs()[1].fPos)) {
- return kThree_ColorType;
- }
- }
-
- return kTexture_ColorType;
-}
-
-void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler,
- const GrGradientEffect& ge) {
- if (int colorCount = color_type_to_color_count(ge.getColorType())) {
- fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
- kVec4f_GrSLType,
- kDefault_GrSLPrecision,
- "Colors",
- colorCount);
- if (ge.fColorType == kSingleHardStop_ColorType) {
- fHardStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
- kDefault_GrSLPrecision, "HardStopT");
- }
- } else {
- fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kFloat_GrSLType, kDefault_GrSLPrecision,
- "GradientYCoordFS");
- }
-}
-
-static inline void set_after_interp_color_uni_array(
- const GrGLSLProgramDataManager& pdman,
- const GrGLSLProgramDataManager::UniformHandle uni,
- const SkTDArray<SkColor4f>& colors,
- const GrColorSpaceXform* colorSpaceXform) {
- int count = colors.count();
- if (colorSpaceXform) {
- constexpr int kSmallCount = 10;
- SkAutoSTArray<4 * kSmallCount, float> vals(4 * count);
-
- for (int i = 0; i < count; i++) {
- colorSpaceXform->srcToDst().mapScalars(colors[i].vec(), &vals[4 * i]);
- }
-
- pdman.set4fv(uni, count, vals.get());
- } else {
- pdman.set4fv(uni, count, (float*)&colors[0]);
- }
-}
-
-static inline void set_before_interp_color_uni_array(
- const GrGLSLProgramDataManager& pdman,
- const GrGLSLProgramDataManager::UniformHandle uni,
- const SkTDArray<SkColor4f>& colors,
- const GrColorSpaceXform* colorSpaceXform) {
- int count = colors.count();
- constexpr int kSmallCount = 10;
- SkAutoSTArray<4 * kSmallCount, float> vals(4 * count);
-
- for (int i = 0; i < count; i++) {
- float a = colors[i].fA;
- vals[4 * i + 0] = colors[i].fR * a;
- vals[4 * i + 1] = colors[i].fG * a;
- vals[4 * i + 2] = colors[i].fB * a;
- vals[4 * i + 3] = a;
- }
-
- if (colorSpaceXform) {
- for (int i = 0; i < count; i++) {
- colorSpaceXform->srcToDst().mapScalars(&vals[4 * i]);
- }
- }
-
- pdman.set4fv(uni, count, vals.get());
-}
-
-static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
- const GrGLSLProgramDataManager::UniformHandle uni,
- const SkTDArray<SkColor>& colors) {
- int count = colors.count();
- constexpr int kSmallCount = 10;
-
- SkAutoSTArray<4*kSmallCount, float> vals(4*count);
-
- for (int i = 0; i < colors.count(); i++) {
- // RGBA
- vals[4*i + 0] = SkColorGetR(colors[i]) / 255.f;
- vals[4*i + 1] = SkColorGetG(colors[i]) / 255.f;
- vals[4*i + 2] = SkColorGetB(colors[i]) / 255.f;
- vals[4*i + 3] = SkColorGetA(colors[i]) / 255.f;
- }
-
- pdman.set4fv(uni, colors.count(), vals.get());
-}
-
-static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
- const GrGLSLProgramDataManager::UniformHandle uni,
- const SkTDArray<SkColor>& colors) {
- int count = colors.count();
- constexpr int kSmallCount = 10;
-
- SkAutoSTArray<4*kSmallCount, float> vals(4*count);
-
- for (int i = 0; i < count; i++) {
- float a = SkColorGetA(colors[i]) / 255.f;
- float aDiv255 = a / 255.f;
-
- // RGBA
- vals[4*i + 0] = SkColorGetR(colors[i]) * aDiv255;
- vals[4*i + 1] = SkColorGetG(colors[i]) * aDiv255;
- vals[4*i + 2] = SkColorGetB(colors[i]) * aDiv255;
- vals[4*i + 3] = a;
- }
-
- pdman.set4fv(uni, count, vals.get());
-}
-
-void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
- const GrFragmentProcessor& processor) {
- const GrGradientEffect& e = processor.cast<GrGradientEffect>();
-
- switch (e.getColorType()) {
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- case GrGradientEffect::kSingleHardStop_ColorType:
- pdman.set1f(fHardStopT, e.fPositions[1]);
- // fall through
- case GrGradientEffect::kHardStopLeftEdged_ColorType:
- case GrGradientEffect::kHardStopRightEdged_ColorType:
-#endif
- case GrGradientEffect::kTwo_ColorType:
- case GrGradientEffect::kThree_ColorType: {
- if (e.fColors4f.count() > 0) {
- // Gamma-correct / color-space aware
- if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
- set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors4f,
- e.fColorSpaceXform.get());
- } else {
- set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors4f,
- e.fColorSpaceXform.get());
- }
- } else {
- // Legacy mode. Would be nice if we had converted the 8-bit colors to float earlier
- if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
- set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors);
- } else {
- set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors);
- }
- }
-
- break;
- }
-
- case GrGradientEffect::kTexture_ColorType: {
- SkScalar yCoord = e.getYCoord();
- if (yCoord != fCachedYCoord) {
- pdman.set1f(fFSYUni, yCoord);
- fCachedYCoord = yCoord;
- }
- if (SkToBool(e.fColorSpaceXform)) {
- fColorSpaceHelper.setData(pdman, e.fColorSpaceXform.get());
- }
- break;
- }
- }
-}
-
-uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) {
- const GrGradientEffect& e = processor.cast<GrGradientEffect>();
-
- uint32_t key = 0;
-
- if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
- key |= kPremulBeforeInterpKey;
- }
-
- if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
- key |= kTwoColorKey;
- } else if (GrGradientEffect::kThree_ColorType == e.getColorType()) {
- key |= kThreeColorKey;
- }
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- else if (GrGradientEffect::kSingleHardStop_ColorType == e.getColorType()) {
- key |= kHardStopCenteredKey;
- } else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) {
- key |= kHardStopZeroZeroOneKey;
- } else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) {
- key |= kHardStopZeroOneOneKey;
- }
-
- if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) {
- key |= kClampTileMode;
- } else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) {
- key |= kRepeatTileMode;
- } else {
- key |= kMirrorTileMode;
- }
-#endif
-
- key |= GrColorSpaceXform::XformKey(e.fColorSpaceXform.get()) << kReservedBits;
-
- return key;
-}
-
-void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
- GrGLSLUniformHandler* uniformHandler,
- const GrShaderCaps* shaderCaps,
- const GrGradientEffect& ge,
- const char* gradientTValue,
- const char* outputColor,
- const char* inputColor,
- const TextureSamplers& texSamplers) {
- switch (ge.getColorType()) {
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- case kSingleHardStop_ColorType: {
- const char* t = gradientTValue;
- const char* colors = uniformHandler->getUniformCStr(fColorsUni);
- const char* stopT = uniformHandler->getUniformCStr(fHardStopT);
-
- fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
-
- // Account for tile mode
- if (SkShader::kRepeat_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
- } else if (SkShader::kMirror_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
- fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
- fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
- fragBuilder->codeAppendf(" } else {");
- fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
- fragBuilder->codeAppendf(" }");
- fragBuilder->codeAppendf("}");
- }
-
- // Calculate color
- fragBuilder->codeAppend ("vec4 start, end;");
- fragBuilder->codeAppend ("float relative_t;");
- fragBuilder->codeAppendf("if (clamp_t < %s) {", stopT);
- fragBuilder->codeAppendf(" start = %s[0];", colors);
- fragBuilder->codeAppendf(" end = %s[1];", colors);
- fragBuilder->codeAppendf(" relative_t = clamp_t / %s;", stopT);
- fragBuilder->codeAppend ("} else {");
- fragBuilder->codeAppendf(" start = %s[2];", colors);
- fragBuilder->codeAppendf(" end = %s[3];", colors);
- fragBuilder->codeAppendf(" relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT);
- fragBuilder->codeAppend ("}");
- fragBuilder->codeAppend ("vec4 colorTemp = mix(start, end, relative_t);");
-
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
- fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
- }
- if (ge.fColorSpaceXform) {
- fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
- }
- fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
-
- break;
- }
-
- case kHardStopLeftEdged_ColorType: {
- const char* t = gradientTValue;
- const char* colors = uniformHandler->getUniformCStr(fColorsUni);
-
- fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
-
- // Account for tile mode
- if (SkShader::kRepeat_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
- } else if (SkShader::kMirror_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
- fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
- fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
- fragBuilder->codeAppendf(" } else {");
- fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
- fragBuilder->codeAppendf(" }");
- fragBuilder->codeAppendf("}");
- }
-
- fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors,
- colors);
- if (SkShader::kClamp_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("if (%s < 0.0) {", t);
- fragBuilder->codeAppendf(" colorTemp = %s[0];", colors);
- fragBuilder->codeAppendf("}");
- }
-
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
- fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
- }
- if (ge.fColorSpaceXform) {
- fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
- }
- fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
-
- break;
- }
-
- case kHardStopRightEdged_ColorType: {
- const char* t = gradientTValue;
- const char* colors = uniformHandler->getUniformCStr(fColorsUni);
-
- fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
-
- // Account for tile mode
- if (SkShader::kRepeat_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
- } else if (SkShader::kMirror_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
- fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
- fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
- fragBuilder->codeAppendf(" } else {");
- fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
- fragBuilder->codeAppendf(" }");
- fragBuilder->codeAppendf("}");
- }
-
- fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors,
- colors);
- if (SkShader::kClamp_TileMode == ge.fTileMode) {
- fragBuilder->codeAppendf("if (%s > 1.0) {", t);
- fragBuilder->codeAppendf(" colorTemp = %s[2];", colors);
- fragBuilder->codeAppendf("}");
- }
-
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
- fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
- }
- if (ge.fColorSpaceXform) {
- fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
- }
- fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
-
- break;
- }
-#endif
-
- case kTwo_ColorType: {
- const char* t = gradientTValue;
- const char* colors = uniformHandler->getUniformCStr(fColorsUni);
-
- fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp(%s, 0.0, 1.0));",
- colors, colors, t);
-
- // We could skip this step if both colors are known to be opaque. Two
- // considerations:
- // The gradient SkShader reporting opaque is more restrictive than necessary in the two
- // pt case. Make sure the key reflects this optimization (and note that it can use the
- // same shader as thekBeforeIterp case). This same optimization applies to the 3 color
- // case below.
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
- fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
- }
- if (ge.fColorSpaceXform) {
- fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
- }
-
- fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
-
- break;
- }
-
- case kThree_ColorType: {
- const char* t = gradientTValue;
- const char* colors = uniformHandler->getUniformCStr(fColorsUni);
-
- fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t);
- fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];",
- colors);
- if (!shaderCaps->canUseMinAndAbsTogether()) {
- // The Tegra3 compiler will sometimes never return if we have
- // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
- fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);");
- fragBuilder->codeAppendf("minAbs = minAbs > 1.0 ? 1.0 : minAbs;");
- fragBuilder->codeAppendf("colorTemp += (1.0 - minAbs) * %s[1];", colors);
- } else {
- fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];",
- colors);
- }
- fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors);
-
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
- fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
- }
- if (ge.fColorSpaceXform) {
- fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
- }
-
- fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
-
- break;
- }
-
- case kTexture_ColorType: {
- fColorSpaceHelper.emitCode(uniformHandler, ge.fColorSpaceXform.get());
-
- const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni);
-
- fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni);
- fragBuilder->codeAppendf("%s = ", outputColor);
- fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord",
- kVec2f_GrSLType, &fColorSpaceHelper);
- fragBuilder->codeAppend(";");
-
- break;
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-
-inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) {
- return isOpaque
- ? kPreservesOpaqueInput_OptimizationFlag |
- kCompatibleWithCoverageAsAlpha_OptimizationFlag
- : kCompatibleWithCoverageAsAlpha_OptimizationFlag;
-}
-
-GrGradientEffect::GrGradientEffect(const CreateArgs& args, bool isOpaque)
- : INHERITED(OptFlags(isOpaque)) {
- const SkGradientShaderBase& shader(*args.fShader);
-
- fIsOpaque = shader.isOpaque();
-
- fColorType = this->determineColorType(shader);
- fColorSpaceXform = std::move(args.fColorSpaceXform);
-
- if (kTexture_ColorType != fColorType) {
- SkASSERT(shader.fOrigColors && shader.fOrigColors4f);
- if (args.fGammaCorrect) {
- fColors4f = SkTDArray<SkColor4f>(shader.fOrigColors4f, shader.fColorCount);
- } else {
- fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount);
- }
-
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- if (shader.fOrigPos) {
- fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount);
- }
-#endif
- }
-
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- fTileMode = args.fTileMode;
-#endif
-
- switch (fColorType) {
- // The two and three color specializations do not currently support tiling.
- case kTwo_ColorType:
- case kThree_ColorType:
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- case kHardStopLeftEdged_ColorType:
- case kHardStopRightEdged_ColorType:
- case kSingleHardStop_ColorType:
-#endif
- fRow = -1;
-
- if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
- fPremulType = kBeforeInterp_PremulType;
- } else {
- fPremulType = kAfterInterp_PremulType;
- }
-
- fCoordTransform.reset(*args.fMatrix);
-
- break;
- case kTexture_ColorType:
- // doesn't matter how this is set, just be consistent because it is part of the
- // effect key.
- fPremulType = kBeforeInterp_PremulType;
-
- SkGradientShaderBase::GradientBitmapType bitmapType =
- SkGradientShaderBase::GradientBitmapType::kLegacy;
- if (args.fGammaCorrect) {
- // Try to use F16 if we can
- if (args.fContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
- bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat;
- } else if (args.fContext->caps()->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) {
- bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB;
- } else {
- // This can happen, but only if someone explicitly creates an unsupported
- // (eg sRGB) surface. Just fall back to legacy behavior.
- }
- }
-
- SkBitmap bitmap;
- shader.getGradientTableBitmap(&bitmap, bitmapType);
- SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width()));
-
-
- GrTextureStripAtlas::Desc desc;
- desc.fWidth = bitmap.width();
- desc.fHeight = 32;
- desc.fRowHeight = bitmap.height();
- desc.fContext = args.fContext;
- desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps());
- fAtlas = GrTextureStripAtlas::GetAtlas(desc);
- SkASSERT(fAtlas);
-
- // We always filter the gradient table. Each table is one row of a texture, always
- // y-clamp.
- GrSamplerParams params;
- params.setFilterMode(GrSamplerParams::kBilerp_FilterMode);
- params.setTileModeX(args.fTileMode);
-
- fRow = fAtlas->lockRow(bitmap);
- if (-1 != fRow) {
- fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
- // This is 1/2 places where auto-normalization is disabled
- fCoordTransform.reset(args.fContext->resourceProvider(), *args.fMatrix,
- fAtlas->asTextureProxyRef().get(), false);
- fTextureSampler.reset(args.fContext->resourceProvider(),
- fAtlas->asTextureProxyRef(), params);
- } else {
- // In this instance we know the params are:
- // clampY, bilerp
- // and the proxy is:
- // exact fit, power of two in both dimensions
- // Only the x-tileMode is unknown. However, given all the other knowns we know
- // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be
- // extracted to a subset or mipmapped).
- sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(
- args.fContext->resourceProvider(),
- bitmap);
- if (!proxy) {
- return;
- }
- // This is 2/2 places where auto-normalization is disabled
- fCoordTransform.reset(args.fContext->resourceProvider(), *args.fMatrix,
- proxy.get(), false);
- fTextureSampler.reset(args.fContext->resourceProvider(),
- std::move(proxy), params);
- fYCoord = SK_ScalarHalf;
- }
-
- this->addTextureSampler(&fTextureSampler);
-
- break;
- }
-
- this->addCoordTransform(&fCoordTransform);
-}
-
-GrGradientEffect::~GrGradientEffect() {
- if (this->useAtlas()) {
- fAtlas->unlockRow(fRow);
- }
-}
-
-bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
- const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
-
- if (this->fColorType != ge.getColorType()) {
- return false;
- }
- SkASSERT(this->useAtlas() == ge.useAtlas());
- if (kTexture_ColorType == fColorType) {
- if (fYCoord != ge.getYCoord()) {
- return false;
- }
- } else {
- if (kSingleHardStop_ColorType == fColorType) {
- if (!SkScalarNearlyEqual(ge.fPositions[1], fPositions[1])) {
- return false;
- }
- }
- if (this->getPremulType() != ge.getPremulType() ||
- this->fColors.count() != ge.fColors.count() ||
- this->fColors4f.count() != ge.fColors4f.count()) {
- return false;
- }
-
- for (int i = 0; i < this->fColors.count(); i++) {
- if (*this->getColors(i) != *ge.getColors(i)) {
- return false;
- }
- }
- for (int i = 0; i < this->fColors4f.count(); i++) {
- if (*this->getColors4f(i) != *ge.getColors4f(i)) {
- return false;
- }
- }
- }
- return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get());
-}
-
-#if GR_TEST_UTILS
-GrGradientEffect::RandomGradientParams::RandomGradientParams(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);
- if (fColorSpace) {
- SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(fColorSpace)->type());
- fColorSpace = static_cast<SkColorSpace_XYZ*>(fColorSpace.get())->makeLinearGamma();
- }
- }
-
- 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
-
-#endif
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
deleted file mode 100644
index 7a66edaffc..0000000000
--- a/src/shaders/gradients/SkGradientShaderPriv.h
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkGradientShaderPriv_DEFINED
-#define SkGradientShaderPriv_DEFINED
-
-#include "SkGradientBitmapCache.h"
-#include "SkGradientShader.h"
-
-#include "SkArenaAlloc.h"
-#include "SkAutoMalloc.h"
-#include "SkClampRange.h"
-#include "SkColorPriv.h"
-#include "SkColorSpace.h"
-#include "SkOnce.h"
-#include "SkPM4fPriv.h"
-#include "SkRasterPipeline.h"
-#include "SkReadBuffer.h"
-#include "SkShaderBase.h"
-#include "SkUtils.h"
-#include "SkWriteBuffer.h"
-
-#if SK_SUPPORT_GPU
- #define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
-#endif
-
-static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
- int count) {
- if (count > 0) {
- if (v0 == v1) {
- sk_memset32(dst, v0, count);
- } else {
- int pairs = count >> 1;
- for (int i = 0; i < pairs; i++) {
- *dst++ = v0;
- *dst++ = v1;
- }
- if (count & 1) {
- *dst = v0;
- }
- }
- }
-}
-
-// Clamp
-
-static inline SkFixed clamp_tileproc(SkFixed x) {
- return SkClampMax(x, 0xFFFF);
-}
-
-// Repeat
-
-static inline SkFixed repeat_tileproc(SkFixed x) {
- return x & 0xFFFF;
-}
-
-// Mirror
-
-static inline SkFixed mirror_tileproc(SkFixed x) {
- int s = SkLeftShift(x, 15) >> 31;
- return (x ^ s) & 0xFFFF;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-typedef SkFixed (*TileProc)(SkFixed);
-
-///////////////////////////////////////////////////////////////////////////////
-
-static const TileProc gTileProcs[] = {
- clamp_tileproc,
- repeat_tileproc,
- mirror_tileproc
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class SkGradientShaderBase : public SkShaderBase {
-public:
- struct Descriptor {
- Descriptor() {
- sk_bzero(this, sizeof(*this));
- fTileMode = SkShader::kClamp_TileMode;
- }
-
- const SkMatrix* fLocalMatrix;
- const SkColor4f* fColors;
- sk_sp<SkColorSpace> fColorSpace;
- const SkScalar* fPos;
- int fCount;
- SkShader::TileMode fTileMode;
- uint32_t fGradFlags;
-
- void flatten(SkWriteBuffer&) const;
- };
-
- class DescriptorScope : public Descriptor {
- public:
- DescriptorScope() {}
-
- bool unflatten(SkReadBuffer&);
-
- // fColors and fPos always point into local memory, so they can be safely mutated
- //
- SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
- SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
-
- private:
- enum {
- kStorageCount = 16
- };
- SkColor4f fColorStorage[kStorageCount];
- SkScalar fPosStorage[kStorageCount];
- SkMatrix fLocalMatrixStorage;
- SkAutoMalloc fDynamicStorage;
- };
-
- SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
- ~SkGradientShaderBase() override;
-
- // The cache is initialized on-demand when getCache32 is called.
- class GradientShaderCache : public SkRefCnt {
- public:
- GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader);
- ~GradientShaderCache();
-
- const SkPMColor* getCache32();
-
- SkPixelRef* getCache32PixelRef() const { return fCache32PixelRef.get(); }
-
- unsigned getAlpha() const { return fCacheAlpha; }
- bool getDither() const { return fCacheDither; }
-
- private:
- // Working pointer. If it's nullptr, we need to recompute the cache values.
- SkPMColor* fCache32;
-
- sk_sp<SkPixelRef> fCache32PixelRef;
- const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
- // Larger than 8bits so we can store uninitialized
- // value.
- const bool fCacheDither; // The dither flag used when we computed the cache.
-
- const SkGradientShaderBase& fShader;
-
- // Make sure we only initialize the cache once.
- SkOnce fCache32InitOnce;
-
- static void initCache32(GradientShaderCache* cache);
-
- static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
- U8CPU alpha, uint32_t gradFlags, bool dither);
- };
-
- class GradientShaderBaseContext : public Context {
- public:
- GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
-
- uint32_t getFlags() const override { return fFlags; }
-
- bool isValid() const;
-
- protected:
- SkMatrix fDstToIndex;
- SkMatrix::MapXYProc fDstToIndexProc;
- uint8_t fDstToIndexClass;
- uint8_t fFlags;
- bool fDither;
-
- sk_sp<GradientShaderCache> fCache;
-
- private:
- typedef Context INHERITED;
- };
-
- bool isOpaque() const override;
-
- enum class GradientBitmapType : uint8_t {
- kLegacy,
- kSRGB,
- kHalfFloat,
- };
-
- void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
-
- enum {
- /// Seems like enough for visual accuracy. TODO: if pos[] deserves
- /// it, use a larger cache.
- kCache32Bits = 8,
- kCache32Count = (1 << kCache32Bits),
- kCache32Shift = 16 - kCache32Bits,
- kSqrt32Shift = 8 - kCache32Bits,
-
- /// This value is used to *read* the dither cache; it may be 0
- /// if dithering is disabled.
- kDitherStride32 = kCache32Count,
- };
-
- uint32_t getGradFlags() const { return fGradFlags; }
-
-protected:
- struct Rec {
- SkFixed fPos; // 0...1
- uint32_t fScale; // (1 << 24) / range
- };
-
- class GradientShaderBase4fContext;
-
- SkGradientShaderBase(SkReadBuffer& );
- void flatten(SkWriteBuffer&) const override;
- SK_TO_STRING_OVERRIDE()
-
- void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
-
- bool onAsLuminanceColor(SkColor*) const override;
-
- void initLinearBitmap(SkBitmap* bitmap) const;
-
- /*
- * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
- * Count is the number of colors in the gradient
- * It will then flip all the color and rec information and return in their respective Dst
- * pointers. It is assumed that space has already been allocated for the Dst pointers.
- * The rec src and dst are only assumed to be valid if count > 2
- */
- static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
- SkColor* colorSrc, Rec* recSrc,
- int count);
-
- bool onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS, SkArenaAlloc* alloc,
- const SkMatrix& ctm, const SkPaint& paint,
- const SkMatrix* localM) const override;
-
- virtual bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const { return false; }
-
- template <typename T, typename... Args>
- static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
- auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
- if (!ctx->isValid()) {
- return nullptr;
- }
- return ctx;
- }
-
- const SkMatrix fPtsToUnit;
- TileMode fTileMode;
- TileProc fTileProc;
- uint8_t fGradFlags;
- Rec* fRecs;
-
-private:
- enum {
- kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
-
- kStorageSize = kColorStorageCount *
- (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
- };
- SkColor fStorage[(kStorageSize + 3) >> 2];
-public:
- SkColor* fOrigColors; // original colors, before modulation by paint in context.
- SkColor4f* fOrigColors4f; // original colors, as linear floats
- SkScalar* fOrigPos; // original positions
- int fColorCount;
- sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
-
- bool colorsAreOpaque() const { return fColorsAreOpaque; }
-
- TileMode getTileMode() const { return fTileMode; }
- Rec* getRecs() const { return fRecs; }
-
-private:
- bool fColorsAreOpaque;
-
- sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const;
- mutable SkMutex fCacheMutex;
- mutable sk_sp<GradientShaderCache> fCache;
-
- void initCommon();
-
- typedef SkShaderBase INHERITED;
-};
-
-
-static inline int init_dither_toggle(int x, int y) {
- x &= 1;
- y = (y & 1) << 1;
- return (x | y) * SkGradientShaderBase::kDitherStride32;
-}
-
-static inline int next_dither_toggle(int toggle) {
- return toggle ^ SkGradientShaderBase::kDitherStride32;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "GrColorSpaceXform.h"
-#include "GrCoordTransform.h"
-#include "GrFragmentProcessor.h"
-#include "glsl/GrGLSLColorSpaceXformHelper.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLProgramDataManager.h"
-
-class GrInvariantOutput;
-
-/*
- * The interpretation of the texture matrix depends on the sample mode. The
- * texture matrix is applied both when the texture coordinates are explicit
- * and when vertex positions are used as texture coordinates. In the latter
- * case the texture matrix is applied to the pre-view-matrix position
- * values.
- *
- * Normal SampleMode
- * The post-matrix texture coordinates are in normalize space with (0,0) at
- * the top-left and (1,1) at the bottom right.
- * RadialGradient
- * The matrix specifies the radial gradient parameters.
- * (0,0) in the post-matrix space is center of the radial gradient.
- * Radial2Gradient
- * Matrix transforms to space where first circle is centered at the
- * origin. The second circle will be centered (x, 0) where x may be
- * 0 and is provided by setRadial2Params. The post-matrix space is
- * normalized such that 1 is the second radius - first radius.
- * SweepGradient
- * The angle from the origin of texture coordinates in post-matrix space
- * determines the gradient value.
- */
-
- class GrTextureStripAtlas;
-
-// Base class for Gr gradient effects
-class GrGradientEffect : public GrFragmentProcessor {
-public:
- struct CreateArgs {
- CreateArgs(GrContext* context,
- const SkGradientShaderBase* shader,
- const SkMatrix* matrix,
- SkShader::TileMode tileMode,
- sk_sp<GrColorSpaceXform> colorSpaceXform,
- bool gammaCorrect)
- : fContext(context)
- , fShader(shader)
- , fMatrix(matrix)
- , fTileMode(tileMode)
- , fColorSpaceXform(std::move(colorSpaceXform))
- , fGammaCorrect(gammaCorrect) {}
-
- GrContext* fContext;
- const SkGradientShaderBase* fShader;
- const SkMatrix* fMatrix;
- SkShader::TileMode fTileMode;
- sk_sp<GrColorSpaceXform> fColorSpaceXform;
- bool fGammaCorrect;
- };
-
- class GLSLProcessor;
-
- ~GrGradientEffect() override;
-
- bool useAtlas() const { return SkToBool(-1 != fRow); }
- SkScalar getYCoord() const { return fYCoord; }
-
- enum ColorType {
- kTwo_ColorType,
- kThree_ColorType, // Symmetric three color
- kTexture_ColorType,
-
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- kSingleHardStop_ColorType, // 0, t, t, 1
- kHardStopLeftEdged_ColorType, // 0, 0, 1
- kHardStopRightEdged_ColorType, // 0, 1, 1
-#endif
- };
-
- ColorType getColorType() const { return fColorType; }
-
- // Determines the type of gradient, one of:
- // - Two-color
- // - Symmetric three-color
- // - Texture
- // - Centered hard stop
- // - Left-edged hard stop
- // - Right-edged hard stop
- ColorType determineColorType(const SkGradientShaderBase& shader);
-
- enum PremulType {
- kBeforeInterp_PremulType,
- kAfterInterp_PremulType,
- };
-
- PremulType getPremulType() const { return fPremulType; }
-
- const SkColor* getColors(int pos) const {
- SkASSERT(fColorType != kTexture_ColorType);
- SkASSERT(pos < fColors.count());
- return &fColors[pos];
- }
-
- const SkColor4f* getColors4f(int pos) const {
- SkASSERT(fColorType != kTexture_ColorType);
- SkASSERT(pos < fColors4f.count());
- return &fColors4f[pos];
- }
-
-protected:
- GrGradientEffect(const CreateArgs&, bool isOpaque);
-
- #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 RandomGradientParams {
- static const int kMaxRandomGradientColors = 5;
-
- RandomGradientParams(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
-
- bool onIsEqual(const GrFragmentProcessor&) const override;
-
- const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
-
-private:
- static OptimizationFlags OptFlags(bool isOpaque);
-
- // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
- // fColors4f and fColorSpaceXform will be populated.
- SkTDArray<SkColor> fColors;
-
- SkTDArray<SkColor4f> fColors4f;
- sk_sp<GrColorSpaceXform> fColorSpaceXform;
-
- SkTDArray<SkScalar> fPositions;
- SkShader::TileMode fTileMode;
-
- GrCoordTransform fCoordTransform;
- TextureSampler fTextureSampler;
- SkScalar fYCoord;
- GrTextureStripAtlas* fAtlas;
- int fRow;
- bool fIsOpaque;
- ColorType fColorType;
- PremulType fPremulType; // This is already baked into the table for texture gradients, and
- // only changes behavior for gradients that don't use a texture.
- typedef GrFragmentProcessor INHERITED;
-
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-// Base class for GL gradient effects
-class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
-public:
- GLSLProcessor() {
- fCachedYCoord = SK_ScalarMax;
- }
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
-protected:
- /**
- * Subclasses must call this. It will return a key for the part of the shader code controlled
- * by the base class. The subclasses must stick it in their key and then pass it to the below
- * emit* functions from their emitCode function.
- */
- static uint32_t GenBaseGradientKey(const GrProcessor&);
-
- // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
- // should call this method from their emitCode().
- void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
-
- // Emit code that gets a fragment's color from an expression for t; has branches for
- // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
- // color gradients that use the traditional texture lookup, as well as several varieties
- // of hard stop gradients
- void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
- GrGLSLUniformHandler* uniformHandler,
- const GrShaderCaps* shaderCaps,
- const GrGradientEffect&,
- const char* gradientTValue,
- const char* outputColor,
- const char* inputColor,
- const TextureSamplers&);
-
-private:
- enum {
- // First bit for premul before/after interp
- kPremulBeforeInterpKey = 1,
-
- // Next three bits for 2/3 color type or different special
- // hard stop cases (neither means using texture atlas)
- kTwoColorKey = 2,
- kThreeColorKey = 4,
-#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
- kHardStopCenteredKey = 6,
- kHardStopZeroZeroOneKey = 8,
- kHardStopZeroOneOneKey = 10,
-
- // Next two bits for tile mode
- kClampTileMode = 16,
- kRepeatTileMode = 32,
- kMirrorTileMode = 48,
-
- // Lower six bits for premul, 2/3 color type, and tile mode
- kReservedBits = 6,
-#endif
- };
-
- SkScalar fCachedYCoord;
- GrGLSLProgramDataManager::UniformHandle fColorsUni;
- GrGLSLProgramDataManager::UniformHandle fHardStopT;
- GrGLSLProgramDataManager::UniformHandle fFSYUni;
- GrGLSLColorSpaceXformHelper fColorSpaceHelper;
-
- typedef GrGLSLFragmentProcessor INHERITED;
-};
-
-#endif
-
-#endif
diff --git a/src/shaders/gradients/SkLinearGradient.cpp b/src/shaders/gradients/SkLinearGradient.cpp
deleted file mode 100644
index 17c4fd36a4..0000000000
--- a/src/shaders/gradients/SkLinearGradient.cpp
+++ /dev/null
@@ -1,804 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Sk4fLinearGradient.h"
-#include "SkColorSpaceXformer.h"
-#include "SkLinearGradient.h"
-#include "SkRefCnt.h"
-
-// define to test the 4f gradient path
-// #define FORCE_4F_CONTEXT
-
-static const float kInv255Float = 1.0f / 255;
-
-static inline int repeat_8bits(int x) {
- return x & 0xFF;
-}
-
-static inline int mirror_8bits(int x) {
- if (x & 256) {
- x = ~x;
- }
- return x & 255;
-}
-
-static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
- SkVector vec = pts[1] - pts[0];
- SkScalar mag = vec.length();
- SkScalar inv = mag ? SkScalarInvert(mag) : 0;
-
- vec.scale(inv);
- SkMatrix matrix;
- matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
- matrix.postTranslate(-pts[0].fX, -pts[0].fY);
- matrix.postScale(inv, inv);
- return matrix;
-}
-
-static bool use_4f_context(const SkShaderBase::ContextRec& rec, uint32_t flags) {
-#ifdef FORCE_4F_CONTEXT
- return true;
-#else
- return rec.fPreferredDstType == SkShaderBase::ContextRec::kPM4f_DstType
- || SkToBool(flags & SkLinearGradient::kForce4fContext_PrivateFlag);
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
- : SkGradientShaderBase(desc, pts_to_unit_matrix(pts))
- , fStart(pts[0])
- , fEnd(pts[1]) {
-}
-
-sk_sp<SkFlattenable> SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
- DescriptorScope desc;
- if (!desc.unflatten(buffer)) {
- return nullptr;
- }
- SkPoint pts[2];
- pts[0] = buffer.readPoint();
- pts[1] = buffer.readPoint();
- return SkGradientShader::MakeLinear(pts, desc.fColors, std::move(desc.fColorSpace), desc.fPos,
- desc.fCount, desc.fTileMode, desc.fGradFlags,
- desc.fLocalMatrix);
-}
-
-void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- buffer.writePoint(fStart);
- buffer.writePoint(fEnd);
-}
-
-SkShaderBase::Context* SkLinearGradient::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const
-{
- return use_4f_context(rec, fGradFlags)
- ? CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec)
- : CheckedMakeContext< LinearGradientContext>(alloc, *this, rec);
-}
-
-bool SkLinearGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const {
- *matrix = SkMatrix::Concat(fPtsToUnit, *matrix);
- // If the gradient is less than a quarter of a pixel, this falls into the
- // subpixel gradient code handled on a different path.
- SkVector dx = matrix->mapVector(1, 0);
- if (dx.fX >= 4) {
- return false;
- }
- return true;
-}
-
-sk_sp<SkShader> SkLinearGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- SkPoint pts[2] = { fStart, fEnd };
- SkSTArray<8, SkColor> xformedColors(fColorCount);
- xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
- return SkGradientShader::MakeLinear(pts, xformedColors.begin(), fOrigPos, fColorCount,
- fTileMode, fGradFlags, &this->getLocalMatrix());
-}
-
-// This swizzles SkColor into the same component order as SkPMColor, but does not actually
-// "pre" multiply the color components.
-//
-// This allows us to map directly to Sk4f, and eventually scale down to bytes to output a
-// SkPMColor from the floats, without having to swizzle each time.
-//
-static uint32_t SkSwizzle_Color_to_PMColor(SkColor c) {
- return SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
-}
-
-SkLinearGradient::LinearGradientContext::LinearGradientContext(
- const SkLinearGradient& shader, const ContextRec& ctx)
- : INHERITED(shader, ctx)
-{
- // setup for Sk4f
- const int count = shader.fColorCount;
- SkASSERT(count > 1);
-
- fRecs.setCount(count);
- Rec* rec = fRecs.begin();
- if (shader.fOrigPos) {
- rec[0].fPos = 0;
- SkDEBUGCODE(rec[0].fPosScale = SK_FloatNaN;) // should never get used
- for (int i = 1; i < count; ++i) {
- rec[i].fPos = SkTPin(shader.fOrigPos[i], rec[i - 1].fPos, 1.0f);
- float diff = rec[i].fPos - rec[i - 1].fPos;
- if (diff > 0) {
- rec[i].fPosScale = 1.0f / diff;
- } else {
- rec[i].fPosScale = 0;
- }
- }
- } else {
- // no pos specified, so we compute evenly spaced values
- const float scale = float(count - 1);
- const float invScale = 1.0f / scale;
- for (int i = 0; i < count; ++i) {
- rec[i].fPos = i * invScale;
- rec[i].fPosScale = scale;
- }
- }
- rec[count - 1].fPos = 1; // overwrite the last value just to be sure we end at 1.0
-
- fApplyAlphaAfterInterp = true;
- if ((shader.getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag) ||
- shader.colorsAreOpaque())
- {
- fApplyAlphaAfterInterp = false;
- }
-
- if (fApplyAlphaAfterInterp) {
- // Our fColor values are in PMColor order, but are still unpremultiplied, allowing us to
- // interpolate in unpremultiplied space first, and then scale by alpha right before we
- // convert to SkPMColor bytes.
- const float paintAlpha = ctx.fPaint->getAlpha() * kInv255Float;
- const Sk4f scale(1, 1, 1, paintAlpha);
- for (int i = 0; i < count; ++i) {
- uint32_t c = SkSwizzle_Color_to_PMColor(shader.fOrigColors[i]);
- rec[i].fColor = SkNx_cast<float>(Sk4b::Load(&c)) * scale;
- if (i > 0) {
- SkASSERT(rec[i - 1].fPos <= rec[i].fPos);
- }
- }
- } else {
- // Our fColor values are premultiplied, so converting to SkPMColor is just a matter
- // of converting the floats down to bytes.
- unsigned alphaScale = ctx.fPaint->getAlpha() + (ctx.fPaint->getAlpha() >> 7);
- for (int i = 0; i < count; ++i) {
- SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]);
- pmc = SkAlphaMulQ(pmc, alphaScale);
- rec[i].fColor = SkNx_cast<float>(Sk4b::Load(&pmc));
- if (i > 0) {
- SkASSERT(rec[i - 1].fPos <= rec[i].fPos);
- }
- }
- }
-}
-
-#define NO_CHECK_ITER \
- do { \
- unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \
- SkASSERT(fi <= 0xFF); \
- fx += dx; \
- *dstC++ = cache[toggle + fi]; \
- toggle = next_dither_toggle(toggle); \
- } while (0)
-
-namespace {
-
-typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
- SkPMColor* dstC, const SkPMColor* cache,
- int toggle, int count);
-
-// Linear interpolation (lerp) is unnecessary if there are no sharp
-// discontinuities in the gradient - which must be true if there are
-// only 2 colors - but it's cheap.
-void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
- SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache,
- int toggle, int count) {
- // We're a vertical gradient, so no change in a span.
- // If colors change sharply across the gradient, dithering is
- // insufficient (it subsamples the color space) and we need to lerp.
- unsigned fullIndex = proc(SkGradFixedToFixed(fx));
- unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
- unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
-
- int index0 = fi + toggle;
- int index1 = index0;
- if (fi < SkGradientShaderBase::kCache32Count - 1) {
- index1 += 1;
- }
- SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
- index0 ^= SkGradientShaderBase::kDitherStride32;
- index1 ^= SkGradientShaderBase::kDitherStride32;
- SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
- sk_memset32_dither(dstC, lerp, dlerp, count);
-}
-
-void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
- SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache,
- int toggle, int count) {
- SkClampRange range;
- range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
- range.validate(count);
-
- if ((count = range.fCount0) > 0) {
- sk_memset32_dither(dstC,
- cache[toggle + range.fV0],
- cache[next_dither_toggle(toggle) + range.fV0],
- count);
- dstC += count;
- }
- if ((count = range.fCount1) > 0) {
- int unroll = count >> 3;
- fx = range.fFx1;
- for (int i = 0; i < unroll; i++) {
- NO_CHECK_ITER; NO_CHECK_ITER;
- NO_CHECK_ITER; NO_CHECK_ITER;
- NO_CHECK_ITER; NO_CHECK_ITER;
- NO_CHECK_ITER; NO_CHECK_ITER;
- }
- if ((count &= 7) > 0) {
- do {
- NO_CHECK_ITER;
- } while (--count != 0);
- }
- }
- if ((count = range.fCount2) > 0) {
- sk_memset32_dither(dstC,
- cache[toggle + range.fV1],
- cache[next_dither_toggle(toggle) + range.fV1],
- count);
- }
-}
-
-void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
- SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache,
- int toggle, int count) {
- do {
- unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8);
- SkASSERT(fi <= 0xFF);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle = next_dither_toggle(toggle);
- } while (--count != 0);
-}
-
-void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
- SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache,
- int toggle, int count) {
- do {
- unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8);
- SkASSERT(fi <= 0xFF);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle = next_dither_toggle(toggle);
- } while (--count != 0);
-}
-
-}
-
-void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
- int count) {
- SkASSERT(count > 0);
- const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader);
-
- if (SkShader::kClamp_TileMode == linearGradient.fTileMode &&
- kLinear_MatrixClass == fDstToIndexClass)
- {
- this->shade4_clamp(x, y, dstC, count);
- return;
- }
-
- SkPoint srcPt;
- SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = linearGradient.fTileProc;
- const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
- int toggle = init_dither_toggle(x, y);
-
- if (fDstToIndexClass != kPerspective_MatrixClass) {
- dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
- SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkGradFixed dx, fx = SkScalarPinToGradFixed(srcPt.fX);
-
- if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
- const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y));
- // todo: do we need a real/high-precision value for dx here?
- dx = SkScalarPinToGradFixed(step.fX);
- } else {
- SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarPinToGradFixed(fDstToIndex.getScaleX());
- }
-
- LinearShadeProc shadeProc = shadeSpan_linear_repeat;
- if (0 == dx) {
- shadeProc = shadeSpan_linear_vertical_lerp;
- } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
- shadeProc = shadeSpan_linear_clamp;
- } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) {
- shadeProc = shadeSpan_linear_mirror;
- } else {
- SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode);
- }
- (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
- } else {
- SkScalar dstX = SkIntToScalar(x);
- SkScalar dstY = SkIntToScalar(y);
- do {
- dstProc(fDstToIndex, dstX, dstY, &srcPt);
- unsigned fi = proc(SkScalarToFixed(srcPt.fX));
- SkASSERT(fi <= 0xFFFF);
- *dstC++ = cache[toggle + (fi >> kCache32Shift)];
- toggle = next_dither_toggle(toggle);
- dstX += SK_Scalar1;
- } while (--count != 0);
- }
-}
-
-SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
- if (info) {
- commonAsAGradient(info);
- info->fPoint[0] = fStart;
- info->fPoint[1] = fEnd;
- }
- return kLinear_GradientType;
-}
-
-#if SK_SUPPORT_GPU
-
-#include "GrColorSpaceXform.h"
-#include "GrShaderCaps.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "SkGr.h"
-
-/////////////////////////////////////////////////////////////////////
-
-class GrLinearGradient : public GrGradientEffect {
-public:
- class GLSLLinearProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
- return sk_sp<GrFragmentProcessor>(new GrLinearGradient(args));
- }
-
- ~GrLinearGradient() override {}
-
- const char* name() const override { return "Linear Gradient"; }
-
-private:
- GrLinearGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
- this->initClassID<GrLinearGradient>();
- }
-
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const override;
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- typedef GrGradientEffect INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////
-
-class GrLinearGradient::GLSLLinearProcessor : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLLinearProcessor(const GrProcessor&) {}
-
- ~GLSLLinearProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- b->add32(GenBaseGradientKey(processor));
- }
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////
-
-GrGLSLFragmentProcessor* GrLinearGradient::onCreateGLSLInstance() const {
- return new GrLinearGradient::GLSLLinearProcessor(*this);
-}
-
-void GrLinearGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- GrLinearGradient::GLSLLinearProcessor::GenKey(*this, caps, b);
-}
-
-/////////////////////////////////////////////////////////////////////
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradient);
-
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> GrLinearGradient::TestCreate(GrProcessorTestData* d) {
- SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()},
- {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}};
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-/////////////////////////////////////////////////////////////////////
-
-void GrLinearGradient::GLSLLinearProcessor::emitCode(EmitArgs& args) {
- const GrLinearGradient& ge = args.fFp.cast<GrLinearGradient>();
- this->emitUniforms(args.fUniformHandler, ge);
- SkString t = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
- t.append(".x");
- this->emitColor(args.fFragBuilder,
- args.fUniformHandler,
- args.fShaderCaps,
- ge,
- t.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
-}
-
-/////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor(const AsFPArgs& args) const {
- SkASSERT(args.fContext);
-
- SkMatrix matrix;
- if (!this->getLocalMatrix().invert(&matrix)) {
- return nullptr;
- }
- if (args.fLocalMatrix) {
- SkMatrix inv;
- if (!args.fLocalMatrix->invert(&inv)) {
- return nullptr;
- }
- matrix.postConcat(inv);
- }
- matrix.postConcat(fPtsToUnit);
-
- sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
- args.fDstColorSpace);
- sk_sp<GrFragmentProcessor> inner(GrLinearGradient::Make(
- GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
- std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
-}
-
-
-#endif
-
-#ifndef SK_IGNORE_TO_STRING
-void SkLinearGradient::toString(SkString* str) const {
- str->append("SkLinearGradient (");
-
- str->appendf("start: (%f, %f)", fStart.fX, fStart.fY);
- str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY);
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#include "SkNx.h"
-
-static const SkLinearGradient::LinearGradientContext::Rec*
-find_forward(const SkLinearGradient::LinearGradientContext::Rec rec[], float tiledX) {
- SkASSERT(tiledX >= 0 && tiledX <= 1);
-
- SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
- SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
- SkASSERT(rec[0].fPos <= rec[1].fPos);
- rec += 1;
- while (rec->fPos < tiledX || rec->fPosScale == 0) {
- SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
- SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
- SkASSERT(rec[0].fPos <= rec[1].fPos);
- rec += 1;
- }
- return rec - 1;
-}
-
-static const SkLinearGradient::LinearGradientContext::Rec*
-find_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float tiledX) {
- SkASSERT(tiledX >= 0 && tiledX <= 1);
-
- SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
- SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
- SkASSERT(rec[0].fPos <= rec[1].fPos);
- while (tiledX < rec->fPos || rec[1].fPosScale == 0) {
- rec -= 1;
- SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
- SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
- SkASSERT(rec[0].fPos <= rec[1].fPos);
- }
- return rec;
-}
-
-// As an optimization, we can apply the dither bias before interpolation -- but only when
-// operating in premul space (apply_alpha == false). When apply_alpha == true, we must
-// defer the bias application until after premul.
-//
-// The following two helpers encapsulate this logic: pre_bias is called before interpolation,
-// and effects the bias when apply_alpha == false, while post_bias is called after premul and
-// effects the bias for the apply_alpha == true case.
-
-template <bool apply_alpha>
-Sk4f pre_bias(const Sk4f& x, const Sk4f& bias) {
- return apply_alpha ? x : x + bias;
-}
-
-template <bool apply_alpha>
-Sk4f post_bias(const Sk4f& x, const Sk4f& bias) {
- return apply_alpha ? x + bias : x;
-}
-
-template <bool apply_alpha> SkPMColor trunc_from_255(const Sk4f& x, const Sk4f& bias) {
- SkPMColor c;
- Sk4f c4f255 = x;
- if (apply_alpha) {
- const float scale = x[SkPM4f::A] * (1 / 255.f);
- c4f255 *= Sk4f(scale, scale, scale, 1);
- }
- SkNx_cast<uint8_t>(post_bias<apply_alpha>(c4f255, bias)).store(&c);
-
- return c;
-}
-
-template <bool apply_alpha> void fill(SkPMColor dst[], int count,
- const Sk4f& c4, const Sk4f& bias0, const Sk4f& bias1) {
- const SkPMColor c0 = trunc_from_255<apply_alpha>(pre_bias<apply_alpha>(c4, bias0), bias0);
- const SkPMColor c1 = trunc_from_255<apply_alpha>(pre_bias<apply_alpha>(c4, bias1), bias1);
- sk_memset32_dither(dst, c0, c1, count);
-}
-
-template <bool apply_alpha> void fill(SkPMColor dst[], int count, const Sk4f& c4) {
- // Assumes that c4 does not need to be dithered.
- sk_memset32(dst, trunc_from_255<apply_alpha>(c4, 0), count);
-}
-
-/*
- * TODOs
- *
- * - tilemodes
- * - interp before or after premul
- * - perspective
- * - optimizations
- * - use fixed (32bit or 16bit) instead of floats?
- */
-
-static Sk4f lerp_color(float fx, const SkLinearGradient::LinearGradientContext::Rec* rec) {
- SkASSERT(fx >= rec[0].fPos);
- SkASSERT(fx <= rec[1].fPos);
-
- const float p0 = rec[0].fPos;
- const Sk4f c0 = rec[0].fColor;
- const Sk4f c1 = rec[1].fColor;
- const Sk4f diffc = c1 - c0;
- const float scale = rec[1].fPosScale;
- const float t = (fx - p0) * scale;
- return c0 + Sk4f(t) * diffc;
-}
-
-template <bool apply_alpha> void ramp(SkPMColor dstC[], int n, const Sk4f& c, const Sk4f& dc,
- const Sk4f& dither0, const Sk4f& dither1) {
- Sk4f dc2 = dc + dc;
- Sk4f dc4 = dc2 + dc2;
- Sk4f cd0 = pre_bias<apply_alpha>(c , dither0);
- Sk4f cd1 = pre_bias<apply_alpha>(c + dc, dither1);
- Sk4f cd2 = cd0 + dc2;
- Sk4f cd3 = cd1 + dc2;
- while (n >= 4) {
- if (!apply_alpha) {
- Sk4f_ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3);
- dstC += 4;
- } else {
- *dstC++ = trunc_from_255<apply_alpha>(cd0, dither0);
- *dstC++ = trunc_from_255<apply_alpha>(cd1, dither1);
- *dstC++ = trunc_from_255<apply_alpha>(cd2, dither0);
- *dstC++ = trunc_from_255<apply_alpha>(cd3, dither1);
- }
- cd0 = cd0 + dc4;
- cd1 = cd1 + dc4;
- cd2 = cd2 + dc4;
- cd3 = cd3 + dc4;
- n -= 4;
- }
- if (n & 2) {
- *dstC++ = trunc_from_255<apply_alpha>(cd0, dither0);
- *dstC++ = trunc_from_255<apply_alpha>(cd1, dither1);
- cd0 = cd0 + dc2;
- }
- if (n & 1) {
- *dstC++ = trunc_from_255<apply_alpha>(cd0, dither0);
- }
-}
-
-template <bool apply_alpha, bool dx_is_pos>
-void SkLinearGradient::LinearGradientContext::shade4_dx_clamp(SkPMColor dstC[], int count,
- float fx, float dx, float invDx,
- const float dither[2]) {
- Sk4f dither0(dither[0]);
- Sk4f dither1(dither[1]);
- const Rec* rec = fRecs.begin();
-
- const Sk4f dx4 = Sk4f(dx);
- SkDEBUGCODE(SkPMColor* endDstC = dstC + count;)
-
- if (dx_is_pos) {
- if (fx < 0) {
- // count is guaranteed to be positive, but the first arg may overflow int32 after
- // increment => casting to uint32 ensures correct clamping.
- int n = SkTMin<uint32_t>(static_cast<uint32_t>(SkFloatToIntFloor(-fx * invDx)) + 1,
- count);
- SkASSERT(n > 0);
- fill<apply_alpha>(dstC, n, rec[0].fColor);
- count -= n;
- dstC += n;
- fx += n * dx;
- SkASSERT(0 == count || fx >= 0);
- if (n & 1) {
- SkTSwap(dither0, dither1);
- }
- }
- } else { // dx < 0
- if (fx > 1) {
- // count is guaranteed to be positive, but the first arg may overflow int32 after
- // increment => casting to uint32 ensures correct clamping.
- int n = SkTMin<uint32_t>(static_cast<uint32_t>(SkFloatToIntFloor((1 - fx) * invDx)) + 1,
- count);
- SkASSERT(n > 0);
- fill<apply_alpha>(dstC, n, rec[fRecs.count() - 1].fColor);
- count -= n;
- dstC += n;
- fx += n * dx;
- SkASSERT(0 == count || fx <= 1);
- if (n & 1) {
- SkTSwap(dither0, dither1);
- }
- }
- }
- SkASSERT(count >= 0);
-
- const Rec* r;
- if (dx_is_pos) {
- r = fRecs.begin(); // start at the beginning
- } else {
- r = fRecs.begin() + fRecs.count() - 2; // start at the end
- }
-
- while (count > 0) {
- if (dx_is_pos) {
- if (fx >= 1) {
- fill<apply_alpha>(dstC, count, rec[fRecs.count() - 1].fColor);
- return;
- }
- } else { // dx < 0
- if (fx <= 0) {
- fill<apply_alpha>(dstC, count, rec[0].fColor);
- return;
- }
- }
-
- if (dx_is_pos) {
- r = find_forward(r, fx);
- } else {
- r = find_backward(r, fx);
- }
- SkASSERT(r >= fRecs.begin() && r < fRecs.begin() + fRecs.count() - 1);
-
- const float p0 = r[0].fPos;
- const Sk4f c0 = r[0].fColor;
- const float p1 = r[1].fPos;
- const Sk4f diffc = Sk4f(r[1].fColor) - c0;
- const float scale = r[1].fPosScale;
- const float t = (fx - p0) * scale;
- const Sk4f c = c0 + Sk4f(t) * diffc;
- const Sk4f dc = diffc * dx4 * Sk4f(scale);
-
- int n;
- if (dx_is_pos) {
- n = SkTMin((int)((p1 - fx) * invDx) + 1, count);
- } else {
- n = SkTMin((int)((p0 - fx) * invDx) + 1, count);
- }
-
- fx += n * dx;
- // fx should now outside of the p0..p1 interval. However, due to float precision loss,
- // its possible that fx is slightly too small/large, so we clamp it.
- if (dx_is_pos) {
- fx = SkTMax(fx, p1);
- } else {
- fx = SkTMin(fx, p0);
- }
-
- ramp<apply_alpha>(dstC, n, c, dc, dither0, dither1);
- dstC += n;
- SkASSERT(dstC <= endDstC);
-
- if (n & 1) {
- SkTSwap(dither0, dither1);
- }
-
- count -= n;
- SkASSERT(count >= 0);
- }
-}
-
-void SkLinearGradient::LinearGradientContext::shade4_clamp(int x, int y, SkPMColor dstC[],
- int count) {
- SkASSERT(count > 0);
- SkASSERT(kLinear_MatrixClass == fDstToIndexClass);
-
- SkPoint srcPt;
- fDstToIndexProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt);
- float fx = srcPt.x();
- const float dx = fDstToIndex.getScaleX();
-
- // Default our dither bias values to 1/2, (rounding), which is no dithering
- float dither0 = 0.5f;
- float dither1 = 0.5f;
- if (fDither) {
- const float ditherCell[] = {
- 1/8.0f, 5/8.0f,
- 7/8.0f, 3/8.0f,
- };
- const int rowIndex = (y & 1) << 1;
- dither0 = ditherCell[rowIndex];
- dither1 = ditherCell[rowIndex + 1];
- if (x & 1) {
- SkTSwap(dither0, dither1);
- }
- }
- const float dither[2] = { dither0, dither1 };
-
- if (SkScalarNearlyZero(dx * count)) { // gradient is vertical
- const float pinFx = SkTPin(fx, 0.0f, 1.0f);
- Sk4f c = lerp_color(pinFx, find_forward(fRecs.begin(), pinFx));
- if (fApplyAlphaAfterInterp) {
- fill<true>(dstC, count, c, dither0, dither1);
- } else {
- fill<false>(dstC, count, c, dither0, dither1);
- }
- return;
- }
-
- SkASSERT(0.f != dx);
- const float invDx = 1 / dx;
- if (dx > 0) {
- if (fApplyAlphaAfterInterp) {
- this->shade4_dx_clamp<true, true>(dstC, count, fx, dx, invDx, dither);
- } else {
- this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dither);
- }
- } else {
- if (fApplyAlphaAfterInterp) {
- this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dither);
- } else {
- this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dither);
- }
- }
-}
diff --git a/src/shaders/gradients/SkLinearGradient.h b/src/shaders/gradients/SkLinearGradient.h
deleted file mode 100644
index 19a965c7bb..0000000000
--- a/src/shaders/gradients/SkLinearGradient.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkLinearGradient_DEFINED
-#define SkLinearGradient_DEFINED
-
-#include "SkGradientShaderPriv.h"
-#include "SkNx.h"
-
-struct Sk4fStorage {
- float fArray[4];
-
- operator Sk4f() const {
- return Sk4f::Load(fArray);
- }
-
- Sk4fStorage& operator=(const Sk4f& src) {
- src.store(fArray);
- return *this;
- }
-};
-
-class SkLinearGradient : public SkGradientShaderBase {
-public:
- enum {
- // Temp flag for testing the 4f impl.
- kForce4fContext_PrivateFlag = 1 << 7,
- };
-
- SkLinearGradient(const SkPoint pts[2], const Descriptor&);
-
- class LinearGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
- public:
- LinearGradientContext(const SkLinearGradient&, const ContextRec&);
-
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
-
- struct Rec {
- Sk4fStorage fColor;
- float fPos;
- float fPosScale;
- };
- private:
- SkTDArray<Rec> fRecs;
- bool fApplyAlphaAfterInterp;
-
- void shade4_clamp(int x, int y, SkPMColor dstC[], int count);
- template <bool, bool> void shade4_dx_clamp(SkPMColor dstC[], int count, float fx, float dx,
- float invDx, const float dither[2]);
-
- typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
- };
-
- GradientType asAGradient(GradientInfo* info) const override;
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLinearGradient)
-
-protected:
- SkLinearGradient(SkReadBuffer& buffer);
- void flatten(SkWriteBuffer& buffer) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
-
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const final;
-
-
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
-private:
- class LinearGradient4fContext;
-
- friend class SkGradientShader;
- typedef SkGradientShaderBase INHERITED;
- const SkPoint fStart;
- const SkPoint fEnd;
-};
-
-#endif
diff --git a/src/shaders/gradients/SkRadialGradient.cpp b/src/shaders/gradients/SkRadialGradient.cpp
deleted file mode 100644
index d49b3dd8e1..0000000000
--- a/src/shaders/gradients/SkRadialGradient.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkColorSpaceXformer.h"
-#include "SkRadialGradient.h"
-#include "SkNx.h"
-
-namespace {
-
-// GCC doesn't like using static functions as template arguments. So force these to be non-static.
-inline SkFixed mirror_tileproc_nonstatic(SkFixed x) {
- return mirror_tileproc(x);
-}
-
-inline SkFixed repeat_tileproc_nonstatic(SkFixed x) {
- return repeat_tileproc(x);
-}
-
-SkMatrix rad_to_unit_matrix(const SkPoint& center, SkScalar radius) {
- SkScalar inv = SkScalarInvert(radius);
-
- SkMatrix matrix;
- matrix.setTranslate(-center.fX, -center.fY);
- matrix.postScale(inv, inv);
- return matrix;
-}
-
-
-} // namespace
-
-/////////////////////////////////////////////////////////////////////
-
-SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc)
- : SkGradientShaderBase(desc, rad_to_unit_matrix(center, radius))
- , fCenter(center)
- , fRadius(radius) {
-}
-
-SkShaderBase::Context* SkRadialGradient::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const
-{
- return CheckedMakeContext<RadialGradientContext>(alloc, *this, rec);
-}
-
-SkRadialGradient::RadialGradientContext::RadialGradientContext(
- const SkRadialGradient& shader, const ContextRec& rec)
- : INHERITED(shader, rec) {}
-
-SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const {
- if (info) {
- commonAsAGradient(info);
- info->fPoint[0] = fCenter;
- info->fRadius[0] = fRadius;
- }
- return kRadial_GradientType;
-}
-
-sk_sp<SkFlattenable> SkRadialGradient::CreateProc(SkReadBuffer& buffer) {
- DescriptorScope desc;
- if (!desc.unflatten(buffer)) {
- return nullptr;
- }
- const SkPoint center = buffer.readPoint();
- const SkScalar radius = buffer.readScalar();
- return SkGradientShader::MakeRadial(center, radius, desc.fColors, std::move(desc.fColorSpace),
- desc.fPos, desc.fCount, desc.fTileMode, desc.fGradFlags,
- desc.fLocalMatrix);
-}
-
-void SkRadialGradient::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- buffer.writePoint(fCenter);
- buffer.writeScalar(fRadius);
-}
-
-namespace {
-
-inline bool radial_completely_pinned(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy) {
- // fast, overly-conservative test: checks unit square instead of unit circle
- bool xClamped = (fx >= 1 && dx >= 0) || (fx <= -1 && dx <= 0);
- bool yClamped = (fy >= 1 && dy >= 0) || (fy <= -1 && dy <= 0);
- return xClamped || yClamped;
-}
-
-typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
- SkScalar sfy, SkScalar sdy,
- SkPMColor* dstC, const SkPMColor* cache,
- int count, int toggle);
-
-static inline Sk4f fast_sqrt(const Sk4f& R) {
- return R * R.rsqrt();
-}
-
-static inline Sk4f sum_squares(const Sk4f& a, const Sk4f& b) {
- return a * a + b * b;
-}
-
-void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar sdy,
- SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
- int count, int toggle) {
- if (radial_completely_pinned(sfx, sdx, sfy, sdy)) {
- unsigned fi = SkGradientShaderBase::kCache32Count - 1;
- sk_memset32_dither(dstC,
- cache[toggle + fi],
- cache[next_dither_toggle(toggle) + fi],
- count);
- } else {
- const Sk4f min(SK_ScalarNearlyZero);
- const Sk4f max(255);
- const float scale = 255;
- sfx *= scale;
- sfy *= scale;
- sdx *= scale;
- sdy *= scale;
- const Sk4f fx4(sfx, sfx + sdx, sfx + 2*sdx, sfx + 3*sdx);
- const Sk4f fy4(sfy, sfy + sdy, sfy + 2*sdy, sfy + 3*sdy);
- const Sk4f dx4(sdx * 4);
- const Sk4f dy4(sdy * 4);
-
- Sk4f tmpxy = fx4 * dx4 + fy4 * dy4;
- Sk4f tmpdxdy = sum_squares(dx4, dy4);
- Sk4f R = Sk4f::Max(sum_squares(fx4, fy4), min);
- Sk4f dR = tmpxy + tmpxy + tmpdxdy;
- const Sk4f ddR = tmpdxdy + tmpdxdy;
-
- for (int i = 0; i < (count >> 2); ++i) {
- Sk4f dist = Sk4f::Min(fast_sqrt(R), max);
- R = Sk4f::Max(R + dR, min);
- dR = dR + ddR;
-
- uint8_t fi[4];
- SkNx_cast<uint8_t>(dist).store(fi);
-
- for (int i = 0; i < 4; i++) {
- *dstC++ = cache[toggle + fi[i]];
- toggle = next_dither_toggle(toggle);
- }
- }
- count &= 3;
- if (count) {
- Sk4f dist = Sk4f::Min(fast_sqrt(R), max);
-
- uint8_t fi[4];
- SkNx_cast<uint8_t>(dist).store(fi);
- for (int i = 0; i < count; i++) {
- *dstC++ = cache[toggle + fi[i]];
- toggle = next_dither_toggle(toggle);
- }
- }
- }
-}
-
-// Unrolling this loop doesn't seem to help (when float); we're stalling to
-// get the results of the sqrt (?), and don't have enough extra registers to
-// have many in flight.
-template <SkFixed (*TileProc)(SkFixed)>
-void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
- SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
- int count, int toggle) {
- do {
- const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy));
- const unsigned fi = TileProc(dist);
- SkASSERT(fi <= 0xFFFF);
- *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)];
- toggle = next_dither_toggle(toggle);
- fx += dx;
- fy += dy;
- } while (--count != 0);
-}
-
-void shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
- SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
- int count, int toggle) {
- shadeSpan_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
-}
-
-void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
- SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
- int count, int toggle) {
- shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
-}
-
-} // namespace
-
-void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y,
- SkPMColor* SK_RESTRICT dstC, int count) {
- SkASSERT(count > 0);
-
- const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
-
- SkPoint srcPt;
- SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = radialGradient.fTileProc;
- const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
- int toggle = init_dither_toggle(x, y);
-
- if (fDstToIndexClass != kPerspective_MatrixClass) {
- dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
- SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkScalar sdx = fDstToIndex.getScaleX();
- SkScalar sdy = fDstToIndex.getSkewY();
-
- if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
- const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y));
- sdx = step.fX;
- sdy = step.fY;
- } else {
- SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- }
-
- RadialShadeProc shadeProc = shadeSpan_radial_repeat;
- if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
- shadeProc = shadeSpan_radial_clamp2;
- } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
- shadeProc = shadeSpan_radial_mirror;
- } else {
- SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
- }
- (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
- } else { // perspective case
- SkScalar dstX = SkIntToScalar(x);
- SkScalar dstY = SkIntToScalar(y);
- do {
- dstProc(fDstToIndex, dstX, dstY, &srcPt);
- unsigned fi = proc(SkScalarToFixed(srcPt.length()));
- SkASSERT(fi <= 0xFFFF);
- *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift];
- dstX += SK_Scalar1;
- } while (--count != 0);
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "SkGr.h"
-#include "GrShaderCaps.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-
-class GrRadialGradient : public GrGradientEffect {
-public:
- class GLSLRadialProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
- return sk_sp<GrFragmentProcessor>(new GrRadialGradient(args));
- }
-
- ~GrRadialGradient() override {}
-
- const char* name() const override { return "Radial Gradient"; }
-
-private:
- GrRadialGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
- this->initClassID<GrRadialGradient>();
- }
-
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const override;
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- typedef GrGradientEffect INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////
-
-class GrRadialGradient::GLSLRadialProcessor : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLRadialProcessor(const GrProcessor&) {}
- ~GLSLRadialProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- b->add32(GenBaseGradientKey(processor));
- }
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-/////////////////////////////////////////////////////////////////////
-
-GrGLSLFragmentProcessor* GrRadialGradient::onCreateGLSLInstance() const {
- return new GrRadialGradient::GLSLRadialProcessor(*this);
-}
-
-void GrRadialGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- GrRadialGradient::GLSLRadialProcessor::GenKey(*this, caps, b);
-}
-
-/////////////////////////////////////////////////////////////////////
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadialGradient);
-
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> GrRadialGradient::TestCreate(GrProcessorTestData* d) {
- sk_sp<SkShader> shader;
- do {
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-/////////////////////////////////////////////////////////////////////
-
-void GrRadialGradient::GLSLRadialProcessor::emitCode(EmitArgs& args) {
- const GrRadialGradient& ge = args.fFp.cast<GrRadialGradient>();
- this->emitUniforms(args.fUniformHandler, ge);
- SkString t("length(");
- t.append(args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]));
- t.append(")");
- this->emitColor(args.fFragBuilder,
- args.fUniformHandler,
- args.fShaderCaps,
- ge, t.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
-}
-
-/////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> SkRadialGradient::asFragmentProcessor(const AsFPArgs& args) const {
- SkASSERT(args.fContext);
-
- SkMatrix matrix;
- if (!this->getLocalMatrix().invert(&matrix)) {
- return nullptr;
- }
- if (args.fLocalMatrix) {
- SkMatrix inv;
- if (!args.fLocalMatrix->invert(&inv)) {
- return nullptr;
- }
- matrix.postConcat(inv);
- }
- matrix.postConcat(fPtsToUnit);
- sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
- args.fDstColorSpace);
- sk_sp<GrFragmentProcessor> inner(GrRadialGradient::Make(
- GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
- std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
-}
-
-#endif
-
-sk_sp<SkShader> SkRadialGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- SkSTArray<8, SkColor> xformedColors(fColorCount);
- xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
- return SkGradientShader::MakeRadial(fCenter, fRadius, xformedColors.begin(), fOrigPos,
- fColorCount, fTileMode, fGradFlags,
- &this->getLocalMatrix());
-}
-
-bool SkRadialGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const {
- matrix->postTranslate(-fCenter.fX, -fCenter.fY);
- matrix->postScale(1/fRadius, 1/fRadius);
-
- p->append(SkRasterPipeline::xy_to_radius);
- return true;
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkRadialGradient::toString(SkString* str) const {
- str->append("SkRadialGradient: (");
-
- str->append("center: (");
- str->appendScalar(fCenter.fX);
- str->append(", ");
- str->appendScalar(fCenter.fY);
- str->append(") radius: ");
- str->appendScalar(fRadius);
- str->append(" ");
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
diff --git a/src/shaders/gradients/SkRadialGradient.h b/src/shaders/gradients/SkRadialGradient.h
deleted file mode 100644
index 69ec4b1285..0000000000
--- a/src/shaders/gradients/SkRadialGradient.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkRadialGradient_DEFINED
-#define SkRadialGradient_DEFINED
-
-#include "SkGradientShaderPriv.h"
-
-class SkRadialGradient : public SkGradientShaderBase {
-public:
- SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor&);
-
- class RadialGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
- public:
- RadialGradientContext(const SkRadialGradient&, const ContextRec&);
-
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
-
- private:
- typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
- };
-
- GradientType asAGradient(GradientInfo* info) const override;
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRadialGradient)
-
-protected:
- SkRadialGradient(SkReadBuffer& buffer);
- void flatten(SkWriteBuffer& buffer) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const final;
-
-private:
- const SkPoint fCenter;
- const SkScalar fRadius;
-
- friend class SkGradientShader;
- typedef SkGradientShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/gradients/SkSweepGradient.cpp b/src/shaders/gradients/SkSweepGradient.cpp
deleted file mode 100644
index a138a8e213..0000000000
--- a/src/shaders/gradients/SkSweepGradient.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkColorSpaceXformer.h"
-#include "SkSweepGradient.h"
-
-#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))
-{
- // overwrite the tilemode to a canonical value (since sweep ignores it)
- fTileMode = SkShader::kClamp_TileMode;
-}
-
-SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
- if (info) {
- commonAsAGradient(info);
- info->fPoint[0] = fCenter;
- }
- return kSweep_GradientType;
-}
-
-sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
- DescriptorScope desc;
- if (!desc.unflatten(buffer)) {
- return nullptr;
- }
- const SkPoint center = buffer.readPoint();
- return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
- std::move(desc.fColorSpace), desc.fPos, desc.fCount,
- desc.fGradFlags, desc.fLocalMatrix);
-}
-
-void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- buffer.writePoint(fCenter);
-}
-
-/////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "SkGr.h"
-#include "GrShaderCaps.h"
-#include "gl/GrGLContext.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-
-class GrSweepGradient : public GrGradientEffect {
-public:
- class GLSLSweepProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
- return sk_sp<GrFragmentProcessor>(new GrSweepGradient(args));
- }
- ~GrSweepGradient() override {}
-
- const char* name() const override { return "Sweep Gradient"; }
-
-private:
- GrSweepGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) {
- this->initClassID<GrSweepGradient>();
- }
-
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const override;
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- typedef GrGradientEffect INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////
-
-class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLSweepProcessor(const GrProcessor&) {}
- ~GLSLSweepProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- b->add32(GenBaseGradientKey(processor));
- }
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-/////////////////////////////////////////////////////////////////////
-
-GrGLSLFragmentProcessor* GrSweepGradient::onCreateGLSLInstance() const {
- return new GrSweepGradient::GLSLSweepProcessor(*this);
-}
-
-void GrSweepGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- GrSweepGradient::GLSLSweepProcessor::GenKey(*this, caps, b);
-}
-
-
-/////////////////////////////////////////////////////////////////////
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient);
-
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> GrSweepGradient::TestCreate(GrProcessorTestData* d) {
- SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-/////////////////////////////////////////////////////////////////////
-
-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;
- // 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());
- }
- this->emitColor(args.fFragBuilder,
- args.fUniformHandler,
- args.fShaderCaps,
- ge, t.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
-}
-
-/////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs& args) const {
-
- SkMatrix matrix;
- if (!this->getLocalMatrix().invert(&matrix)) {
- return nullptr;
- }
- if (args.fLocalMatrix) {
- SkMatrix inv;
- if (!args.fLocalMatrix->invert(&inv)) {
- return nullptr;
- }
- matrix.postConcat(inv);
- }
- matrix.postConcat(fPtsToUnit);
-
- 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))));
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
-}
-
-#endif
-
-sk_sp<SkShader> SkSweepGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- SkSTArray<8, SkColor> xformedColors(fColorCount);
- xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
- return SkGradientShader::MakeSweep(fCenter.fX, fCenter.fY, xformedColors.begin(), fOrigPos,
- fColorCount, fGradFlags, &this->getLocalMatrix());
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkSweepGradient::toString(SkString* str) const {
- str->append("SkSweepGradient: (");
-
- str->append("center: (");
- str->appendScalar(fCenter.fX);
- str->append(", ");
- str->appendScalar(fCenter.fY);
- str->append(") ");
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-
-bool SkSweepGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const {
- matrix->postTranslate(-fCenter.fX, -fCenter.fY);
- p->append(SkRasterPipeline::xy_to_unit_angle);
-
- return true;
-}
-
-#endif
diff --git a/src/shaders/gradients/SkSweepGradient.h b/src/shaders/gradients/SkSweepGradient.h
deleted file mode 100644
index c30ca4d916..0000000000
--- a/src/shaders/gradients/SkSweepGradient.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkSweepGradient_DEFINED
-#define SkSweepGradient_DEFINED
-
-#include "SkGradientShaderPriv.h"
-
-class SkSweepGradient final : public SkGradientShaderBase {
-public:
- SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&);
-
- GradientType asAGradient(GradientInfo* info) const override;
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSweepGradient)
-
-protected:
- void flatten(SkWriteBuffer& buffer) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
- bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
- SkMatrix* matrix,
- SkRasterPipeline* p) const override;
-
- bool isRasterPipelineOnly() const override { return true; }
-
-private:
- const SkPoint fCenter;
-
- friend class SkGradientShader;
- typedef SkGradientShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/gradients/SkTwoPointConicalGradient.cpp b/src/shaders/gradients/SkTwoPointConicalGradient.cpp
deleted file mode 100644
index 4549527d51..0000000000
--- a/src/shaders/gradients/SkTwoPointConicalGradient.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkTwoPointConicalGradient.h"
-
-struct TwoPtRadialContext {
- const TwoPtRadial& fRec;
- float fRelX, fRelY;
- const float fIncX, fIncY;
- float fB;
- const float fDB;
-
- TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
- SkScalar dfx, SkScalar dfy);
- SkFixed nextT();
-};
-
-static int valid_divide(float numer, float denom, float* ratio) {
- SkASSERT(ratio);
- if (0 == denom) {
- return 0;
- }
- *ratio = numer / denom;
- return 1;
-}
-
-// Return the number of distinct real roots, and write them into roots[] in
-// ascending order
-static int find_quad_roots(float A, float B, float C, float roots[2], bool descendingOrder = false) {
- SkASSERT(roots);
-
- if (A == 0) {
- return valid_divide(-C, B, roots);
- }
-
- float R = B*B - 4*A*C;
- if (R < 0) {
- return 0;
- }
- R = sk_float_sqrt(R);
-
-#if 1
- float Q = B;
- if (Q < 0) {
- Q -= R;
- } else {
- Q += R;
- }
-#else
- // on 10.6 this was much slower than the above branch :(
- float Q = B + copysignf(R, B);
-#endif
- Q *= -0.5f;
- if (0 == Q) {
- roots[0] = 0;
- return 1;
- }
-
- float r0 = Q / A;
- float r1 = C / Q;
- roots[0] = r0 < r1 ? r0 : r1;
- roots[1] = r0 > r1 ? r0 : r1;
- if (descendingOrder) {
- SkTSwap(roots[0], roots[1]);
- }
- return 2;
-}
-
-static float lerp(float x, float dx, float t) {
- return x + t * dx;
-}
-
-static float sqr(float x) { return x * x; }
-
-void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
- const SkPoint& center1, SkScalar rad1,
- bool flipped) {
- fCenterX = SkScalarToFloat(center0.fX);
- fCenterY = SkScalarToFloat(center0.fY);
- fDCenterX = SkScalarToFloat(center1.fX) - fCenterX;
- fDCenterY = SkScalarToFloat(center1.fY) - fCenterY;
- fRadius = SkScalarToFloat(rad0);
- fDRadius = SkScalarToFloat(rad1) - fRadius;
-
- fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius);
- fRadius2 = sqr(fRadius);
- fRDR = fRadius * fDRadius;
-
- fFlipped = flipped;
-}
-
-TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy,
- SkScalar dfx, SkScalar dfy)
- : fRec(rec)
- , fRelX(SkScalarToFloat(fx) - rec.fCenterX)
- , fRelY(SkScalarToFloat(fy) - rec.fCenterY)
- , fIncX(SkScalarToFloat(dfx))
- , fIncY(SkScalarToFloat(dfy))
- , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR))
- , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {}
-
-SkFixed TwoPtRadialContext::nextT() {
- float roots[2];
-
- float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2;
- int countRoots = find_quad_roots(fRec.fA, fB, C, roots, fRec.fFlipped);
-
- fRelX += fIncX;
- fRelY += fIncY;
- fB += fDB;
-
- if (0 == countRoots) {
- return TwoPtRadial::kDontDrawT;
- }
-
- // Prefer the bigger t value if both give a radius(t) > 0
- // find_quad_roots returns the values sorted, so we start with the last
- float t = roots[countRoots - 1];
- float r = lerp(fRec.fRadius, fRec.fDRadius, t);
- if (r < 0) {
- t = roots[0]; // might be the same as roots[countRoots-1]
- r = lerp(fRec.fRadius, fRec.fDRadius, t);
- if (r < 0) {
- return TwoPtRadial::kDontDrawT;
- }
- }
- return SkFloatToFixed(t);
-}
-
-typedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC,
- const SkPMColor* cache, int toggle, int count);
-
-static void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache, int toggle,
- int count) {
- for (; count > 0; --count) {
- SkFixed t = rec->nextT();
- if (TwoPtRadial::DontDrawT(t)) {
- *dstC++ = 0;
- } else {
- SkFixed index = SkClampMax(t, 0xFFFF);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[toggle +
- (index >> SkGradientShaderBase::kCache32Shift)];
- }
- toggle = next_dither_toggle(toggle);
- }
-}
-
-static void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache, int toggle,
- int count) {
- for (; count > 0; --count) {
- SkFixed t = rec->nextT();
- if (TwoPtRadial::DontDrawT(t)) {
- *dstC++ = 0;
- } else {
- SkFixed index = repeat_tileproc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[toggle +
- (index >> SkGradientShaderBase::kCache32Shift)];
- }
- toggle = next_dither_toggle(toggle);
- }
-}
-
-static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache, int toggle,
- int count) {
- for (; count > 0; --count) {
- SkFixed t = rec->nextT();
- if (TwoPtRadial::DontDrawT(t)) {
- *dstC++ = 0;
- } else {
- SkFixed index = mirror_tileproc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[toggle +
- (index >> SkGradientShaderBase::kCache32Shift)];
- }
- toggle = next_dither_toggle(toggle);
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-
-SkTwoPointConicalGradient::SkTwoPointConicalGradient(
- const SkPoint& start, SkScalar startRadius,
- const SkPoint& end, SkScalar endRadius,
- bool flippedGrad, const Descriptor& desc)
- : SkGradientShaderBase(desc, SkMatrix::I())
- , fCenter1(start)
- , fCenter2(end)
- , fRadius1(startRadius)
- , fRadius2(endRadius)
- , fFlippedGrad(flippedGrad)
-{
- // this is degenerate, and should be caught by our caller
- SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
- fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
-}
-
-bool SkTwoPointConicalGradient::isOpaque() const {
- // Because areas outside the cone are left untouched, we cannot treat the
- // shader as opaque even if the gradient itself is opaque.
- // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
- return false;
-}
-
-SkShaderBase::Context* SkTwoPointConicalGradient::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const {
- return CheckedMakeContext<TwoPointConicalGradientContext>(alloc, *this, rec);
-}
-
-SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext(
- const SkTwoPointConicalGradient& shader, const ContextRec& rec)
- : INHERITED(shader, rec)
-{
- // in general, we might discard based on computed-radius, so clear
- // this flag (todo: sometimes we can detect that we never discard...)
- fFlags &= ~kOpaqueAlpha_Flag;
-}
-
-void SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan(
- int x, int y, SkPMColor* dstCParam, int count) {
- const SkTwoPointConicalGradient& twoPointConicalGradient =
- static_cast<const SkTwoPointConicalGradient&>(fShader);
-
- int toggle = init_dither_toggle(x, y);
-
- SkASSERT(count > 0);
-
- SkPMColor* SK_RESTRICT dstC = dstCParam;
-
- SkMatrix::MapXYProc dstProc = fDstToIndexProc;
-
- const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
-
- TwoPointConicalProc shadeProc = twopoint_repeat;
- if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) {
- shadeProc = twopoint_clamp;
- } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode) {
- shadeProc = twopoint_mirror;
- } else {
- SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode);
- }
-
- if (fDstToIndexClass != kPerspective_MatrixClass) {
- SkPoint srcPt;
- dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
- SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkScalar dx, fx = srcPt.fX;
- SkScalar dy, fy = srcPt.fY;
-
- if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
- const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y));
- dx = step.fX;
- dy = step.fY;
- } else {
- SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = fDstToIndex.getScaleX();
- dy = fDstToIndex.getSkewY();
- }
-
- TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy);
- (*shadeProc)(&rec, dstC, cache, toggle, count);
- } else { // perspective case
- SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf;
- SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf;
- for (; count > 0; --count) {
- SkPoint srcPt;
- dstProc(fDstToIndex, dstX, dstY, &srcPt);
- TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt.fY, 0, 0);
- (*shadeProc)(&rec, dstC, cache, toggle, 1);
-
- dstX += SK_Scalar1;
- toggle = next_dither_toggle(toggle);
- dstC += 1;
- }
- }
-}
-
-// Returns the original non-sorted version of the gradient
-SkShader::GradientType SkTwoPointConicalGradient::asAGradient(
- GradientInfo* info) const {
- if (info) {
- commonAsAGradient(info, fFlippedGrad);
- info->fPoint[0] = fCenter1;
- info->fPoint[1] = fCenter2;
- info->fRadius[0] = fRadius1;
- info->fRadius[1] = fRadius2;
- if (fFlippedGrad) {
- SkTSwap(info->fPoint[0], info->fPoint[1]);
- SkTSwap(info->fRadius[0], info->fRadius[1]);
- }
- }
- return kConical_GradientType;
-}
-
-sk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer) {
- DescriptorScope desc;
- if (!desc.unflatten(buffer)) {
- return nullptr;
- }
- SkPoint c1 = buffer.readPoint();
- SkPoint c2 = buffer.readPoint();
- SkScalar r1 = buffer.readScalar();
- SkScalar r2 = buffer.readScalar();
-
- if (buffer.readBool()) { // flipped
- SkTSwap(c1, c2);
- SkTSwap(r1, r2);
-
- SkColor4f* colors = desc.mutableColors();
- SkScalar* pos = desc.mutablePos();
- const int last = desc.fCount - 1;
- const int half = desc.fCount >> 1;
- for (int i = 0; i < half; ++i) {
- SkTSwap(colors[i], colors[last - i]);
- if (pos) {
- SkScalar tmp = pos[i];
- pos[i] = SK_Scalar1 - pos[last - i];
- pos[last - i] = SK_Scalar1 - tmp;
- }
- }
- if (pos) {
- if (desc.fCount & 1) {
- pos[half] = SK_Scalar1 - pos[half];
- }
- }
- }
-
- return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors,
- std::move(desc.fColorSpace), desc.fPos,
- desc.fCount, desc.fTileMode, desc.fGradFlags,
- desc.fLocalMatrix);
-}
-
-void SkTwoPointConicalGradient::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- buffer.writePoint(fCenter1);
- buffer.writePoint(fCenter2);
- buffer.writeScalar(fRadius1);
- buffer.writeScalar(fRadius2);
- buffer.writeBool(fFlippedGrad);
-}
-
-#if SK_SUPPORT_GPU
-
-#include "SkGr.h"
-#include "SkTwoPointConicalGradient_gpu.h"
-
-sk_sp<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProcessor(
- const AsFPArgs& args) const {
- SkASSERT(args.fContext);
- SkASSERT(fPtsToUnit.isIdentity());
- sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
- args.fDstColorSpace);
- sk_sp<GrFragmentProcessor> inner(Gr2PtConicalGradientEffect::Make(
- GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode,
- std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
-}
-
-#endif
-
-sk_sp<SkShader> SkTwoPointConicalGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- SkSTArray<8, SkColor> origColorsStorage(fColorCount);
- SkSTArray<8, SkScalar> origPosStorage(fColorCount);
- SkSTArray<8, SkColor> xformedColorsStorage(fColorCount);
- SkColor* origColors = origColorsStorage.begin();
- SkScalar* origPos = fOrigPos ? origPosStorage.begin() : nullptr;
- SkColor* xformedColors = xformedColorsStorage.begin();
-
- // Flip if necessary
- SkPoint center1 = fFlippedGrad ? fCenter2 : fCenter1;
- SkPoint center2 = fFlippedGrad ? fCenter1 : fCenter2;
- SkScalar radius1 = fFlippedGrad ? fRadius2 : fRadius1;
- SkScalar radius2 = fFlippedGrad ? fRadius1 : fRadius2;
- for (int i = 0; i < fColorCount; i++) {
- origColors[i] = fFlippedGrad ? fOrigColors[fColorCount - i - 1] : fOrigColors[i];
- if (origPos) {
- origPos[i] = fFlippedGrad ? 1.0f - fOrigPos[fColorCount - i - 1] : fOrigPos[i];
- }
- }
-
- xformer->apply(xformedColors, origColors, fColorCount);
- return SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, xformedColors,
- origPos, fColorCount, fTileMode, fGradFlags,
- &this->getLocalMatrix());
-}
-
-
-#ifndef SK_IGNORE_TO_STRING
-void SkTwoPointConicalGradient::toString(SkString* str) const {
- str->append("SkTwoPointConicalGradient: (");
-
- str->append("center1: (");
- str->appendScalar(fCenter1.fX);
- str->append(", ");
- str->appendScalar(fCenter1.fY);
- str->append(") radius1: ");
- str->appendScalar(fRadius1);
- str->append(" ");
-
- str->append("center2: (");
- str->appendScalar(fCenter2.fX);
- str->append(", ");
- str->appendScalar(fCenter2.fY);
- str->append(") radius2: ");
- str->appendScalar(fRadius2);
- str->append(" ");
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
diff --git a/src/shaders/gradients/SkTwoPointConicalGradient.h b/src/shaders/gradients/SkTwoPointConicalGradient.h
deleted file mode 100644
index b32f52c1e0..0000000000
--- a/src/shaders/gradients/SkTwoPointConicalGradient.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkTwoPointConicalGradient_DEFINED
-#define SkTwoPointConicalGradient_DEFINED
-
-#include "SkColorSpaceXformer.h"
-#include "SkGradientShaderPriv.h"
-
-// TODO(dominikg): Worth making it truly immutable (i.e. set values in constructor)?
-// Should only be initialized once via init(). Immutable afterwards.
-struct TwoPtRadial {
- enum {
- // This value is outside the range SK_FixedMin to SK_FixedMax.
- kDontDrawT = 0x80000000
- };
-
- float fCenterX, fCenterY;
- float fDCenterX, fDCenterY;
- float fRadius;
- float fDRadius;
- float fA;
- float fRadius2;
- float fRDR;
- bool fFlipped;
-
- void init(const SkPoint& center0, SkScalar rad0,
- const SkPoint& center1, SkScalar rad1,
- bool flipped);
-
- static bool DontDrawT(SkFixed t) {
- return kDontDrawT == (uint32_t)t;
- }
-};
-
-
-class SkTwoPointConicalGradient : public SkGradientShaderBase {
- TwoPtRadial fRec;
-public:
- SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius,
- const SkPoint& end, SkScalar endRadius,
- bool flippedGrad, const Descriptor&);
-
- class TwoPointConicalGradientContext : public SkGradientShaderBase::GradientShaderBaseContext {
- public:
- TwoPointConicalGradientContext(const SkTwoPointConicalGradient&, const ContextRec&);
- ~TwoPointConicalGradientContext() override {}
-
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
-
- private:
- typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED;
- };
-
- SkShader::GradientType asAGradient(GradientInfo* info) const override;
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
- bool isOpaque() const override;
-
- SkScalar getCenterX1() const { return SkPoint::Distance(fCenter1, fCenter2); }
- SkScalar getStartRadius() const { return fRadius1; }
- SkScalar getDiffRadius() const { return fRadius2 - fRadius1; }
- const SkPoint& getStartCenter() const { return fCenter1; }
- const SkPoint& getEndCenter() const { return fCenter2; }
- SkScalar getEndRadius() const { return fRadius2; }
- bool isFlippedGrad() const { return fFlippedGrad; }
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTwoPointConicalGradient)
-
-protected:
- SkTwoPointConicalGradient(SkReadBuffer& buffer);
- void flatten(SkWriteBuffer& buffer) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
-private:
- SkPoint fCenter1;
- SkPoint fCenter2;
- SkScalar fRadius1;
- SkScalar fRadius2;
- bool fFlippedGrad;
-
- friend class SkGradientShader;
- typedef SkGradientShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp
deleted file mode 100644
index 8402199362..0000000000
--- a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkTwoPointConicalGradient.h"
-
-#if SK_SUPPORT_GPU
-#include "GrCoordTransform.h"
-#include "GrPaint.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramDataManager.h"
-#include "glsl/GrGLSLUniformHandler.h"
-#include "SkTwoPointConicalGradient_gpu.h"
-
-// For brevity
-typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
-
-static const SkScalar kErrorTol = 0.00001f;
-static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
-
-/**
- * We have three general cases for 2pt conical gradients. First we always assume that
- * the start radius <= end radius. Our first case (kInside_) is when the start circle
- * is completely enclosed by the end circle. The second case (kOutside_) is the case
- * when the start circle is either completely outside the end circle or the circles
- * overlap. The final case (kEdge_) is when the start circle is inside the end one,
- * but the two are just barely touching at 1 point along their edges.
- */
-enum ConicalType {
- kInside_ConicalType,
- kOutside_ConicalType,
- kEdge_ConicalType,
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
- SkMatrix* invLMatrix) {
- // Inverse of the current local matrix is passed in then,
- // translate to center1, rotate so center2 is on x axis.
- const SkPoint& center1 = shader.getStartCenter();
- const SkPoint& center2 = shader.getEndCenter();
-
- invLMatrix->postTranslate(-center1.fX, -center1.fY);
-
- SkPoint diff = center2 - center1;
- SkScalar diffLen = diff.length();
- if (0 != diffLen) {
- SkScalar invDiffLen = SkScalarInvert(diffLen);
- SkMatrix rot;
- rot.setSinCos(-invDiffLen * diff.fY, invDiffLen * diff.fX);
- invLMatrix->postConcat(rot);
- }
-}
-
-class Edge2PtConicalEffect : public GrGradientEffect {
-public:
- class GLSLEdge2PtConicalProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
- return sk_sp<GrFragmentProcessor>(new Edge2PtConicalEffect(args));
- }
-
- ~Edge2PtConicalEffect() override {}
-
- const char* name() const override {
- return "Two-Point Conical Gradient Edge Touching";
- }
-
- // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
- SkScalar center() const { return fCenterX1; }
- SkScalar diffRadius() const { return fDiffRadius; }
- SkScalar radius() const { return fRadius0; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-
- bool onIsEqual(const GrFragmentProcessor& sBase) const override {
- const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
- return (INHERITED::onIsEqual(sBase) &&
- this->fCenterX1 == s.fCenterX1 &&
- this->fRadius0 == s.fRadius0 &&
- this->fDiffRadius == s.fDiffRadius);
- }
-
- Edge2PtConicalEffect(const CreateArgs& args)
- : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) {
- const SkTwoPointConicalGradient& shader =
- *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
- fCenterX1 = shader.getCenterX1();
- fRadius0 = shader.getStartRadius();
- fDiffRadius = shader.getDiffRadius();
- this->initClassID<Edge2PtConicalEffect>();
- // We should only be calling this shader if we are degenerate case with touching circles
- // When deciding if we are in edge case, we scaled by the end radius for cases when the
- // start radius was close to zero, otherwise we scaled by the start radius. In addition
- // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
- // need the sqrt value below
- SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
- (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
- fRadius0 * sqrt(kEdgeErrorTol)));
-
- // We pass the linear part of the quadratic as a varying.
- // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
- fBTransform = this->getCoordTransform();
- SkMatrix& bMatrix = *fBTransform.accessMatrix();
- SkScalar r0dr = fRadius0 * fDiffRadius;
- bMatrix[SkMatrix::kMScaleX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMScaleX] +
- r0dr * bMatrix[SkMatrix::kMPersp0]);
- bMatrix[SkMatrix::kMSkewX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMSkewX] +
- r0dr * bMatrix[SkMatrix::kMPersp1]);
- bMatrix[SkMatrix::kMTransX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMTransX] +
- r0dr * bMatrix[SkMatrix::kMPersp2]);
- this->addCoordTransform(&fBTransform);
- }
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- // @{
- // Cache of values - these can change arbitrarily, EXCEPT
- // we shouldn't change between degenerate and non-degenerate?!
-
- GrCoordTransform fBTransform;
- SkScalar fCenterX1;
- SkScalar fRadius0;
- SkScalar fDiffRadius;
-
- // @}
-
- typedef GrGradientEffect INHERITED;
-};
-
-class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLEdge2PtConicalProcessor(const GrProcessor&);
- ~GLSLEdge2PtConicalProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
- UniformHandle fParamUni;
-
- const char* fVSVaryingName;
- const char* fFSVaryingName;
-
- // @{
- /// Values last uploaded as uniforms
-
- SkScalar fCachedRadius;
- SkScalar fCachedDiffRadius;
-
- // @}
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
- return new Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor(*this);
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
-
-/*
- * All Two point conical gradient test create functions may occasionally create edge case shaders
- */
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
- SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
- SkScalar radius1 = d->fRandom->nextUScalar1();
- SkPoint center2;
- SkScalar radius2;
- do {
- center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
- // If the circles are identical the factory will give us an empty shader.
- // This will happen if we pick identical centers
- } while (center1 == center2);
-
- // Below makes sure that circle one is contained within circle two
- // and both circles are touching on an edge
- SkPoint diff = center2 - center1;
- SkScalar diffLen = diff.length();
- radius2 = radius1 + diffLen;
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&)
- : fVSVaryingName(nullptr)
- , fFSVaryingName(nullptr)
- , fCachedRadius(-SK_ScalarMax)
- , fCachedDiffRadius(-SK_ScalarMax) {}
-
-void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) {
- const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- this->emitUniforms(uniformHandler, ge);
- fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec3f_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSParams");
-
- SkString cName("c");
- SkString tName("t");
- SkString p0; // start radius
- SkString p1; // start radius squared
- SkString p2; // difference in radii (r1 - r0)
-
-
- p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
- p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
- p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
-
- // We interpolate the linear component in coords[1].
- SkASSERT(args.fTransformedCoords[0].getType() == args.fTransformedCoords[1].getType());
- const char* coords2D;
- SkString bVar;
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- if (kVec3f_GrSLType == args.fTransformedCoords[0].getType()) {
- fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
- args.fTransformedCoords[0].c_str(),
- args.fTransformedCoords[0].c_str(),
- args.fTransformedCoords[1].c_str(),
- args.fTransformedCoords[1].c_str());
- coords2D = "interpolants.xy";
- bVar = "interpolants.z";
- } else {
- coords2D = args.fTransformedCoords[0].c_str();
- bVar.printf("%s.x", args.fTransformedCoords[1].c_str());
- }
-
- // output will default to transparent black (we simply won't write anything
- // else to it if invalid, instead of discarding or returning prematurely)
- fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
-
- // c = (x^2)+(y^2) - params[1]
- fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
- cName.c_str(), coords2D, coords2D, p1.c_str());
-
- // linear case: t = -c/b
- fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
- cName.c_str(), bVar.c_str());
-
- // if r(t) > 0, then t will be the x coordinate
- fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
- p2.c_str(), p0.c_str());
- fragBuilder->codeAppend("\t");
- this->emitColor(fragBuilder,
- uniformHandler,
- args.fShaderCaps,
- ge,
- tName.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
- fragBuilder->codeAppend("\t}\n");
-}
-
-void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData(
- const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
- INHERITED::onSetData(pdman, processor);
- const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
- SkScalar radius0 = data.radius();
- SkScalar diffRadius = data.diffRadius();
-
- if (fCachedRadius != radius0 ||
- fCachedDiffRadius != diffRadius) {
-
- pdman.set3f(fParamUni, radius0, radius0 * radius0, diffRadius);
- fCachedRadius = radius0;
- fCachedDiffRadius = diffRadius;
- }
-}
-
-void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor,
- const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- b->add32(GenBaseGradientKey(processor));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Focal Conical Gradients
-//////////////////////////////////////////////////////////////////////////////
-
-static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
- SkMatrix* invLMatrix, SkScalar* focalX) {
- // Inverse of the current local matrix is passed in then,
- // translate, scale, and rotate such that endCircle is unit circle on x-axis,
- // and focal point is at the origin.
- ConicalType conicalType;
- const SkPoint& focal = shader.getStartCenter();
- const SkPoint& centerEnd = shader.getEndCenter();
- SkScalar radius = shader.getEndRadius();
- SkScalar invRadius = 1.f / radius;
-
- SkMatrix matrix;
-
- matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
- matrix.postScale(invRadius, invRadius);
-
- SkPoint focalTrans;
- matrix.mapPoints(&focalTrans, &focal, 1);
- *focalX = focalTrans.length();
-
- if (0.f != *focalX) {
- SkScalar invFocalX = SkScalarInvert(*focalX);
- SkMatrix rot;
- rot.setSinCos(-invFocalX * focalTrans.fY, invFocalX * focalTrans.fX);
- matrix.postConcat(rot);
- }
-
- matrix.postTranslate(-(*focalX), 0.f);
-
- // If the focal point is touching the edge of the circle it will
- // cause a degenerate case that must be handled separately
- // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
- // stability trade off versus the linear approx used in the Edge Shader
- if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
- return kEdge_ConicalType;
- }
-
- // Scale factor 1 / (1 - focalX * focalX)
- SkScalar oneMinusF2 = 1.f - *focalX * *focalX;
- SkScalar s = SkScalarInvert(oneMinusF2);
-
-
- if (s >= 0.f) {
- conicalType = kInside_ConicalType;
- matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
- } else {
- conicalType = kOutside_ConicalType;
- matrix.postScale(s, s);
- }
-
- invLMatrix->postConcat(matrix);
-
- return conicalType;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-class FocalOutside2PtConicalEffect : public GrGradientEffect {
-public:
- class GLSLFocalOutside2PtConicalProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
- return sk_sp<GrFragmentProcessor>(
- new FocalOutside2PtConicalEffect(args, focalX));
- }
-
- ~FocalOutside2PtConicalEffect() override {}
-
- const char* name() const override {
- return "Two-Point Conical Gradient Focal Outside";
- }
-
- bool isFlipped() const { return fIsFlipped; }
- SkScalar focal() const { return fFocalX; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-
- bool onIsEqual(const GrFragmentProcessor& sBase) const override {
- const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
- return (INHERITED::onIsEqual(sBase) &&
- this->fFocalX == s.fFocalX &&
- this->fIsFlipped == s.fIsFlipped);
- }
-
- static bool IsFlipped(const CreateArgs& args) {
- // eww.
- return static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad();
- }
-
- FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
- : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
- , fFocalX(focalX)
- , fIsFlipped(IsFlipped(args)) {
- this->initClassID<FocalOutside2PtConicalEffect>();
- }
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- SkScalar fFocalX;
- bool fIsFlipped;
-
- typedef GrGradientEffect INHERITED;
-};
-
-class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
- : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
- ~GLSLFocalOutside2PtConicalProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
- UniformHandle fParamUni;
-
- const char* fVSVaryingName;
- const char* fFSVaryingName;
-
- bool fIsFlipped;
-
- // @{
- /// Values last uploaded as uniforms
-
- SkScalar fCachedFocal;
-
- // @}
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
- return new FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor(*this);
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
-
-/*
- * All Two point conical gradient test create functions may occasionally create edge case shaders
- */
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
- SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
- SkScalar radius1 = 0.f;
- SkPoint center2;
- SkScalar radius2;
- do {
- center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
- // Need to make sure the centers are not the same or else focal point will be inside
- } while (center1 == center2);
-
- SkPoint diff = center2 - center1;
- SkScalar diffLen = diff.length();
- // Below makes sure that the focal point is not contained within circle two
- radius2 = d->fRandom->nextRangeF(0.f, diffLen);
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
- ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor)
- : fVSVaryingName(nullptr)
- , fFSVaryingName(nullptr)
- , fCachedFocal(SK_ScalarMax) {
- const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
- fIsFlipped = data.isFlipped();
-}
-
-void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
- const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- this->emitUniforms(uniformHandler, ge);
- fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec2f_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSParams");
- SkString tName("t");
- SkString p0; // focalX
- SkString p1; // 1 - focalX * focalX
-
- p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
- p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
-
- // if we have a vec3 from being in perspective, convert it to a vec2 first
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
- const char* coords2D = coords2DString.c_str();
-
- // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
-
- // output will default to transparent black (we simply won't write anything
- // else to it if invalid, instead of discarding or returning prematurely)
- fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
-
- fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
- fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
- fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
-
- // Must check to see if we flipped the circle order (to make sure start radius < end radius)
- // If so we must also flip sign on sqrt
- if (!fIsFlipped) {
- fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
- coords2D, p0.c_str());
- } else {
- fragBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
- coords2D, p0.c_str());
- }
-
- fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
- fragBuilder->codeAppend("\t\t");
- this->emitColor(fragBuilder,
- uniformHandler,
- args.fShaderCaps,
- ge,
- tName.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
- fragBuilder->codeAppend("\t}\n");
-}
-
-void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData(
- const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
- INHERITED::onSetData(pdman, processor);
- const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
- SkASSERT(data.isFlipped() == fIsFlipped);
- SkScalar focal = data.focal();
-
- if (fCachedFocal != focal) {
- SkScalar oneMinus2F = 1.f - focal * focal;
-
- pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
- fCachedFocal = focal;
- }
-}
-
-void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(
- const GrProcessor& processor,
- const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- uint32_t* key = b->add32n(2);
- key[0] = GenBaseGradientKey(processor);
- key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-class FocalInside2PtConicalEffect : public GrGradientEffect {
-public:
- class GLSLFocalInside2PtConicalProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
- return sk_sp<GrFragmentProcessor>(
- new FocalInside2PtConicalEffect(args, focalX));
- }
-
- ~FocalInside2PtConicalEffect() override {}
-
- const char* name() const override {
- return "Two-Point Conical Gradient Focal Inside";
- }
-
- SkScalar focal() const { return fFocalX; }
-
- typedef FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor GLSLProcessor;
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-
- bool onIsEqual(const GrFragmentProcessor& sBase) const override {
- const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
- return (INHERITED::onIsEqual(sBase) &&
- this->fFocalX == s.fFocalX);
- }
-
- FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
- : INHERITED(args, args.fShader->colorsAreOpaque()), fFocalX(focalX) {
- this->initClassID<FocalInside2PtConicalEffect>();
- }
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- SkScalar fFocalX;
-
- typedef GrGradientEffect INHERITED;
-};
-
-class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
- : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLFocalInside2PtConicalProcessor(const GrProcessor&);
- ~GLSLFocalInside2PtConicalProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
- UniformHandle fFocalUni;
-
- const char* fVSVaryingName;
- const char* fFSVaryingName;
-
- // @{
- /// Values last uploaded as uniforms
-
- SkScalar fCachedFocal;
-
- // @}
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
- return new FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor(*this);
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
-
-/*
- * All Two point conical gradient test create functions may occasionally create edge case shaders
- */
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
- SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
- SkScalar radius1 = 0.f;
- SkPoint center2;
- SkScalar radius2;
- do {
- center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
- // Below makes sure radius2 is larger enouch such that the focal point
- // is inside the end circle
- SkScalar increase = d->fRandom->nextUScalar1();
- SkPoint diff = center2 - center1;
- SkScalar diffLen = diff.length();
- radius2 = diffLen + increase;
- // If the circles are identical the factory will give us an empty shader.
- } while (radius1 == radius2 && center1 == center2);
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
- ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
- : fVSVaryingName(nullptr)
- , fFSVaryingName(nullptr)
- , fCachedFocal(SK_ScalarMax) {}
-
-void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
- const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- this->emitUniforms(uniformHandler, ge);
- fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kFloat_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSParams");
- SkString tName("t");
-
- // this is the distance along x-axis from the end center to focal point in
- // transformed coordinates
- GrShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
-
- // if we have a vec3 from being in perspective, convert it to a vec2 first
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
- const char* coords2D = coords2DString.c_str();
-
- // t = p.x * focalX + length(p)
- fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
- coords2D, focal.c_str(), coords2D);
-
- this->emitColor(fragBuilder,
- uniformHandler,
- args.fShaderCaps,
- ge,
- tName.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
-}
-
-void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
- const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
- INHERITED::onSetData(pdman, processor);
- const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
- SkScalar focal = data.focal();
-
- if (fCachedFocal != focal) {
- pdman.set1f(fFocalUni, SkScalarToFloat(focal));
- fCachedFocal = focal;
- }
-}
-
-void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
- const GrProcessor& processor,
- const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- b->add32(GenBaseGradientKey(processor));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Circle Conical Gradients
-//////////////////////////////////////////////////////////////////////////////
-
-struct CircleConicalInfo {
- SkPoint fCenterEnd;
- SkScalar fA;
- SkScalar fB;
- SkScalar fC;
-};
-
-// Returns focal distance along x-axis in transformed coords
-static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
- SkMatrix* invLMatrix, CircleConicalInfo* info) {
- // Inverse of the current local matrix is passed in then,
- // translate and scale such that start circle is on the origin and has radius 1
- const SkPoint& centerStart = shader.getStartCenter();
- const SkPoint& centerEnd = shader.getEndCenter();
- SkScalar radiusStart = shader.getStartRadius();
- SkScalar radiusEnd = shader.getEndRadius();
-
- SkMatrix matrix;
-
- matrix.setTranslate(-centerStart.fX, -centerStart.fY);
-
- SkScalar invStartRad = 1.f / radiusStart;
- matrix.postScale(invStartRad, invStartRad);
-
- radiusEnd /= radiusStart;
-
- SkPoint centerEndTrans;
- matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
-
- SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
- - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
-
- // Check to see if start circle is inside end circle with edges touching.
- // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
- // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
- // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
- // still accurate.
- if (SkScalarAbs(A) < kEdgeErrorTol) {
- return kEdge_ConicalType;
- }
-
- SkScalar C = 1.f / A;
- SkScalar B = (radiusEnd - 1.f) * C;
-
- matrix.postScale(C, C);
-
- invLMatrix->postConcat(matrix);
-
- info->fCenterEnd = centerEndTrans;
- info->fA = A;
- info->fB = B;
- info->fC = C;
-
- // if A ends up being negative, the start circle is contained completely inside the end cirlce
- if (A < 0.f) {
- return kInside_ConicalType;
- }
- return kOutside_ConicalType;
-}
-
-class CircleInside2PtConicalEffect : public GrGradientEffect {
-public:
- class GLSLCircleInside2PtConicalProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
- return sk_sp<GrFragmentProcessor>(
- new CircleInside2PtConicalEffect(args, info));
- }
-
- ~CircleInside2PtConicalEffect() override {}
-
- const char* name() const override { return "Two-Point Conical Gradient Inside"; }
-
- SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
- SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
- SkScalar A() const { return fInfo.fA; }
- SkScalar B() const { return fInfo.fB; }
- SkScalar C() const { return fInfo.fC; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const override;
-
- bool onIsEqual(const GrFragmentProcessor& sBase) const override {
- const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
- return (INHERITED::onIsEqual(sBase) &&
- this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
- this->fInfo.fA == s.fInfo.fA &&
- this->fInfo.fB == s.fInfo.fB &&
- this->fInfo.fC == s.fInfo.fC);
- }
-
- CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
- : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) {
- this->initClassID<CircleInside2PtConicalEffect>();
- }
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- const CircleConicalInfo fInfo;
-
- typedef GrGradientEffect INHERITED;
-};
-
-class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
- : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
- ~GLSLCircleInside2PtConicalProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
- UniformHandle fCenterUni;
- UniformHandle fParamUni;
-
- const char* fVSVaryingName;
- const char* fFSVaryingName;
-
- // @{
- /// Values last uploaded as uniforms
-
- SkScalar fCachedCenterX;
- SkScalar fCachedCenterY;
- SkScalar fCachedA;
- SkScalar fCachedB;
- SkScalar fCachedC;
-
- // @}
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
- return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
-
-/*
- * All Two point conical gradient test create functions may occasionally create edge case shaders
- */
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
- SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
- SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
- SkPoint center2;
- SkScalar radius2;
- do {
- center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
- // Below makes sure that circle one is contained within circle two
- SkScalar increase = d->fRandom->nextUScalar1();
- SkPoint diff = center2 - center1;
- SkScalar diffLen = diff.length();
- radius2 = radius1 + diffLen + increase;
- // If the circles are identical the factory will give us an empty shader.
- } while (radius1 == radius2 && center1 == center2);
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
- ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
- : fVSVaryingName(nullptr)
- , fFSVaryingName(nullptr)
- , fCachedCenterX(SK_ScalarMax)
- , fCachedCenterY(SK_ScalarMax)
- , fCachedA(SK_ScalarMax)
- , fCachedB(SK_ScalarMax)
- , fCachedC(SK_ScalarMax) {}
-
-void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
- const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- this->emitUniforms(uniformHandler, ge);
- fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec2f_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSCenter");
- fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec3f_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSParams");
- SkString tName("t");
-
- GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
- // params.x = A
- // params.y = B
- // params.z = C
- GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
-
- // if we have a vec3 from being in perspective, convert it to a vec2 first
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
- const char* coords2D = coords2DString.c_str();
-
- // p = coords2D
- // e = center end
- // r = radius end
- // A = dot(e, e) - r^2 + 2 * r - 1
- // B = (r -1) / A
- // C = 1 / A
- // d = dot(e, p) + B
- // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
- fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
- fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
- params.c_str());
- fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
- tName.c_str(), params.c_str(), params.c_str());
-
- this->emitColor(fragBuilder,
- uniformHandler,
- args.fShaderCaps,
- ge,
- tName.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
-}
-
-void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
- const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
- INHERITED::onSetData(pdman, processor);
- const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
- SkScalar centerX = data.centerX();
- SkScalar centerY = data.centerY();
- SkScalar A = data.A();
- SkScalar B = data.B();
- SkScalar C = data.C();
-
- if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
- fCachedA != A || fCachedB != B || fCachedC != C) {
-
- pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
- pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
-
- fCachedCenterX = centerX;
- fCachedCenterY = centerY;
- fCachedA = A;
- fCachedB = B;
- fCachedC = C;
- }
-}
-
-void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
- const GrProcessor& processor,
- const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- b->add32(GenBaseGradientKey(processor));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-class CircleOutside2PtConicalEffect : public GrGradientEffect {
-public:
- class GLSLCircleOutside2PtConicalProcessor;
-
- static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
- return sk_sp<GrFragmentProcessor>(
- new CircleOutside2PtConicalEffect(args, info));
- }
-
- ~CircleOutside2PtConicalEffect() override {}
-
- const char* name() const override { return "Two-Point Conical Gradient Outside"; }
-
- SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
- SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
- SkScalar A() const { return fInfo.fA; }
- SkScalar B() const { return fInfo.fB; }
- SkScalar C() const { return fInfo.fC; }
- SkScalar tLimit() const { return fTLimit; }
- bool isFlipped() const { return fIsFlipped; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-
- bool onIsEqual(const GrFragmentProcessor& sBase) const override {
- const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
- return (INHERITED::onIsEqual(sBase) &&
- this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
- this->fInfo.fA == s.fInfo.fA &&
- this->fInfo.fB == s.fInfo.fB &&
- this->fInfo.fC == s.fInfo.fC &&
- this->fTLimit == s.fTLimit &&
- this->fIsFlipped == s.fIsFlipped);
- }
-
- CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
- : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
- , fInfo(info) {
- this->initClassID<CircleOutside2PtConicalEffect>();
- const SkTwoPointConicalGradient& shader =
- *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
- if (shader.getStartRadius() != shader.getEndRadius()) {
- fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
- } else {
- fTLimit = SK_ScalarMin;
- }
-
- fIsFlipped = shader.isFlippedGrad();
- }
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- const CircleConicalInfo fInfo;
- SkScalar fTLimit;
- bool fIsFlipped;
-
- typedef GrGradientEffect INHERITED;
-};
-
-class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
- : public GrGradientEffect::GLSLProcessor {
-public:
- GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
- ~GLSLCircleOutside2PtConicalProcessor() override {}
-
- virtual void emitCode(EmitArgs&) override;
-
- static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
- UniformHandle fCenterUni;
- UniformHandle fParamUni;
-
- const char* fVSVaryingName;
- const char* fFSVaryingName;
-
- bool fIsFlipped;
-
- // @{
- /// Values last uploaded as uniforms
-
- SkScalar fCachedCenterX;
- SkScalar fCachedCenterY;
- SkScalar fCachedA;
- SkScalar fCachedB;
- SkScalar fCachedC;
- SkScalar fCachedTLimit;
-
- // @}
-
-private:
- typedef GrGradientEffect::GLSLProcessor INHERITED;
-
-};
-
-void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
- return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
-
-/*
- * All Two point conical gradient test create functions may occasionally create edge case shaders
- */
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
- SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
- SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
- SkPoint center2;
- SkScalar radius2;
- SkScalar diffLen;
- do {
- center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
- // If the circles share a center than we can't be in the outside case
- } while (center1 == center2);
- SkPoint diff = center2 - center1;
- diffLen = diff.length();
- // Below makes sure that circle one is not contained within circle two
- // and have radius2 >= radius to match sorting on cpu side
- radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
-
- RandomGradientParams 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);
- sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
- GrAlwaysAssert(fp);
- return fp;
-}
-#endif
-
-CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
- ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
- : fVSVaryingName(nullptr)
- , fFSVaryingName(nullptr)
- , fCachedCenterX(SK_ScalarMax)
- , fCachedCenterY(SK_ScalarMax)
- , fCachedA(SK_ScalarMax)
- , fCachedB(SK_ScalarMax)
- , fCachedC(SK_ScalarMax)
- , fCachedTLimit(SK_ScalarMax) {
- const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
- fIsFlipped = data.isFlipped();
- }
-
-void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
- const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- this->emitUniforms(uniformHandler, ge);
- fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec2f_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSCenter");
- fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec4f_GrSLType, kDefault_GrSLPrecision,
- "Conical2FSParams");
- SkString tName("t");
-
- GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
- // params.x = A
- // params.y = B
- // params.z = C
- GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
-
- // if we have a vec3 from being in perspective, convert it to a vec2 first
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
- const char* coords2D = coords2DString.c_str();
-
- // output will default to transparent black (we simply won't write anything
- // else to it if invalid, instead of discarding or returning prematurely)
- fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
-
- // p = coords2D
- // e = center end
- // r = radius end
- // A = dot(e, e) - r^2 + 2 * r - 1
- // B = (r -1) / A
- // C = 1 / A
- // d = dot(e, p) + B
- // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
-
- fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
- fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
- params.c_str());
- fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
- params.c_str());
-
- // Must check to see if we flipped the circle order (to make sure start radius < end radius)
- // If so we must also flip sign on sqrt
- if (!fIsFlipped) {
- fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
- } else {
- fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
- }
-
- fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
- tName.c_str(), params.c_str());
- fragBuilder->codeAppend("\t\t");
- this->emitColor(fragBuilder,
- uniformHandler,
- args.fShaderCaps,
- ge,
- tName.c_str(),
- args.fOutputColor,
- args.fInputColor,
- args.fTexSamplers);
- fragBuilder->codeAppend("\t}\n");
-}
-
-void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
- const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
- INHERITED::onSetData(pdman, processor);
- const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
- SkASSERT(data.isFlipped() == fIsFlipped);
- SkScalar centerX = data.centerX();
- SkScalar centerY = data.centerY();
- SkScalar A = data.A();
- SkScalar B = data.B();
- SkScalar C = data.C();
- SkScalar tLimit = data.tLimit();
-
- if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
- fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
-
- pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
- pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
- SkScalarToFloat(tLimit));
-
- fCachedCenterX = centerX;
- fCachedCenterY = centerY;
- fCachedA = A;
- fCachedB = B;
- fCachedC = C;
- fCachedTLimit = tLimit;
- }
-}
-
-void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
- const GrProcessor& processor,
- const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- uint32_t* key = b->add32n(2);
- key[0] = GenBaseGradientKey(processor);
- key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
- const GrGradientEffect::CreateArgs& args) {
- const SkTwoPointConicalGradient& shader =
- *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
-
- SkMatrix matrix;
- if (!shader.getLocalMatrix().invert(&matrix)) {
- return nullptr;
- }
- if (args.fMatrix) {
- SkMatrix inv;
- if (!args.fMatrix->invert(&inv)) {
- return nullptr;
- }
- matrix.postConcat(inv);
- }
-
- GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
- std::move(args.fColorSpaceXform), args.fGammaCorrect);
-
- if (shader.getStartRadius() < kErrorTol) {
- SkScalar focalX;
- ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
- if (type == kInside_ConicalType) {
- return FocalInside2PtConicalEffect::Make(newArgs, focalX);
- } else if(type == kEdge_ConicalType) {
- set_matrix_edge_conical(shader, &matrix);
- return Edge2PtConicalEffect::Make(newArgs);
- } else {
- return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
- }
- }
-
- CircleConicalInfo info;
- ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
-
- if (type == kInside_ConicalType) {
- return CircleInside2PtConicalEffect::Make(newArgs, info);
- } else if (type == kEdge_ConicalType) {
- set_matrix_edge_conical(shader, &matrix);
- return Edge2PtConicalEffect::Make(newArgs);
- } else {
- return CircleOutside2PtConicalEffect::Make(newArgs, info);
- }
-}
-
-#endif
diff --git a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.h b/src/shaders/gradients/SkTwoPointConicalGradient_gpu.h
deleted file mode 100644
index 46edb1f7d1..0000000000
--- a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkTwoPointConicalGradient_gpu_DEFINED
-#define SkTwoPointConicalGradient_gpu_DEFINED
-
-#include "SkGradientShaderPriv.h"
-
-class GrProcessor;
-class SkTwoPointConicalGradient;
-
-namespace Gr2PtConicalGradientEffect {
- /**
- * Creates an effect that produces a two point conical gradient based on the
- * shader passed in.
- */
- sk_sp<GrFragmentProcessor> Make(const GrGradientEffect::CreateArgs& args);
-};
-
-#endif