aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/shaders
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
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')
-rw-r--r--src/shaders/SkBitmapProcShader.cpp229
-rw-r--r--src/shaders/SkBitmapProcShader.h26
-rw-r--r--src/shaders/SkColorFilterShader.cpp138
-rw-r--r--src/shaders/SkColorFilterShader.h60
-rw-r--r--src/shaders/SkColorShader.cpp339
-rw-r--r--src/shaders/SkColorShader.h142
-rw-r--r--src/shaders/SkComposeShader.cpp311
-rw-r--r--src/shaders/SkComposeShader.h88
-rw-r--r--src/shaders/SkEmptyShader.h41
-rw-r--r--src/shaders/SkImageShader.cpp391
-rw-r--r--src/shaders/SkImageShader.h58
-rw-r--r--src/shaders/SkLightingShader.cpp488
-rw-r--r--src/shaders/SkLightingShader.h39
-rw-r--r--src/shaders/SkLocalMatrixShader.cpp110
-rw-r--r--src/shaders/SkLocalMatrixShader.h75
-rw-r--r--src/shaders/SkPerlinNoiseShader.cpp1056
-rw-r--r--src/shaders/SkPictureShader.cpp364
-rw-r--r--src/shaders/SkPictureShader.h79
-rw-r--r--src/shaders/SkShader.cpp305
-rw-r--r--src/shaders/SkShaderBase.h303
-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
41 files changed, 0 insertions, 12445 deletions
diff --git a/src/shaders/SkBitmapProcShader.cpp b/src/shaders/SkBitmapProcShader.cpp
deleted file mode 100644
index e52982354d..0000000000
--- a/src/shaders/SkBitmapProcShader.cpp
+++ /dev/null
@@ -1,229 +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 "SkBitmapProcShader.h"
-
-#include "SkArenaAlloc.h"
-#include "SkBitmapProcState.h"
-#include "SkBitmapProvider.h"
-#include "SkXfermodePriv.h"
-
-static bool only_scale_and_translate(const SkMatrix& matrix) {
- unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
- return (matrix.getType() & ~mask) == 0;
-}
-
-class BitmapProcInfoContext : public SkShaderBase::Context {
-public:
- // The info has been allocated elsewhere, but we are responsible for calling its destructor.
- BitmapProcInfoContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec,
- SkBitmapProcInfo* info)
- : INHERITED(shader, rec)
- , fInfo(info)
- {
- fFlags = 0;
- if (fInfo->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
- fFlags |= SkShaderBase::kOpaqueAlpha_Flag;
- }
-
- if (1 == fInfo->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
- fFlags |= SkShaderBase::kConstInY32_Flag;
- }
- }
-
- uint32_t getFlags() const override { return fFlags; }
-
-private:
- SkBitmapProcInfo* fInfo;
- uint32_t fFlags;
-
- typedef SkShaderBase::Context INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class BitmapProcShaderContext : public BitmapProcInfoContext {
-public:
- BitmapProcShaderContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec,
- SkBitmapProcState* state)
- : INHERITED(shader, rec, state)
- , fState(state)
- {}
-
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
- const SkBitmapProcState& state = *fState;
- if (state.getShaderProc32()) {
- state.getShaderProc32()(&state, x, y, dstC, count);
- return;
- }
-
- const int BUF_MAX = 128;
- uint32_t buffer[BUF_MAX];
- SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
- SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
- const int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
-
- SkASSERT(state.fPixmap.addr());
-
- for (;;) {
- int n = SkTMin(count, max);
- SkASSERT(n > 0 && n < BUF_MAX*2);
- mproc(state, buffer, n, x, y);
- sproc(state, buffer, n, dstC);
-
- if ((count -= n) == 0) {
- break;
- }
- SkASSERT(count > 0);
- x += n;
- dstC += n;
- }
- }
-
- ShadeProc asAShadeProc(void** ctx) override {
- if (fState->getShaderProc32()) {
- *ctx = fState;
- return (ShadeProc)fState->getShaderProc32();
- }
- return nullptr;
- }
-
-private:
- SkBitmapProcState* fState;
-
- typedef BitmapProcInfoContext INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-#include "SkLinearBitmapPipeline.h"
-#include "SkPM4f.h"
-
-class LinearPipelineContext : public BitmapProcInfoContext {
-public:
- LinearPipelineContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec,
- SkBitmapProcInfo* info, SkArenaAlloc* alloc)
- : INHERITED(shader, rec, info), fAllocator{alloc}
- {
- // Save things off in case we need to build a blitter pipeline.
- fSrcPixmap = info->fPixmap;
- fAlpha = SkColorGetA(info->fPaintColor) / 255.0f;
- fFilterQuality = info->fFilterQuality;
- fMatrixTypeMask = info->fRealInvMatrix.getType();
-
- fShaderPipeline = alloc->make<SkLinearBitmapPipeline>(
- info->fRealInvMatrix, info->fFilterQuality,
- info->fTileModeX, info->fTileModeY,
- info->fPaintColor,
- info->fPixmap,
- fAllocator);
-
- // To implement the old shadeSpan entry-point, we need to efficiently convert our native
- // floats into SkPMColor. The SkXfermode::D32Procs do exactly that.
- //
- fSrcModeProc = SkXfermode::GetD32Proc(SkBlendMode::kSrc, 0);
- }
-
- void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override {
- fShaderPipeline->shadeSpan4f(x, y, dstC, count);
- }
-
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
- const int N = 128;
- SkPM4f tmp[N];
-
- while (count > 0) {
- const int n = SkTMin(count, N);
- fShaderPipeline->shadeSpan4f(x, y, tmp, n);
- fSrcModeProc(SkBlendMode::kSrc, dstC, tmp, n, nullptr);
- dstC += n;
- x += n;
- count -= n;
- }
- }
-
- bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override {
- if ((fBlitterPipeline = SkLinearBitmapPipeline::ClonePipelineForBlitting(
- *fShaderPipeline,
- fMatrixTypeMask,
- fFilterQuality, fSrcPixmap,
- fAlpha, state->fMode, dstInfo, fAllocator)))
- {
- state->fStorage[0] = fBlitterPipeline;
- state->fBlitBW = &LinearPipelineContext::ForwardToPipeline;
-
- return true;
- }
-
- return false;
- }
-
- static void ForwardToPipeline(BlitState* state, int x, int y, const SkPixmap& dst, int count) {
- SkLinearBitmapPipeline* pipeline = static_cast<SkLinearBitmapPipeline*>(state->fStorage[0]);
- void* addr = dst.writable_addr32(x, y);
- pipeline->blitSpan(x, y, addr, count);
- }
-
-private:
- // Store the allocator from the context creation incase we are asked to build a blitter.
- SkArenaAlloc* fAllocator;
- SkLinearBitmapPipeline* fShaderPipeline;
- SkLinearBitmapPipeline* fBlitterPipeline;
- SkXfermode::D32Proc fSrcModeProc;
- SkPixmap fSrcPixmap;
- float fAlpha;
- SkMatrix::TypeMask fMatrixTypeMask;
- SkFilterQuality fFilterQuality;
-
- typedef BitmapProcInfoContext INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static bool choose_linear_pipeline(const SkShaderBase::ContextRec& rec, const SkImageInfo& srcInfo) {
- // If we get here, we can reasonably use either context, respect the caller's preference
- //
- bool needsPremul = srcInfo.alphaType() == kUnpremul_SkAlphaType;
- bool needsSwizzle = srcInfo.bytesPerPixel() == 4 && srcInfo.colorType() != kN32_SkColorType;
- return SkShaderBase::ContextRec::kPM4f_DstType == rec.fPreferredDstType
- || needsPremul || needsSwizzle;
-}
-
-size_t SkBitmapProcLegacyShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) {
- size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
- size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo);
- size_t s = SkTMax(size0, size1);
- return s;
-}
-
-SkShaderBase::Context* SkBitmapProcLegacyShader::MakeContext(
- const SkShaderBase& shader, TileMode tmx, TileMode tmy,
- const SkBitmapProvider& provider, const ContextRec& rec, SkArenaAlloc* alloc)
-{
- SkMatrix totalInverse;
- // Do this first, so we know the matrix can be inverted.
- if (!shader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &totalInverse)) {
- return nullptr;
- }
-
- // Decide if we can/want to use the new linear pipeline
- bool useLinearPipeline = choose_linear_pipeline(rec, provider.info());
-
- if (useLinearPipeline) {
- SkBitmapProcInfo* info = alloc->make<SkBitmapProcInfo>(provider, tmx, tmy);
- if (!info->init(totalInverse, *rec.fPaint)) {
- return nullptr;
- }
-
- return alloc->make<LinearPipelineContext>(shader, rec, info, alloc);
- } else {
- SkBitmapProcState* state = alloc->make<SkBitmapProcState>(provider, tmx, tmy);
- if (!state->setup(totalInverse, *rec.fPaint)) {
- return nullptr;
- }
- return alloc->make<BitmapProcShaderContext>(shader, rec, state);
- }
-}
diff --git a/src/shaders/SkBitmapProcShader.h b/src/shaders/SkBitmapProcShader.h
deleted file mode 100644
index 2a2599cb1d..0000000000
--- a/src/shaders/SkBitmapProcShader.h
+++ /dev/null
@@ -1,26 +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.
- */
-#ifndef SkBitmapProcShader_DEFINED
-#define SkBitmapProcShader_DEFINED
-
-#include "SkImagePriv.h"
-#include "SkShaderBase.h"
-
-class SkBitmapProvider;
-
-class SkBitmapProcLegacyShader : public SkShaderBase {
-private:
- friend class SkImageShader;
-
- static size_t ContextSize(const ContextRec&, const SkImageInfo& srcInfo);
- static Context* MakeContext(const SkShaderBase&, TileMode tmx, TileMode tmy,
- const SkBitmapProvider&, const ContextRec&, SkArenaAlloc* alloc);
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkColorFilterShader.cpp b/src/shaders/SkColorFilterShader.cpp
deleted file mode 100644
index 4798422dfa..0000000000
--- a/src/shaders/SkColorFilterShader.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkArenaAlloc.h"
-#include "SkColorFilterShader.h"
-#include "SkColorSpaceXformer.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkShader.h"
-#include "SkString.h"
-
-#if SK_SUPPORT_GPU
-#include "GrFragmentProcessor.h"
-#endif
-
-SkColorFilterShader::SkColorFilterShader(sk_sp<SkShader> shader, sk_sp<SkColorFilter> filter)
- : fShader(std::move(shader))
- , fFilter(std::move(filter))
-{
- SkASSERT(fShader);
- SkASSERT(fFilter);
-}
-
-sk_sp<SkFlattenable> SkColorFilterShader::CreateProc(SkReadBuffer& buffer) {
- auto shader = buffer.readShader();
- auto filter = buffer.readColorFilter();
- if (!shader || !filter) {
- return nullptr;
- }
- return sk_make_sp<SkColorFilterShader>(shader, filter);
-}
-
-void SkColorFilterShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeFlattenable(fShader.get());
- buffer.writeFlattenable(fFilter.get());
-}
-
-uint32_t SkColorFilterShader::FilterShaderContext::getFlags() const {
- const SkColorFilterShader& filterShader = static_cast<const SkColorFilterShader&>(fShader);
-
- uint32_t shaderF = fShaderContext->getFlags();
- uint32_t filterF = filterShader.fFilter->getFlags();
-
- // If the filter does not support a given feature, but sure to clear the corresponding flag
- // in the shader flags.
- //
- if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) {
- shaderF &= ~kOpaqueAlpha_Flag;
- }
- return shaderF;
-}
-
-SkShaderBase::Context* SkColorFilterShader::onMakeContext(const ContextRec& rec,
- SkArenaAlloc* alloc) const {
- auto* shaderContext = as_SB(fShader)->makeContext(rec, alloc);
- if (nullptr == shaderContext) {
- return nullptr;
- }
- return alloc->make<FilterShaderContext>(*this, shaderContext, rec);
-}
-
-sk_sp<SkShader> SkColorFilterShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- return xformer->apply(fShader.get())->makeWithColorFilter(xformer->apply(fFilter.get()));
-}
-
-SkColorFilterShader::FilterShaderContext::FilterShaderContext(
- const SkColorFilterShader& filterShader,
- SkShaderBase::Context* shaderContext,
- const ContextRec& rec)
- : INHERITED(filterShader, rec)
- , fShaderContext(shaderContext)
-{}
-
-void SkColorFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[],
- int count) {
- const SkColorFilterShader& filterShader = static_cast<const SkColorFilterShader&>(fShader);
-
- fShaderContext->shadeSpan(x, y, result, count);
- filterShader.fFilter->filterSpan(result, count, result);
-}
-
-void SkColorFilterShader::FilterShaderContext::shadeSpan4f(int x, int y, SkPM4f result[],
- int count) {
- const SkColorFilterShader& filterShader = static_cast<const SkColorFilterShader&>(fShader);
-
- fShaderContext->shadeSpan4f(x, y, result, count);
- filterShader.fFilter->filterSpan4f(result, count, result);
-}
-
-#if SK_SUPPORT_GPU
-/////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> SkColorFilterShader::asFragmentProcessor(const AsFPArgs& args) const {
-
- sk_sp<GrFragmentProcessor> fp1(as_SB(fShader)->asFragmentProcessor(args));
- if (!fp1) {
- return nullptr;
- }
-
- sk_sp<GrFragmentProcessor> fp2(fFilter->asFragmentProcessor(args.fContext,
- args.fDstColorSpace));
- if (!fp2) {
- return fp1;
- }
-
- sk_sp<GrFragmentProcessor> fpSeries[] = { std::move(fp1), std::move(fp2) };
- return GrFragmentProcessor::RunInSeries(fpSeries, 2);
-}
-#endif
-
-#ifndef SK_IGNORE_TO_STRING
-void SkColorFilterShader::toString(SkString* str) const {
- str->append("SkColorFilterShader: (");
-
- str->append("Shader: ");
- as_SB(fShader)->toString(str);
- str->append(" Filter: ");
- // TODO: add "fFilter->toString(str);" once SkColorFilter::toString is added
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-sk_sp<SkShader> SkShader::makeWithColorFilter(sk_sp<SkColorFilter> filter) const {
- SkShader* base = const_cast<SkShader*>(this);
- if (!filter) {
- return sk_ref_sp(base);
- }
- return sk_make_sp<SkColorFilterShader>(sk_ref_sp(base), filter);
-}
diff --git a/src/shaders/SkColorFilterShader.h b/src/shaders/SkColorFilterShader.h
deleted file mode 100644
index 7f4202158a..0000000000
--- a/src/shaders/SkColorFilterShader.h
+++ /dev/null
@@ -1,60 +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 SkColorFilterShader_DEFINED
-#define SkColorFilterShader_DEFINED
-
-#include "SkColorFilter.h"
-#include "SkShaderBase.h"
-
-class SkArenaAlloc;
-
-class SkColorFilterShader : public SkShaderBase {
-public:
- SkColorFilterShader(sk_sp<SkShader> shader, sk_sp<SkColorFilter> filter);
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- class FilterShaderContext : public Context {
- public:
- // Takes ownership of shaderContext and calls its destructor.
- FilterShaderContext(const SkColorFilterShader&, SkShaderBase::Context*, const ContextRec&);
-
- uint32_t getFlags() const override;
-
- void shadeSpan(int x, int y, SkPMColor[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f[], int count) override;
-
- void set3DMask(const SkMask* mask) override {
- // forward to our proxy
- fShaderContext->set3DMask(mask);
- }
-
- private:
- SkShaderBase::Context* fShaderContext;
-
- typedef Context INHERITED;
- };
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorFilterShader)
-
-protected:
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc* alloc) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
-private:
- sk_sp<SkShader> fShader;
- sk_sp<SkColorFilter> fFilter;
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkColorShader.cpp b/src/shaders/SkColorShader.cpp
deleted file mode 100644
index 32b2c54d71..0000000000
--- a/src/shaders/SkColorShader.cpp
+++ /dev/null
@@ -1,339 +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 "SkArenaAlloc.h"
-#include "SkColorShader.h"
-#include "SkColorSpace.h"
-#include "SkPM4fPriv.h"
-#include "SkRasterPipeline.h"
-#include "SkReadBuffer.h"
-#include "SkUtils.h"
-
-SkColorShader::SkColorShader(SkColor c) : fColor(c) {}
-
-bool SkColorShader::isOpaque() const {
- return SkColorGetA(fColor) == 255;
-}
-
-sk_sp<SkFlattenable> SkColorShader::CreateProc(SkReadBuffer& buffer) {
- return sk_make_sp<SkColorShader>(buffer.readColor());
-}
-
-void SkColorShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeColor(fColor);
-}
-
-uint32_t SkColorShader::ColorShaderContext::getFlags() const {
- return fFlags;
-}
-
-SkShaderBase::Context* SkColorShader::onMakeContext(const ContextRec& rec,
- SkArenaAlloc* alloc) const {
- return alloc->make<ColorShaderContext>(*this, rec);
-}
-
-SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
- const ContextRec& rec)
- : INHERITED(shader, rec)
-{
- SkColor color = shader.fColor;
- unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
-
- unsigned r = SkColorGetR(color);
- unsigned g = SkColorGetG(color);
- unsigned b = SkColorGetB(color);
-
- if (a != 255) {
- r = SkMulDiv255Round(r, a);
- g = SkMulDiv255Round(g, a);
- b = SkMulDiv255Round(b, a);
- }
- fPMColor = SkPackARGB32(a, r, g, b);
-
- SkColor4f c4 = SkColor4f::FromColor(shader.fColor);
- c4.fA *= rec.fPaint->getAlpha() / 255.0f;
- fPM4f = c4.premul();
-
- fFlags = kConstInY32_Flag;
- if (255 == a) {
- fFlags |= kOpaqueAlpha_Flag;
- }
-}
-
-void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
- sk_memset32(span, fPMColor, count);
-}
-
-void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
- memset(alpha, SkGetPackedA32(fPMColor), count);
-}
-
-void SkColorShader::ColorShaderContext::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
- for (int i = 0; i < count; ++i) {
- span[i] = fPM4f;
- }
-}
-
-SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
- if (info) {
- if (info->fColors && info->fColorCount >= 1) {
- info->fColors[0] = fColor;
- }
- info->fColorCount = 1;
- info->fTileMode = SkShader::kRepeat_TileMode;
- }
- return kColor_GradientType;
-}
-
-#if SK_SUPPORT_GPU
-
-#include "SkGr.h"
-#include "effects/GrConstColorProcessor.h"
-sk_sp<GrFragmentProcessor> SkColorShader::asFragmentProcessor(const AsFPArgs& args) const {
- GrColor4f color = SkColorToPremulGrColor4f(fColor, args.fDstColorSpace);
- return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode);
-}
-
-#endif
-
-#ifndef SK_IGNORE_TO_STRING
-void SkColorShader::toString(SkString* str) const {
- str->append("SkColorShader: (");
-
- str->append("Color: ");
- str->appendHex(fColor);
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static unsigned unit_to_byte(float unit) {
- SkASSERT(unit >= 0 && unit <= 1);
- return (unsigned)(unit * 255 + 0.5);
-}
-
-static SkColor unit_to_skcolor(const SkColor4f& unit, SkColorSpace* cs) {
- return SkColorSetARGB(unit_to_byte(unit.fA), unit_to_byte(unit.fR),
- unit_to_byte(unit.fG), unit_to_byte(unit.fB));
-}
-
-SkColor4Shader::SkColor4Shader(const SkColor4f& color, sk_sp<SkColorSpace> space)
- : fColorSpace(std::move(space))
- , fColor4(color)
- , fCachedByteColor(unit_to_skcolor(color.pin(), space.get()))
-{}
-
-sk_sp<SkFlattenable> SkColor4Shader::CreateProc(SkReadBuffer& buffer) {
- SkColor4f color;
- buffer.readColor4f(&color);
- if (buffer.readBool()) {
- // TODO how do we unflatten colorspaces
- }
- return SkShader::MakeColorShader(color, nullptr);
-}
-
-void SkColor4Shader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeColor4f(fColor4);
- buffer.writeBool(false); // TODO how do we flatten colorspaces?
-}
-
-uint32_t SkColor4Shader::Color4Context::getFlags() const {
- return fFlags;
-}
-
-SkShaderBase::Context* SkColor4Shader::onMakeContext(const ContextRec& rec,
- SkArenaAlloc* alloc) const {
- return alloc->make<Color4Context>(*this, rec);
-}
-
-SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader,
- const ContextRec& rec)
-: INHERITED(shader, rec)
-{
- SkColor color = shader.fCachedByteColor;
- unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
-
- unsigned r = SkColorGetR(color);
- unsigned g = SkColorGetG(color);
- unsigned b = SkColorGetB(color);
-
- if (a != 255) {
- r = SkMulDiv255Round(r, a);
- g = SkMulDiv255Round(g, a);
- b = SkMulDiv255Round(b, a);
- }
- fPMColor = SkPackARGB32(a, r, g, b);
-
- SkColor4f c4 = shader.fColor4;
- c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f);
- fPM4f = c4.premul();
-
- fFlags = kConstInY32_Flag;
- if (255 == a) {
- fFlags |= kOpaqueAlpha_Flag;
- }
-}
-
-void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) {
- sk_memset32(span, fPMColor, count);
-}
-
-void SkColor4Shader::Color4Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
- memset(alpha, SkGetPackedA32(fPMColor), count);
-}
-
-void SkColor4Shader::Color4Context::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
- for (int i = 0; i < count; ++i) {
- span[i] = fPM4f;
- }
-}
-
-// TODO: do we need an updated version of this method for color4+colorspace?
-SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const {
- if (info) {
- if (info->fColors && info->fColorCount >= 1) {
- info->fColors[0] = fCachedByteColor;
- }
- info->fColorCount = 1;
- info->fTileMode = SkShader::kRepeat_TileMode;
- }
- return kColor_GradientType;
-}
-
-#if SK_SUPPORT_GPU
-
-#include "SkGr.h"
-#include "effects/GrConstColorProcessor.h"
-#include "GrColorSpaceXform.h"
-sk_sp<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor(const AsFPArgs& args) const {
- sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
- args.fDstColorSpace);
- GrColor4f color = GrColor4f::FromSkColor4f(fColor4);
- if (colorSpaceXform) {
- color = colorSpaceXform->apply(color);
- }
- return GrConstColorProcessor::Make(color.premul(), GrConstColorProcessor::kModulateA_InputMode);
-}
-
-#endif
-
-#ifndef SK_IGNORE_TO_STRING
-void SkColor4Shader::toString(SkString* str) const {
- str->append("SkColor4Shader: (");
-
- str->append("RGBA:");
- for (int i = 0; i < 4; ++i) {
- str->appendf(" %g", fColor4.vec()[i]);
- }
- str->append(" )");
-}
-#endif
-
-sk_sp<SkShader> SkColor4Shader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- return SkShader::MakeColorShader(xformer->apply(fCachedByteColor));
-}
-
-sk_sp<SkShader> SkShader::MakeColorShader(const SkColor4f& color, sk_sp<SkColorSpace> space) {
- if (!SkScalarsAreFinite(color.vec(), 4)) {
- return nullptr;
- }
- return sk_make_sp<SkColor4Shader>(color, std::move(space));
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static void D32_BlitBW(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
- int count) {
- SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
- const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
- proc(state->fMode, dst.writable_addr32(x, y), src, count, nullptr);
-}
-
-static void D32_BlitAA(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
- int count, const SkAlpha aa[]) {
- SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
- const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
- proc(state->fMode, dst.writable_addr32(x, y), src, count, aa);
-}
-
-static void F16_BlitBW(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
- int count) {
- SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
- const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
- proc(state->fMode, dst.writable_addr64(x, y), src, count, nullptr);
-}
-
-static void F16_BlitAA(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
- int count, const SkAlpha aa[]) {
- SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
- const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
- proc(state->fMode, dst.writable_addr64(x, y), src, count, aa);
-}
-
-static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info,
- SkShaderBase::Context::BlitState* state) {
- uint32_t flags = SkXfermode::kSrcIsSingle_D32Flag;
- if (pm4->a() == 1) {
- flags |= SkXfermode::kSrcIsOpaque_D32Flag;
- }
- switch (info.colorType()) {
- case kN32_SkColorType:
- if (info.gammaCloseToSRGB()) {
- flags |= SkXfermode::kDstIsSRGB_D32Flag;
- }
- state->fStorage[0] = (void*)SkXfermode::GetD32Proc(state->fMode, flags);
- state->fStorage[1] = (void*)pm4;
- state->fBlitBW = D32_BlitBW;
- state->fBlitAA = D32_BlitAA;
- return true;
- case kRGBA_F16_SkColorType:
- state->fStorage[0] = (void*)SkXfermode::GetF16Proc(state->fMode, flags);
- state->fStorage[1] = (void*)pm4;
- state->fBlitBW = F16_BlitBW;
- state->fBlitAA = F16_BlitAA;
- return true;
- default:
- return false;
- }
-}
-
-bool SkColorShader::ColorShaderContext::onChooseBlitProcs(const SkImageInfo& info,
- BlitState* state) {
- return choose_blitprocs(&fPM4f, info, state);
-}
-
-bool SkColor4Shader::Color4Context::onChooseBlitProcs(const SkImageInfo& info, BlitState* state) {
- return choose_blitprocs(&fPM4f, info, state);
-}
-
-bool SkColorShader::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dst,
- SkArenaAlloc* scratch,
- const SkMatrix&,
- const SkPaint&,
- const SkMatrix*) const {
- auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
- p->append(SkRasterPipeline::constant_color, color);
- return true;
-}
-
-bool SkColor4Shader::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dst,
- SkArenaAlloc* scratch,
- const SkMatrix&,
- const SkPaint&,
- const SkMatrix*) const {
- auto color = scratch->make<SkPM4f>(to_colorspace(fColor4, fColorSpace.get(), dst).premul());
- p->append(SkRasterPipeline::constant_color, color);
- return true;
-}
diff --git a/src/shaders/SkColorShader.h b/src/shaders/SkColorShader.h
deleted file mode 100644
index 9af83c1163..0000000000
--- a/src/shaders/SkColorShader.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2007 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.
- */
-
-#ifndef SkColorShader_DEFINED
-#define SkColorShader_DEFINED
-
-#include "SkColorSpaceXformer.h"
-#include "SkShaderBase.h"
-#include "SkPM4f.h"
-
-/** \class SkColorShader
- A Shader that represents a single color. In general, this effect can be
- accomplished by just using the color field on the paint, but if an
- actual shader object is needed, this provides that feature.
-*/
-class SK_API SkColorShader : public SkShaderBase {
-public:
- /** Create a ColorShader that ignores the color in the paint, and uses the
- specified color. Note: like all shaders, at draw time the paint's alpha
- will be respected, and is applied to the specified color.
- */
- explicit SkColorShader(SkColor c);
-
- bool isOpaque() const override;
- bool isConstant() const override { return true; }
-
- class ColorShaderContext : public Context {
- public:
- ColorShaderContext(const SkColorShader& shader, const ContextRec&);
-
- uint32_t getFlags() const override;
- void shadeSpan(int x, int y, SkPMColor span[], int count) override;
- void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f[], int count) override;
-
- protected:
- bool onChooseBlitProcs(const SkImageInfo&, BlitState*) override;
-
- private:
- SkPM4f fPM4f;
- SkPMColor fPMColor;
- uint32_t fFlags;
-
- typedef Context 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(SkColorShader)
-
-protected:
- SkColorShader(SkReadBuffer&);
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override;
-
- bool onAsLuminanceColor(SkColor* lum) const override {
- *lum = fColor;
- return true;
- }
-
- bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
- const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override;
-
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
- return SkShader::MakeColorShader(xformer->apply(fColor));
- }
-
-private:
- SkColor fColor;
-
- typedef SkShaderBase INHERITED;
-};
-
-class SkColor4Shader : public SkShaderBase {
-public:
- SkColor4Shader(const SkColor4f&, sk_sp<SkColorSpace>);
-
- bool isOpaque() const override {
- return SkColorGetA(fCachedByteColor) == 255;
- }
- bool isConstant() const override { return true; }
-
- class Color4Context : public Context {
- public:
- Color4Context(const SkColor4Shader& shader, const ContextRec&);
-
- uint32_t getFlags() const override;
- void shadeSpan(int x, int y, SkPMColor span[], int count) override;
- void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f[], int count) override;
-
- protected:
- bool onChooseBlitProcs(const SkImageInfo&, BlitState*) override;
-
- private:
- SkPM4f fPM4f;
- SkPMColor fPMColor;
- uint32_t fFlags;
-
- typedef Context 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(SkColorShader)
-
-protected:
- SkColor4Shader(SkReadBuffer&);
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- bool onAsLuminanceColor(SkColor* lum) const override {
- *lum = fCachedByteColor;
- return true;
- }
- bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
- const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override;
-
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
-private:
- sk_sp<SkColorSpace> fColorSpace;
- const SkColor4f fColor4;
- const SkColor fCachedByteColor;
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkComposeShader.cpp b/src/shaders/SkComposeShader.cpp
deleted file mode 100644
index 7735494291..0000000000
--- a/src/shaders/SkComposeShader.cpp
+++ /dev/null
@@ -1,311 +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 "SkArenaAlloc.h"
-#include "SkBlendModePriv.h"
-#include "SkComposeShader.h"
-#include "SkColorFilter.h"
-#include "SkColorPriv.h"
-#include "SkColorShader.h"
-#include "SkRasterPipeline.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkString.h"
-#include "../jumper/SkJumper.h"
-
-sk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
- SkBlendMode mode) {
- if (!src || !dst) {
- return nullptr;
- }
- if (SkBlendMode::kSrc == mode) {
- return src;
- }
- if (SkBlendMode::kDst == mode) {
- return dst;
- }
- return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-class SkAutoAlphaRestore {
-public:
- SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
- fAlpha = paint->getAlpha();
- fPaint = paint;
- paint->setAlpha(newAlpha);
- }
-
- ~SkAutoAlphaRestore() {
- fPaint->setAlpha(fAlpha);
- }
-private:
- SkPaint* fPaint;
- uint8_t fAlpha;
-};
-#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
-
-sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
- sk_sp<SkShader> shaderA(buffer.readShader());
- sk_sp<SkShader> shaderB(buffer.readShader());
- SkBlendMode mode;
- if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) {
- sk_sp<SkXfermode> xfer = buffer.readXfermode();
- mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver;
- } else {
- mode = (SkBlendMode)buffer.read32();
- }
- if (!shaderA || !shaderB) {
- return nullptr;
- }
- return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode);
-}
-
-void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeFlattenable(fShaderA.get());
- buffer.writeFlattenable(fShaderB.get());
- buffer.write32((int)fMode);
-}
-
-SkShaderBase::Context* SkComposeShader::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const
-{
- // we preconcat our localMatrix (if any) with the device matrix
- // before calling our sub-shaders
- SkMatrix tmpM;
- tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix());
-
- // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the
- // result. ComposeShader itself will respect the alpha, and post-apply it after calling the
- // sub-shaders.
- SkPaint opaquePaint(*rec.fPaint);
- opaquePaint.setAlpha(0xFF);
-
- ContextRec newRec(rec);
- newRec.fMatrix = &tmpM;
- newRec.fPaint = &opaquePaint;
-
- SkShaderBase::Context* contextA = as_SB(fShaderA)->makeContext(newRec, alloc);
- SkShaderBase::Context* contextB = as_SB(fShaderB)->makeContext(newRec, alloc);
- if (!contextA || !contextB) {
- return nullptr;
- }
-
- return alloc->make<ComposeShaderContext>(*this, rec, contextA, contextB);
-}
-
-sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- return SkShader::MakeComposeShader(xformer->apply(fShaderA.get()),
- xformer->apply(fShaderB.get()), fMode);
-}
-
-SkComposeShader::ComposeShaderContext::ComposeShaderContext(
- const SkComposeShader& shader, const ContextRec& rec,
- SkShaderBase::Context* contextA, SkShaderBase::Context* contextB)
- : INHERITED(shader, rec)
- , fShaderContextA(contextA)
- , fShaderContextB(contextB) {}
-
-bool SkComposeShader::asACompose(ComposeRec* rec) const {
- if (rec) {
- rec->fShaderA = fShaderA.get();
- rec->fShaderB = fShaderB.get();
- rec->fBlendMode = fMode;
- }
- return true;
-}
-
-bool SkComposeShader::isRasterPipelineOnly() const {
- return as_SB(fShaderA)->isRasterPipelineOnly() || as_SB(fShaderB)->isRasterPipelineOnly();
-}
-
-bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS,
- SkArenaAlloc* alloc, const SkMatrix& ctm,
- const SkPaint& paint, const SkMatrix* localM) const {
- struct Storage {
- float fXY[4 * SkJumper_kMaxStride];
- float fRGBA[4 * SkJumper_kMaxStride];
- float fAlpha;
- };
- auto storage = alloc->make<Storage>();
-
- // We need to save off device x,y (inputs to shader), since after calling fShaderA they
- // will be smashed, and I'll need them again for fShaderB. store_rgba saves off 4 registers
- // even though we only need to save r,g.
- pipeline->append(SkRasterPipeline::store_rgba, storage->fXY);
- if (!as_SB(fShaderB)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // SRC
- return false;
- }
- // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
- // since fShaderB will overwrite them.
- pipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
- // Now we restore the device x,y for the next shader
- pipeline->append(SkRasterPipeline::load_rgba, storage->fXY);
- if (!as_SB(fShaderA)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // DST
- return false;
- }
- // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode
- // so we have to shuttle them. If we had a stage the would load_into_dst, then we could
- // reverse the two shader invocations, and avoid this move...
- pipeline->append(SkRasterPipeline::move_src_dst);
- pipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
-
- // Idea: should time this, and see if it helps to have custom versions of the overflow modes
- // that do their own clamping, avoiding the overhead of an extra stage.
- SkBlendMode_AppendStages(fMode, pipeline);
- if (SkBlendMode_CanOverflow(fMode)) {
- pipeline->append(SkRasterPipeline::clamp_a);
- }
- return true;
-}
-
-// larger is better (fewer times we have to loop), but we shouldn't
-// take up too much stack-space (each element is 4 bytes)
-#define TMP_COLOR_COUNT 64
-
-void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
- auto* shaderContextA = fShaderContextA;
- auto* shaderContextB = fShaderContextB;
- SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode;
- unsigned scale = SkAlpha255To256(this->getPaintAlpha());
-
- SkPMColor tmp[TMP_COLOR_COUNT];
-
- SkXfermode* xfer = SkXfermode::Peek(mode);
- if (nullptr == xfer) { // implied SRC_OVER
- // TODO: when we have a good test-case, should use SkBlitRow::Proc32
- // for these loops
- do {
- int n = count;
- if (n > TMP_COLOR_COUNT) {
- n = TMP_COLOR_COUNT;
- }
-
- shaderContextA->shadeSpan(x, y, result, n);
- shaderContextB->shadeSpan(x, y, tmp, n);
-
- if (256 == scale) {
- for (int i = 0; i < n; i++) {
- result[i] = SkPMSrcOver(tmp[i], result[i]);
- }
- } else {
- for (int i = 0; i < n; i++) {
- result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
- scale);
- }
- }
-
- result += n;
- x += n;
- count -= n;
- } while (count > 0);
- } else { // use mode for the composition
- do {
- int n = count;
- if (n > TMP_COLOR_COUNT) {
- n = TMP_COLOR_COUNT;
- }
-
- shaderContextA->shadeSpan(x, y, result, n);
- shaderContextB->shadeSpan(x, y, tmp, n);
- xfer->xfer32(result, tmp, n, nullptr);
-
- if (256 != scale) {
- for (int i = 0; i < n; i++) {
- result[i] = SkAlphaMulQ(result[i], scale);
- }
- }
-
- result += n;
- x += n;
- count -= n;
- } while (count > 0);
- }
-}
-
-void SkComposeShader::ComposeShaderContext::shadeSpan4f(int x, int y, SkPM4f result[], int count) {
- auto* shaderContextA = fShaderContextA;
- auto* shaderContextB = fShaderContextB;
- SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode;
- unsigned alpha = this->getPaintAlpha();
- Sk4f scale(alpha * (1.0f / 255));
-
- SkPM4f tmp[TMP_COLOR_COUNT];
-
- SkXfermodeProc4f xfer = SkXfermode::GetProc4f(mode);
- do {
- int n = SkTMin(count, TMP_COLOR_COUNT);
-
- shaderContextA->shadeSpan4f(x, y, result, n);
- shaderContextB->shadeSpan4f(x, y, tmp, n);
- if (255 == alpha) {
- for (int i = 0; i < n; ++i) {
- result[i] = xfer(tmp[i], result[i]);
- }
- } else {
- for (int i = 0; i < n; ++i) {
- (xfer(tmp[i], result[i]).to4f() * scale).store(result + i);
- }
- }
- result += n;
- x += n;
- count -= n;
- } while (count > 0);
-}
-
-#if SK_SUPPORT_GPU
-
-#include "effects/GrConstColorProcessor.h"
-#include "effects/GrXfermodeFragmentProcessor.h"
-
-/////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
- switch (fMode) {
- case SkBlendMode::kClear:
- return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
- GrConstColorProcessor::kIgnore_InputMode);
- break;
- case SkBlendMode::kSrc:
- return as_SB(fShaderB)->asFragmentProcessor(args);
- break;
- case SkBlendMode::kDst:
- return as_SB(fShaderA)->asFragmentProcessor(args);
- break;
- default:
- sk_sp<GrFragmentProcessor> fpA(as_SB(fShaderA)->asFragmentProcessor(args));
- if (!fpA) {
- return nullptr;
- }
- sk_sp<GrFragmentProcessor> fpB(as_SB(fShaderB)->asFragmentProcessor(args));
- if (!fpB) {
- return nullptr;
- }
- return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
- std::move(fpA), fMode);
- }
-}
-#endif
-
-#ifndef SK_IGNORE_TO_STRING
-void SkComposeShader::toString(SkString* str) const {
- str->append("SkComposeShader: (");
-
- str->append("ShaderA: ");
- as_SB(fShaderA)->toString(str);
- str->append(" ShaderB: ");
- as_SB(fShaderB)->toString(str);
- if (SkBlendMode::kSrcOver != fMode) {
- str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode));
- }
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
diff --git a/src/shaders/SkComposeShader.h b/src/shaders/SkComposeShader.h
deleted file mode 100644
index 8592f3a8ae..0000000000
--- a/src/shaders/SkComposeShader.h
+++ /dev/null
@@ -1,88 +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.
- */
-
-#ifndef SkComposeShader_DEFINED
-#define SkComposeShader_DEFINED
-
-#include "SkShaderBase.h"
-#include "SkBlendMode.h"
-
-class SkColorSpacXformer;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-/** \class SkComposeShader
- This subclass of shader returns the composition of two other shaders, combined by
- a xfermode.
-*/
-class SK_API SkComposeShader : public SkShaderBase {
-public:
- /** Create a new compose shader, given shaders A, B, and a combining xfermode mode.
- When the xfermode is called, it will be given the result from shader A as its
- "dst", and the result from shader B as its "src".
- mode->xfer32(sA_result, sB_result, ...)
- @param shaderA The colors from this shader are seen as the "dst" by the xfermode
- @param shaderB The colors from this shader are seen as the "src" by the xfermode
- @param mode The xfermode that combines the colors from the two shaders. If mode
- is null, then SRC_OVER is assumed.
- */
- SkComposeShader(sk_sp<SkShader> sA, sk_sp<SkShader> sB, SkBlendMode mode)
- : fShaderA(std::move(sA))
- , fShaderB(std::move(sB))
- , fMode(mode)
- {}
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- class ComposeShaderContext : public Context {
- public:
- // When this object gets destroyed, it will call contextA and contextB's destructor
- // but it will NOT free the memory.
- ComposeShaderContext(const SkComposeShader&, const ContextRec&,
- SkShaderBase::Context* contextA, SkShaderBase::Context* contextB);
-
- void shadeSpan(int x, int y, SkPMColor[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f[], int count) override;
-
- private:
- SkShaderBase::Context* fShaderContextA;
- SkShaderBase::Context* fShaderContextB;
-
- typedef Context INHERITED;
- };
-
-#ifdef SK_DEBUG
- SkShader* getShaderA() { return fShaderA.get(); }
- SkShader* getShaderB() { return fShaderB.get(); }
-#endif
-
- bool asACompose(ComposeRec* rec) const override;
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeShader)
-
-protected:
- SkComposeShader(SkReadBuffer&);
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
- bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
- const SkMatrix&, const SkPaint&, const SkMatrix* localM) const override;
-
- bool isRasterPipelineOnly() const final;
-
-private:
- sk_sp<SkShader> fShaderA;
- sk_sp<SkShader> fShaderB;
- SkBlendMode fMode;
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkEmptyShader.h b/src/shaders/SkEmptyShader.h
deleted file mode 100644
index c1bcfe0957..0000000000
--- a/src/shaders/SkEmptyShader.h
+++ /dev/null
@@ -1,41 +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 SkEmptyShader_DEFINED
-#define SkEmptyShader_DEFINED
-
-#include "SkShaderBase.h"
-
-// TODO: move this to private, as there is a public factory on SkShader
-
-/**
- * \class SkEmptyShader
- * A Shader that always draws nothing. Its createContext always returns nullptr.
- */
-class SK_API SkEmptyShader : public SkShaderBase {
-public:
- SkEmptyShader() {}
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmptyShader)
-
-protected:
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override {
- return nullptr;
- }
-
- void flatten(SkWriteBuffer& buffer) const override {
- // Do nothing.
- // We just don't want to fall through to SkShader::flatten(),
- // which will write data we don't care to serialize or decode.
- }
-
-private:
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
deleted file mode 100644
index 751300e951..0000000000
--- a/src/shaders/SkImageShader.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkArenaAlloc.h"
-#include "SkBitmapController.h"
-#include "SkBitmapProcShader.h"
-#include "SkBitmapProvider.h"
-#include "SkColorTable.h"
-#include "SkEmptyShader.h"
-#include "SkImage_Base.h"
-#include "SkImageShader.h"
-#include "SkPM4fPriv.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "../jumper/SkJumper.h"
-
-SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
- : INHERITED(matrix)
- , fImage(std::move(img))
- , fTileModeX(tmx)
- , fTileModeY(tmy)
-{}
-
-sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
- const TileMode tx = (TileMode)buffer.readUInt();
- const TileMode ty = (TileMode)buffer.readUInt();
- SkMatrix matrix;
- buffer.readMatrix(&matrix);
- sk_sp<SkImage> img = buffer.readImage();
- if (!img) {
- return nullptr;
- }
- return SkImageShader::Make(std::move(img), tx, ty, &matrix);
-}
-
-void SkImageShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeUInt(fTileModeX);
- buffer.writeUInt(fTileModeY);
- buffer.writeMatrix(this->getLocalMatrix());
- buffer.writeImage(fImage.get());
-}
-
-bool SkImageShader::isOpaque() const {
- return fImage->isOpaque();
-}
-
-SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
- SkArenaAlloc* alloc) const {
- return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
- SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
- rec, alloc);
-}
-
-SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
- if (texM) {
- *texM = this->getLocalMatrix();
- }
- if (xy) {
- xy[0] = (TileMode)fTileModeX;
- xy[1] = (TileMode)fTileModeY;
- }
- return const_cast<SkImage*>(fImage.get());
-}
-
-#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
-bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
- const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
- if (!bm) {
- return false;
- }
-
- if (texture) {
- *texture = *bm;
- }
- if (texM) {
- *texM = this->getLocalMatrix();
- }
- if (xy) {
- xy[0] = (TileMode)fTileModeX;
- xy[1] = (TileMode)fTileModeY;
- }
- return true;
-}
-#endif
-
-static bool bitmap_is_too_big(int w, int h) {
- // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
- // communicates between its matrix-proc and its sampler-proc. Until we can
- // widen that, we have to reject bitmaps that are larger.
- //
- static const int kMaxSize = 65535;
-
- return w > kMaxSize || h > kMaxSize;
-}
-
-sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
- const SkMatrix* localMatrix) {
- if (!image || bitmap_is_too_big(image->width(), image->height())) {
- return sk_make_sp<SkEmptyShader>();
- } else {
- return sk_make_sp<SkImageShader>(image, tx, ty, localMatrix);
- }
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkImageShader::toString(SkString* str) const {
- const char* gTileModeName[SkShader::kTileModeCount] = {
- "clamp", "repeat", "mirror"
- };
-
- str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
- fImage->toString(str);
- this->INHERITED::toString(str);
- str->append(")");
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "SkGr.h"
-#include "GrContext.h"
-#include "effects/GrSimpleTextureEffect.h"
-#include "effects/GrBicubicEffect.h"
-#include "effects/GrSimpleTextureEffect.h"
-
-sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
-
- SkMatrix lmInverse;
- if (!this->getLocalMatrix().invert(&lmInverse)) {
- return nullptr;
- }
- if (args.fLocalMatrix) {
- SkMatrix inv;
- if (!args.fLocalMatrix->invert(&inv)) {
- return nullptr;
- }
- lmInverse.postConcat(inv);
- }
-
- SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
-
- // Must set wrap and filter on the sampler before requesting a texture. In two places below
- // we check the matrix scale factors to determine how to interpret the filter quality setting.
- // This completely ignores the complexity of the drawVertices case where explicit local coords
- // are provided by the caller.
- bool doBicubic;
- GrSamplerParams::FilterMode textureFilterMode =
- GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
- &doBicubic);
- GrSamplerParams params(tm, textureFilterMode);
- sk_sp<SkColorSpace> texColorSpace;
- SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
- sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(args.fContext, params,
- args.fDstColorSpace,
- &texColorSpace, scaleAdjust));
- if (!proxy) {
- return nullptr;
- }
-
- bool isAlphaOnly = GrPixelConfigIsAlphaOnly(proxy->config());
-
- lmInverse.postScale(scaleAdjust[0], scaleAdjust[1]);
-
- sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
- args.fDstColorSpace);
- sk_sp<GrFragmentProcessor> inner;
- if (doBicubic) {
- inner = GrBicubicEffect::Make(args.fContext->resourceProvider(), std::move(proxy),
- std::move(colorSpaceXform), lmInverse, tm);
- } else {
- inner = GrSimpleTextureEffect::Make(args.fContext->resourceProvider(), std::move(proxy),
- std::move(colorSpaceXform), lmInverse, params);
- }
-
- if (isAlphaOnly) {
- return inner;
- }
- return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
-}
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-#include "SkImagePriv.h"
-
-sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
- SkShader::TileMode tmy, const SkMatrix* localMatrix,
- SkCopyPixelsMode cpm) {
- return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm),
- tmx, tmy, localMatrix);
-}
-
-static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
- SkMatrix lm;
- buffer.readMatrix(&lm);
- sk_sp<SkImage> image = buffer.readBitmapAsImage();
- SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
- SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
- return image ? image->makeShader(mx, my, &lm) : nullptr;
-}
-
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderBase)
-SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
-SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShaderBase_Type);
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-
-
-bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dstCS, SkArenaAlloc* alloc,
- const SkMatrix& ctm, const SkPaint& paint,
- const SkMatrix* localM) const {
- auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix());
- if (localM) {
- matrix.preConcat(*localM);
- }
-
- if (!matrix.invert(&matrix)) {
- return false;
- }
- auto quality = paint.getFilterQuality();
-
- SkBitmapProvider provider(fImage.get(), dstCS);
- SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kYes);
- std::unique_ptr<SkBitmapController::State> state {
- controller.requestBitmap(provider, matrix, quality)
- };
- if (!state) {
- return false;
- }
-
- const SkPixmap& pm = state->pixmap();
- matrix = state->invMatrix();
- quality = state->quality();
- auto info = pm.info();
-
- // When the matrix is just an integer translate, bilerp == nearest neighbor.
- if (quality == kLow_SkFilterQuality &&
- matrix.getType() <= SkMatrix::kTranslate_Mask &&
- matrix.getTranslateX() == (int)matrix.getTranslateX() &&
- matrix.getTranslateY() == (int)matrix.getTranslateY()) {
- quality = kNone_SkFilterQuality;
- }
-
- // See skia:4649 and the GM image_scale_aligned.
- if (quality == kNone_SkFilterQuality) {
- if (matrix.getScaleX() >= 0) {
- matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
- floorf(matrix.getTranslateX())));
- }
- if (matrix.getScaleY() >= 0) {
- matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
- floorf(matrix.getTranslateY())));
- }
- }
-
-
- struct MiscCtx {
- std::unique_ptr<SkBitmapController::State> state;
- SkColor4f paint_color;
- float matrix[9];
- };
- auto misc = alloc->make<MiscCtx>();
- misc->state = std::move(state); // Extend lifetime to match the pipeline's.
- misc->paint_color = SkColor4f_from_SkColor(paint.getColor(), dstCS);
- if (matrix.asAffine(misc->matrix)) {
- p->append(SkRasterPipeline::matrix_2x3, misc->matrix);
- } else {
- matrix.get9(misc->matrix);
- p->append(SkRasterPipeline::matrix_perspective, misc->matrix);
- }
-
- auto gather = alloc->make<SkJumper_GatherCtx>();
- gather->pixels = pm.addr();
- gather->ctable = pm.ctable() ? pm.ctable()->readColors() : nullptr;
- gather->stride = pm.rowBytesAsPixels();
-
- // Tiling stages (clamp_x, mirror_y, etc.) are inclusive of their limit,
- // so we tick down our width and height by one float to make them exclusive.
- auto ulp_before = [](float f) {
- uint32_t bits;
- memcpy(&bits, &f, 4);
- bits--;
- memcpy(&f, &bits, 4);
- return f;
- };
- auto limit_x = alloc->make<float>(ulp_before((float)pm. width())),
- limit_y = alloc->make<float>(ulp_before((float)pm.height()));
-
- auto append_tiling_and_gather = [&] {
- switch (fTileModeX) {
- case kClamp_TileMode: p->append(SkRasterPipeline::clamp_x, limit_x); break;
- case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit_x); break;
- case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit_x); break;
- }
- switch (fTileModeY) {
- case kClamp_TileMode: p->append(SkRasterPipeline::clamp_y, limit_y); break;
- case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, limit_y); break;
- case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, limit_y); break;
- }
- switch (info.colorType()) {
- case kAlpha_8_SkColorType: p->append(SkRasterPipeline::gather_a8, gather); break;
- case kIndex_8_SkColorType: p->append(SkRasterPipeline::gather_i8, gather); break;
- case kGray_8_SkColorType: p->append(SkRasterPipeline::gather_g8, gather); break;
- case kRGB_565_SkColorType: p->append(SkRasterPipeline::gather_565, gather); break;
- case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, gather); break;
- case kRGBA_8888_SkColorType:
- case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, gather); break;
- case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::gather_f16, gather); break;
- default: SkASSERT(false);
- }
- if (info.gammaCloseToSRGB() && dstCS != nullptr) {
- p->append_from_srgb(info.alphaType());
- }
- };
-
- SkJumper_SamplerCtx* sampler = nullptr;
- if (quality != kNone_SkFilterQuality) {
- sampler = alloc->make<SkJumper_SamplerCtx>();
- }
-
- auto sample = [&](SkRasterPipeline::StockStage setup_x,
- SkRasterPipeline::StockStage setup_y) {
- p->append(setup_x, sampler);
- p->append(setup_y, sampler);
- append_tiling_and_gather();
- p->append(SkRasterPipeline::accumulate, sampler);
- };
-
- if (quality == kNone_SkFilterQuality) {
- append_tiling_and_gather();
- } else if (quality == kLow_SkFilterQuality) {
- p->append(SkRasterPipeline::save_xy, sampler);
-
- sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny);
- sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny);
- sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py);
- sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py);
-
- p->append(SkRasterPipeline::move_dst_src);
- } else {
- p->append(SkRasterPipeline::save_xy, sampler);
-
- sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y);
- sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y);
- sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y);
- sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y);
-
- sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y);
- sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y);
- sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y);
- sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y);
-
- sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y);
- sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y);
- sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y);
- sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y);
-
- sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y);
- sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y);
- sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y);
- sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y);
-
- p->append(SkRasterPipeline::move_dst_src);
- }
-
- auto effective_color_type = [](SkColorType ct) {
- return ct == kIndex_8_SkColorType ? kN32_SkColorType : ct;
- };
-
- if (effective_color_type(info.colorType()) == kBGRA_8888_SkColorType) {
- p->append(SkRasterPipeline::swap_rb);
- }
- if (info.colorType() == kAlpha_8_SkColorType) {
- p->append(SkRasterPipeline::set_rgb, &misc->paint_color);
- }
- if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) {
- p->append(SkRasterPipeline::premul);
- }
- if (quality > kLow_SkFilterQuality) {
- // Bicubic filtering naturally produces out of range values on both sides.
- p->append(SkRasterPipeline::clamp_0);
- p->append(SkRasterPipeline::clamp_a);
- }
- append_gamut_transform(p, alloc, info.colorSpace(), dstCS, kPremul_SkAlphaType);
- return true;
-}
diff --git a/src/shaders/SkImageShader.h b/src/shaders/SkImageShader.h
deleted file mode 100644
index 7be982c5c6..0000000000
--- a/src/shaders/SkImageShader.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkImageShader_DEFINED
-#define SkImageShader_DEFINED
-
-#include "SkBitmapProcShader.h"
-#include "SkColorSpaceXformer.h"
-#include "SkImage.h"
-#include "SkShaderBase.h"
-
-class SkImageShader : public SkShaderBase {
-public:
- static sk_sp<SkShader> Make(sk_sp<SkImage>, TileMode tx, TileMode ty,
- const SkMatrix* localMatrix);
-
- bool isOpaque() const override;
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageShader)
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- SkImageShader(sk_sp<SkImage>, TileMode tx, TileMode ty, const SkMatrix* localMatrix);
-
-protected:
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override;
-#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
- bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override;
-#endif
- SkImage* onIsAImage(SkMatrix*, TileMode*) const override;
-
- bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
- const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override;
-
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
- return xformer->apply(fImage.get())->makeShader(fTileModeX, fTileModeY,
- &this->getLocalMatrix());
- }
-
- sk_sp<SkImage> fImage;
- const TileMode fTileModeX;
- const TileMode fTileModeY;
-
-private:
- friend class SkShaderBase;
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkLightingShader.cpp b/src/shaders/SkLightingShader.cpp
deleted file mode 100644
index cdfa528e1e..0000000000
--- a/src/shaders/SkLightingShader.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkArenaAlloc.h"
-#include "SkBitmapProcShader.h"
-#include "SkBitmapProcState.h"
-#include "SkColor.h"
-#include "SkColorSpaceXformer.h"
-#include "SkEmptyShader.h"
-#include "SkLightingShader.h"
-#include "SkMathPriv.h"
-#include "SkNormalSource.h"
-#include "SkPoint3.h"
-#include "SkReadBuffer.h"
-#include "SkShaderBase.h"
-#include "SkWriteBuffer.h"
-
-////////////////////////////////////////////////////////////////////////////
-
-/*
- SkLightingShader TODOs:
- support different light types
- support multiple lights
- fix non-opaque diffuse textures
-
- To Test:
- A8 diffuse textures
- down & upsampled draws
-*/
-
-
-
-/** \class SkLightingShaderImpl
- This subclass of shader applies lighting.
-*/
-class SkLightingShaderImpl : public SkShaderBase {
-public:
- /** Create a new lighting shader that uses the provided normal map and
- lights to light the diffuse bitmap.
- @param diffuseShader the shader that provides the diffuse colors
- @param normalSource the source of normals for lighting computation
- @param lights the lights applied to the geometry
- */
- SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,
- sk_sp<SkNormalSource> normalSource,
- sk_sp<SkLights> lights)
- : fDiffuseShader(std::move(diffuseShader))
- , fNormalSource(std::move(normalSource))
- , fLights(std::move(lights)) {}
-
- bool isOpaque() const override;
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- class LightingShaderContext : public Context {
- public:
- // The context takes ownership of the context and provider. It will call their destructors
- // and then indirectly free their memory by calling free() on heapAllocated
- LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
- SkShaderBase::Context* diffuseContext, SkNormalSource::Provider*,
- void* heapAllocated);
-
- void shadeSpan(int x, int y, SkPMColor[], int count) override;
-
- uint32_t getFlags() const override { return fFlags; }
-
- private:
- SkShaderBase::Context* fDiffuseContext;
- SkNormalSource::Provider* fNormalProvider;
- SkColor fPaintColor;
- uint32_t fFlags;
-
- typedef Context INHERITED;
- };
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl)
-
-protected:
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
-private:
- sk_sp<SkShader> fDiffuseShader;
- sk_sp<SkNormalSource> fNormalSource;
- sk_sp<SkLights> fLights;
-
- friend class SkLightingShader;
-
- typedef SkShaderBase INHERITED;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "GrCoordTransform.h"
-#include "GrFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramDataManager.h"
-#include "glsl/GrGLSLUniformHandler.h"
-#include "SkGr.h"
-
-// This FP expects a premul'd color input for its diffuse color. Premul'ing of the paint's color is
-// handled by the asFragmentProcessor() factory, but shaders providing diffuse color must output it
-// premul'd.
-class LightingFP : public GrFragmentProcessor {
-public:
- LightingFP(sk_sp<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights)
- : INHERITED(kPreservesOpaqueInput_OptimizationFlag) {
- // fuse all ambient lights into a single one
- fAmbientColor = lights->ambientLightColor();
- for (int i = 0; i < lights->numLights(); ++i) {
- if (SkLights::Light::kDirectional_LightType == lights->light(i).type()) {
- fDirectionalLights.push_back(lights->light(i));
- // TODO get the handle to the shadow map if there is one
- } else {
- SkDEBUGFAIL("Unimplemented Light Type passed to LightingFP");
- }
- }
-
- this->registerChildProcessor(std::move(normalFP));
- this->initClassID<LightingFP>();
- }
-
- class GLSLLightingFP : public GrGLSLFragmentProcessor {
- public:
- GLSLLightingFP() {
- fAmbientColor.fX = 0.0f;
- }
-
- void emitCode(EmitArgs& args) override {
-
- GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- const LightingFP& lightingFP = args.fFp.cast<LightingFP>();
-
- const char *lightDirsUniName = nullptr;
- const char *lightColorsUniName = nullptr;
- if (lightingFP.fDirectionalLights.count() != 0) {
- fLightDirsUni = uniformHandler->addUniformArray(
- kFragment_GrShaderFlag,
- kVec3f_GrSLType,
- kDefault_GrSLPrecision,
- "LightDir",
- lightingFP.fDirectionalLights.count(),
- &lightDirsUniName);
- fLightColorsUni = uniformHandler->addUniformArray(
- kFragment_GrShaderFlag,
- kVec3f_GrSLType,
- kDefault_GrSLPrecision,
- "LightColor",
- lightingFP.fDirectionalLights.count(),
- &lightColorsUniName);
- }
-
- const char* ambientColorUniName = nullptr;
- fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec3f_GrSLType, kDefault_GrSLPrecision,
- "AmbientColor", &ambientColorUniName);
-
- fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor);
-
- SkString dstNormalName("dstNormal");
- this->emitChild(0, &dstNormalName, args);
-
- fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str());
-
- fragBuilder->codeAppend( "vec3 result = vec3(0.0);");
-
- // diffuse light
- if (lightingFP.fDirectionalLights.count() != 0) {
- fragBuilder->codeAppendf("for (int i = 0; i < %d; i++) {",
- lightingFP.fDirectionalLights.count());
- // TODO: modulate the contribution from each light based on the shadow map
- fragBuilder->codeAppendf(" float NdotL = clamp(dot(normal, %s[i]), 0.0, 1.0);",
- lightDirsUniName);
- fragBuilder->codeAppendf(" result += %s[i]*diffuseColor.rgb*NdotL;",
- lightColorsUniName);
- fragBuilder->codeAppend("}");
- }
-
- // ambient light
- fragBuilder->codeAppendf("result += %s * diffuseColor.rgb;", ambientColorUniName);
-
- // Clamping to alpha (equivalent to an unpremul'd clamp to 1.0)
- fragBuilder->codeAppendf("%s = vec4(clamp(result.rgb, 0.0, diffuseColor.a), "
- "diffuseColor.a);", args.fOutputColor);
- }
-
- static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- const LightingFP& lightingFP = proc.cast<LightingFP>();
- b->add32(lightingFP.fDirectionalLights.count());
- }
-
- protected:
- void onSetData(const GrGLSLProgramDataManager& pdman,
- const GrFragmentProcessor& proc) override {
- const LightingFP& lightingFP = proc.cast<LightingFP>();
-
- const SkTArray<SkLights::Light>& directionalLights = lightingFP.directionalLights();
- if (directionalLights != fDirectionalLights) {
- SkTArray<SkColor3f> lightDirs(directionalLights.count());
- SkTArray<SkVector3> lightColors(directionalLights.count());
- for (const SkLights::Light& light : directionalLights) {
- lightDirs.push_back(light.dir());
- lightColors.push_back(light.color());
- }
-
- pdman.set3fv(fLightDirsUni, directionalLights.count(), &(lightDirs[0].fX));
- pdman.set3fv(fLightColorsUni, directionalLights.count(), &(lightColors[0].fX));
-
- fDirectionalLights = directionalLights;
- }
-
- const SkColor3f& ambientColor = lightingFP.ambientColor();
- if (ambientColor != fAmbientColor) {
- pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
- fAmbientColor = ambientColor;
- }
- }
-
- private:
- SkTArray<SkLights::Light> fDirectionalLights;
- GrGLSLProgramDataManager::UniformHandle fLightDirsUni;
- GrGLSLProgramDataManager::UniformHandle fLightColorsUni;
-
- SkColor3f fAmbientColor;
- GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
- };
-
- void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
- GLSLLightingFP::GenKey(*this, caps, b);
- }
-
- const char* name() const override { return "LightingFP"; }
-
- const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; }
- const SkColor3f& ambientColor() const { return fAmbientColor; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
-
- bool onIsEqual(const GrFragmentProcessor& proc) const override {
- const LightingFP& lightingFP = proc.cast<LightingFP>();
- return fDirectionalLights == lightingFP.fDirectionalLights &&
- fAmbientColor == lightingFP.fAmbientColor;
- }
-
- SkTArray<SkLights::Light> fDirectionalLights;
- SkColor3f fAmbientColor;
-
- typedef GrFragmentProcessor INHERITED;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> SkLightingShaderImpl::asFragmentProcessor(const AsFPArgs& args) const {
- sk_sp<GrFragmentProcessor> normalFP(fNormalSource->asFragmentProcessor(args));
- if (!normalFP) {
- return nullptr;
- }
-
- if (fDiffuseShader) {
- sk_sp<GrFragmentProcessor> fpPipeline[] = {
- as_SB(fDiffuseShader)->asFragmentProcessor(args),
- sk_make_sp<LightingFP>(std::move(normalFP), fLights)
- };
- if(!fpPipeline[0]) {
- return nullptr;
- }
-
- sk_sp<GrFragmentProcessor> innerLightFP = GrFragmentProcessor::RunInSeries(fpPipeline, 2);
- // FP is wrapped because paint's alpha needs to be applied to output
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(innerLightFP));
- } else {
- // FP is wrapped because paint comes in unpremul'd to fragment shader, but LightingFP
- // expects premul'd color.
- return GrFragmentProcessor::PremulInput(sk_make_sp<LightingFP>(std::move(normalFP),
- fLights));
- }
-}
-
-#endif
-
-////////////////////////////////////////////////////////////////////////////
-
-bool SkLightingShaderImpl::isOpaque() const {
- return (fDiffuseShader ? fDiffuseShader->isOpaque() : false);
-}
-
-SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
- const SkLightingShaderImpl& shader, const ContextRec& rec,
- SkShaderBase::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
- void* heapAllocated)
- : INHERITED(shader, rec)
- , fDiffuseContext(diffuseContext)
- , fNormalProvider(normalProvider) {
- bool isOpaque = shader.isOpaque();
-
- // update fFlags
- uint32_t flags = 0;
- if (isOpaque && (255 == this->getPaintAlpha())) {
- flags |= kOpaqueAlpha_Flag;
- }
-
- fPaintColor = rec.fPaint->getColor();
- fFlags = flags;
-}
-
-static inline SkPMColor convert(SkColor3f color, U8CPU a) {
- if (color.fX <= 0.0f) {
- color.fX = 0.0f;
- } else if (color.fX >= 255.0f) {
- color.fX = 255.0f;
- }
-
- if (color.fY <= 0.0f) {
- color.fY = 0.0f;
- } else if (color.fY >= 255.0f) {
- color.fY = 255.0f;
- }
-
- if (color.fZ <= 0.0f) {
- color.fZ = 0.0f;
- } else if (color.fZ >= 255.0f) {
- color.fZ = 255.0f;
- }
-
- return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ);
-}
-
-// larger is better (fewer times we have to loop), but we shouldn't
-// take up too much stack-space (each one here costs 16 bytes)
-#define BUFFER_MAX 16
-void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
- SkPMColor result[], int count) {
- const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader);
-
- SkPMColor diffuse[BUFFER_MAX];
- SkPoint3 normals[BUFFER_MAX];
-
- SkColor diffColor = fPaintColor;
-
- do {
- int n = SkTMin(count, BUFFER_MAX);
-
- fNormalProvider->fillScanLine(x, y, normals, n);
-
- if (fDiffuseContext) {
- fDiffuseContext->shadeSpan(x, y, diffuse, n);
- }
-
- for (int i = 0; i < n; ++i) {
- if (fDiffuseContext) {
- diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]);
- }
-
- SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f);
-
- // Adding ambient light
- accum.fX += lightShader.fLights->ambientLightColor().fX * SkColorGetR(diffColor);
- accum.fY += lightShader.fLights->ambientLightColor().fY * SkColorGetG(diffColor);
- accum.fZ += lightShader.fLights->ambientLightColor().fZ * SkColorGetB(diffColor);
-
- // This is all done in linear unpremul color space (each component 0..255.0f though)
- for (int l = 0; l < lightShader.fLights->numLights(); ++l) {
- const SkLights::Light& light = lightShader.fLights->light(l);
-
- SkScalar illuminanceScalingFactor = 1.0f;
-
- if (SkLights::Light::kDirectional_LightType == light.type()) {
- illuminanceScalingFactor = normals[i].dot(light.dir());
- if (illuminanceScalingFactor < 0.0f) {
- illuminanceScalingFactor = 0.0f;
- }
- }
-
- accum.fX += light.color().fX * SkColorGetR(diffColor) * illuminanceScalingFactor;
- accum.fY += light.color().fY * SkColorGetG(diffColor) * illuminanceScalingFactor;
- accum.fZ += light.color().fZ * SkColorGetB(diffColor) * illuminanceScalingFactor;
- }
-
- // convert() premultiplies the accumulate color with alpha
- result[i] = convert(accum, SkColorGetA(diffColor));
- }
-
- result += n;
- x += n;
- count -= n;
- } while (count > 0);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-#ifndef SK_IGNORE_TO_STRING
-void SkLightingShaderImpl::toString(SkString* str) const {
- str->appendf("LightingShader: ()");
-}
-#endif
-
-sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
-
- // Discarding SkShader flattenable params
- bool hasLocalMatrix = buf.readBool();
- SkAssertResult(!hasLocalMatrix);
-
- sk_sp<SkLights> lights = SkLights::MakeFromBuffer(buf);
-
- sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>());
-
- bool hasDiffuse = buf.readBool();
- sk_sp<SkShader> diffuseShader = nullptr;
- if (hasDiffuse) {
- diffuseShader = buf.readFlattenable<SkShaderBase>();
- }
-
- return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
- std::move(lights));
-}
-
-void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
- this->INHERITED::flatten(buf);
-
- fLights->flatten(buf);
-
- buf.writeFlattenable(fNormalSource.get());
- buf.writeBool(fDiffuseShader);
- if (fDiffuseShader) {
- buf.writeFlattenable(fDiffuseShader.get());
- }
-}
-
-SkShaderBase::Context* SkLightingShaderImpl::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const
-{
- SkShaderBase::Context *diffuseContext = nullptr;
- if (fDiffuseShader) {
- diffuseContext = as_SB(fDiffuseShader)->makeContext(rec, alloc);
- if (!diffuseContext) {
- return nullptr;
- }
- }
-
- SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, alloc);
- if (!normalProvider) {
- return nullptr;
- }
-
- return alloc->make<LightingShaderContext>(*this, rec, diffuseContext, normalProvider, nullptr);
-}
-
-sk_sp<SkShader> SkLightingShaderImpl::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- sk_sp<SkShader> xformedDiffuseShader =
- fDiffuseShader ? xformer->apply(fDiffuseShader.get()) : nullptr;
- return SkLightingShader::Make(std::move(xformedDiffuseShader), fNormalSource,
- fLights->makeColorSpace(xformer));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader,
- sk_sp<SkNormalSource> normalSource,
- sk_sp<SkLights> lights) {
- SkASSERT(lights);
- if (!normalSource) {
- normalSource = SkNormalSource::MakeFlat();
- }
-
- return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
- std::move(lights));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl)
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-
-///////////////////////////////////////////////////////////////////////////////
diff --git a/src/shaders/SkLightingShader.h b/src/shaders/SkLightingShader.h
deleted file mode 100644
index aa90710aa4..0000000000
--- a/src/shaders/SkLightingShader.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkLightingShader_DEFINED
-#define SkLightingShader_DEFINED
-
-#include "SkLights.h"
-#include "SkShader.h"
-
-class SkBitmap;
-class SkMatrix;
-class SkNormalSource;
-
-class SK_API SkLightingShader {
-public:
- /** Returns a shader that lights the shape, colored by the diffuseShader, using the
- normals from normalSource, with the set of lights provided.
-
- @param diffuseShader the shader that provides the colors. If nullptr, uses the paint's
- color.
- @param normalSource the source for the shape's normals. If nullptr, assumes straight
- up normals (<0,0,1>).
- @param lights the lights applied to the normals
-
- The lighting equation is currently:
- result = (LightColor * dot(Normal, LightDir) + AmbientColor) * DiffuseColor
-
- */
- static sk_sp<SkShader> Make(sk_sp<SkShader> diffuseShader, sk_sp<SkNormalSource> normalSource,
- sk_sp<SkLights> lights);
-
- SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
-};
-
-#endif
diff --git a/src/shaders/SkLocalMatrixShader.cpp b/src/shaders/SkLocalMatrixShader.cpp
deleted file mode 100644
index e21e4a84b7..0000000000
--- a/src/shaders/SkLocalMatrixShader.cpp
+++ /dev/null
@@ -1,110 +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 "SkLocalMatrixShader.h"
-
-#if SK_SUPPORT_GPU
-#include "GrFragmentProcessor.h"
-#endif
-
-#if SK_SUPPORT_GPU
-sk_sp<GrFragmentProcessor> SkLocalMatrixShader::asFragmentProcessor(const AsFPArgs& args) const {
- SkMatrix tmp = this->getLocalMatrix();
- if (args.fLocalMatrix) {
- tmp.preConcat(*args.fLocalMatrix);
- }
- return as_SB(fProxyShader)->asFragmentProcessor(AsFPArgs(
- args.fContext, args.fViewMatrix, &tmp, args.fFilterQuality, args.fDstColorSpace));
-}
-#endif
-
-sk_sp<SkFlattenable> SkLocalMatrixShader::CreateProc(SkReadBuffer& buffer) {
- SkMatrix lm;
- buffer.readMatrix(&lm);
- auto baseShader(buffer.readShader());
- if (!baseShader) {
- return nullptr;
- }
- return baseShader->makeWithLocalMatrix(lm);
-}
-
-void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeMatrix(this->getLocalMatrix());
- buffer.writeFlattenable(fProxyShader.get());
-}
-
-SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const
-{
- ContextRec newRec(rec);
- SkMatrix tmp;
- if (rec.fLocalMatrix) {
- tmp.setConcat(*rec.fLocalMatrix, this->getLocalMatrix());
- newRec.fLocalMatrix = &tmp;
- } else {
- newRec.fLocalMatrix = &this->getLocalMatrix();
- }
- return as_SB(fProxyShader)->makeContext(newRec, alloc);
-}
-
-SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, enum TileMode* mode) const {
- SkMatrix imageMatrix;
- SkImage* image = fProxyShader->isAImage(&imageMatrix, mode);
- if (image && outMatrix) {
- // Local matrix must be applied first so it is on the right side of the concat.
- *outMatrix = SkMatrix::Concat(imageMatrix, this->getLocalMatrix());
- }
-
- return image;
-}
-
-bool SkLocalMatrixShader::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dst,
- SkArenaAlloc* scratch,
- const SkMatrix& ctm,
- const SkPaint& paint,
- const SkMatrix* localM) const {
- SkMatrix tmp;
- if (localM) {
- tmp.setConcat(*localM, this->getLocalMatrix());
- }
- return as_SB(fProxyShader)->appendStages(p, dst, scratch, ctm, paint,
- localM ? &tmp : &this->getLocalMatrix());
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkLocalMatrixShader::toString(SkString* str) const {
- str->append("SkLocalMatrixShader: (");
-
- as_SB(fProxyShader)->toString(str);
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
-
-sk_sp<SkShader> SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const {
- if (localMatrix.isIdentity()) {
- return sk_ref_sp(const_cast<SkShader*>(this));
- }
-
- const SkMatrix* lm = &localMatrix;
-
- sk_sp<SkShader> baseShader;
- SkMatrix otherLocalMatrix;
- sk_sp<SkShader> proxy(as_SB(this)->makeAsALocalMatrixShader(&otherLocalMatrix));
- if (proxy) {
- otherLocalMatrix.preConcat(localMatrix);
- lm = &otherLocalMatrix;
- baseShader = proxy;
- } else {
- baseShader = sk_ref_sp(const_cast<SkShader*>(this));
- }
-
- return sk_make_sp<SkLocalMatrixShader>(std::move(baseShader), *lm);
-}
diff --git a/src/shaders/SkLocalMatrixShader.h b/src/shaders/SkLocalMatrixShader.h
deleted file mode 100644
index 4572e9fe2e..0000000000
--- a/src/shaders/SkLocalMatrixShader.h
+++ /dev/null
@@ -1,75 +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 SkLocalMatrixShader_DEFINED
-#define SkLocalMatrixShader_DEFINED
-
-#include "SkShaderBase.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-
-class GrFragmentProcessor;
-class SkArenaAlloc;
-class SkColorSpaceXformer;
-
-class SkLocalMatrixShader : public SkShaderBase {
-public:
- SkLocalMatrixShader(sk_sp<SkShader> proxy, const SkMatrix& localMatrix)
- : INHERITED(&localMatrix)
- , fProxyShader(std::move(proxy))
- {}
-
- GradientType asAGradient(GradientInfo* info) const override {
- return fProxyShader->asAGradient(info);
- }
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- sk_sp<SkShader> makeAsALocalMatrixShader(SkMatrix* localMatrix) const override {
- if (localMatrix) {
- *localMatrix = this->getLocalMatrix();
- }
- return fProxyShader;
- }
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLocalMatrixShader)
-
-protected:
- void flatten(SkWriteBuffer&) const override;
-
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
-
- SkImage* onIsAImage(SkMatrix* matrix, TileMode* mode) const override;
-
- bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
- const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
-
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
- return as_SB(fProxyShader)->makeColorSpace(xformer)->makeWithLocalMatrix(
- this->getLocalMatrix());
- }
-
-#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
- bool onIsABitmap(SkBitmap* bitmap, SkMatrix* matrix, TileMode* mode) const override {
- return fProxyShader->isABitmap(bitmap, matrix, mode);
- }
-#endif
-
- bool isRasterPipelineOnly() const final {
- return as_SB(fProxyShader)->isRasterPipelineOnly();
- }
-
-private:
- sk_sp<SkShader> fProxyShader;
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif
diff --git a/src/shaders/SkPerlinNoiseShader.cpp b/src/shaders/SkPerlinNoiseShader.cpp
deleted file mode 100644
index 87f8967242..0000000000
--- a/src/shaders/SkPerlinNoiseShader.cpp
+++ /dev/null
@@ -1,1056 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkPerlinNoiseShader.h"
-
-#include "SkArenaAlloc.h"
-#include "SkColorFilter.h"
-#include "SkReadBuffer.h"
-#include "SkShaderBase.h"
-#include "SkString.h"
-#include "SkUnPreMultiply.h"
-#include "SkWriteBuffer.h"
-
-#if SK_SUPPORT_GPU
-#include "GrContext.h"
-#include "GrCoordTransform.h"
-#include "SkGr.h"
-#include "effects/GrConstColorProcessor.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramDataManager.h"
-#include "glsl/GrGLSLUniformHandler.h"
-#endif
-
-static const int kBlockSize = 256;
-static const int kBlockMask = kBlockSize - 1;
-static const int kPerlinNoise = 4096;
-static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
-
-namespace {
-
-// noiseValue is the color component's value (or color)
-// limitValue is the maximum perlin noise array index value allowed
-// newValue is the current noise dimension (either width or height)
-inline int checkNoise(int noiseValue, int limitValue, int newValue) {
- // If the noise value would bring us out of bounds of the current noise array while we are
- // stiching noise tiles together, wrap the noise around the current dimension of the noise to
- // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
- if (noiseValue >= limitValue) {
- noiseValue -= newValue;
- }
- return noiseValue;
-}
-
-inline SkScalar smoothCurve(SkScalar t) {
- return t * t * (3 - 2 * t);
-}
-
-class SkPerlinNoiseShaderImpl final : public SkShaderBase {
-public:
- /**
- * About the noise types : the difference between the 2 is just minor tweaks to the algorithm,
- * they're not 2 entirely different noises. The output looks different, but once the noise is
- * generated in the [1, -1] range, the output is brought back in the [0, 1] range by doing :
- * kFractalNoise_Type : noise * 0.5 + 0.5
- * kTurbulence_Type : abs(noise)
- * Very little differences between the 2 types, although you can tell the difference visually.
- */
- enum Type {
- kFractalNoise_Type,
- kTurbulence_Type,
- kFirstType = kFractalNoise_Type,
- kLastType = kTurbulence_Type
- };
-
- SkPerlinNoiseShaderImpl(Type type, SkScalar baseFrequencyX,
- SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
- const SkISize* tileSize);
- ~SkPerlinNoiseShaderImpl() override = default;
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPerlinNoiseShaderImpl)
-
- struct StitchData;
- struct PaintingData;
-
-protected:
- void flatten(SkWriteBuffer&) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override;
-
-private:
- class PerlinNoiseShaderContext final : public Context {
- public:
- PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
- ~PerlinNoiseShaderContext() override;
-
- void shadeSpan(int x, int y, SkPMColor[], int count) override;
-
- private:
- SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
- SkScalar calculateTurbulenceValueForPoint(
- int channel,
- StitchData& stitchData, const SkPoint& point) const;
- SkScalar noise2D(int channel,
- const StitchData& stitchData, const SkPoint& noiseVector) const;
-
- SkMatrix fMatrix;
- PaintingData* fPaintingData;
-
- typedef Context INHERITED;
- };
-
- const Type fType;
- const SkScalar fBaseFrequencyX;
- const SkScalar fBaseFrequencyY;
- const int fNumOctaves;
- const SkScalar fSeed;
- const SkISize fTileSize;
- const bool fStitchTiles;
-
- friend class ::SkPerlinNoiseShader;
-
- typedef SkShaderBase INHERITED;
-};
-
-} // end namespace
-
-struct SkPerlinNoiseShaderImpl::StitchData {
- StitchData()
- : fWidth(0)
- , fWrapX(0)
- , fHeight(0)
- , fWrapY(0)
- {}
-
- bool operator==(const StitchData& other) const {
- return fWidth == other.fWidth &&
- fWrapX == other.fWrapX &&
- fHeight == other.fHeight &&
- fWrapY == other.fWrapY;
- }
-
- int fWidth; // How much to subtract to wrap for stitching.
- int fWrapX; // Minimum value to wrap.
- int fHeight;
- int fWrapY;
-};
-
-struct SkPerlinNoiseShaderImpl::PaintingData {
- PaintingData(const SkISize& tileSize, SkScalar seed,
- SkScalar baseFrequencyX, SkScalar baseFrequencyY,
- const SkMatrix& matrix)
- {
- SkVector vec[2] = {
- { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) },
- { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) },
- };
- matrix.mapVectors(vec, 2);
-
- fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
- fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
- this->init(seed);
- if (!fTileSize.isEmpty()) {
- this->stitch();
- }
-
-#if SK_SUPPORT_GPU
- fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
- fPermutationsBitmap.setPixels(fLatticeSelector);
-
- fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
- fNoiseBitmap.setPixels(fNoise[0][0]);
-#endif
- }
-
- int fSeed;
- uint8_t fLatticeSelector[kBlockSize];
- uint16_t fNoise[4][kBlockSize][2];
- SkPoint fGradient[4][kBlockSize];
- SkISize fTileSize;
- SkVector fBaseFrequency;
- StitchData fStitchDataInit;
-
-private:
-
-#if SK_SUPPORT_GPU
- SkBitmap fPermutationsBitmap;
- SkBitmap fNoiseBitmap;
-#endif
-
- inline int random() {
- static const int gRandAmplitude = 16807; // 7**5; primitive root of m
- static const int gRandQ = 127773; // m / a
- static const int gRandR = 2836; // m % a
-
- int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
- if (result <= 0)
- result += kRandMaximum;
- fSeed = result;
- return result;
- }
-
- // Only called once. Could be part of the constructor.
- void init(SkScalar seed)
- {
- static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
-
- // According to the SVG spec, we must truncate (not round) the seed value.
- fSeed = SkScalarTruncToInt(seed);
- // The seed value clamp to the range [1, kRandMaximum - 1].
- if (fSeed <= 0) {
- fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
- }
- if (fSeed > kRandMaximum - 1) {
- fSeed = kRandMaximum - 1;
- }
- for (int channel = 0; channel < 4; ++channel) {
- for (int i = 0; i < kBlockSize; ++i) {
- fLatticeSelector[i] = i;
- fNoise[channel][i][0] = (random() % (2 * kBlockSize));
- fNoise[channel][i][1] = (random() % (2 * kBlockSize));
- }
- }
- for (int i = kBlockSize - 1; i > 0; --i) {
- int k = fLatticeSelector[i];
- int j = random() % kBlockSize;
- SkASSERT(j >= 0);
- SkASSERT(j < kBlockSize);
- fLatticeSelector[i] = fLatticeSelector[j];
- fLatticeSelector[j] = k;
- }
-
- // Perform the permutations now
- {
- // Copy noise data
- uint16_t noise[4][kBlockSize][2];
- for (int i = 0; i < kBlockSize; ++i) {
- for (int channel = 0; channel < 4; ++channel) {
- for (int j = 0; j < 2; ++j) {
- noise[channel][i][j] = fNoise[channel][i][j];
- }
- }
- }
- // Do permutations on noise data
- for (int i = 0; i < kBlockSize; ++i) {
- for (int channel = 0; channel < 4; ++channel) {
- for (int j = 0; j < 2; ++j) {
- fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
- }
- }
- }
- }
-
- // Half of the largest possible value for 16 bit unsigned int
- static const SkScalar gHalfMax16bits = 32767.5f;
-
- // Compute gradients from permutated noise data
- for (int channel = 0; channel < 4; ++channel) {
- for (int i = 0; i < kBlockSize; ++i) {
- fGradient[channel][i] = SkPoint::Make(
- (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
- (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
- fGradient[channel][i].normalize();
- // Put the normalized gradient back into the noise data
- fNoise[channel][i][0] = SkScalarRoundToInt(
- (fGradient[channel][i].fX + 1) * gHalfMax16bits);
- fNoise[channel][i][1] = SkScalarRoundToInt(
- (fGradient[channel][i].fY + 1) * gHalfMax16bits);
- }
- }
- }
-
- // Only called once. Could be part of the constructor.
- void stitch() {
- SkScalar tileWidth = SkIntToScalar(fTileSize.width());
- SkScalar tileHeight = SkIntToScalar(fTileSize.height());
- SkASSERT(tileWidth > 0 && tileHeight > 0);
- // When stitching tiled turbulence, the frequencies must be adjusted
- // so that the tile borders will be continuous.
- if (fBaseFrequency.fX) {
- SkScalar lowFrequencx =
- SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
- SkScalar highFrequencx =
- SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
- // BaseFrequency should be non-negative according to the standard.
- if (fBaseFrequency.fX / lowFrequencx < highFrequencx / fBaseFrequency.fX) {
- fBaseFrequency.fX = lowFrequencx;
- } else {
- fBaseFrequency.fX = highFrequencx;
- }
- }
- if (fBaseFrequency.fY) {
- SkScalar lowFrequency =
- SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
- SkScalar highFrequency =
- SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
- if (fBaseFrequency.fY / lowFrequency < highFrequency / fBaseFrequency.fY) {
- fBaseFrequency.fY = lowFrequency;
- } else {
- fBaseFrequency.fY = highFrequency;
- }
- }
- // Set up TurbulenceInitial stitch values.
- fStitchDataInit.fWidth =
- SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
- fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth;
- fStitchDataInit.fHeight =
- SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
- fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight;
- }
-
-public:
-
-#if SK_SUPPORT_GPU
- const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
-
- const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
-#endif
-};
-
-sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
- SkScalar baseFrequencyY,
- int numOctaves, SkScalar seed,
- const SkISize* tileSize) {
- return sk_make_sp<SkPerlinNoiseShaderImpl>(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
- baseFrequencyX, baseFrequencyY, numOctaves,
- seed, tileSize);
-}
-
-sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
- SkScalar baseFrequencyY,
- int numOctaves, SkScalar seed,
- const SkISize* tileSize) {
- return sk_make_sp<SkPerlinNoiseShaderImpl>(SkPerlinNoiseShaderImpl::kTurbulence_Type,
- baseFrequencyX, baseFrequencyY,
- numOctaves, seed, tileSize);
-}
-
-SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(Type type,
- SkScalar baseFrequencyX,
- SkScalar baseFrequencyY,
- int numOctaves,
- SkScalar seed,
- const SkISize* tileSize)
- : fType(type)
- , fBaseFrequencyX(baseFrequencyX)
- , fBaseFrequencyY(baseFrequencyY)
- , fNumOctaves(SkTPin<int>(numOctaves, 0, 255)) // [0,255] octaves allowed
- , fSeed(seed)
- , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
- , fStitchTiles(!fTileSize.isEmpty())
-{
- SkASSERT(fNumOctaves >= 0 && fNumOctaves < 256);
-}
-
-sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
- Type type = (Type)buffer.readInt();
- SkScalar freqX = buffer.readScalar();
- SkScalar freqY = buffer.readScalar();
- int octaves = buffer.readInt();
- SkScalar seed = buffer.readScalar();
- SkISize tileSize;
- tileSize.fWidth = buffer.readInt();
- tileSize.fHeight = buffer.readInt();
-
- switch (type) {
- case kFractalNoise_Type:
- return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed,
- &tileSize);
- case kTurbulence_Type:
- return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed,
- &tileSize);
- default:
- return nullptr;
- }
-}
-
-void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
- buffer.writeInt((int) fType);
- buffer.writeScalar(fBaseFrequencyX);
- buffer.writeScalar(fBaseFrequencyY);
- buffer.writeInt(fNumOctaves);
- buffer.writeScalar(fSeed);
- buffer.writeInt(fTileSize.fWidth);
- buffer.writeInt(fTileSize.fHeight);
-}
-
-SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
- int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
- struct Noise {
- int noisePositionIntegerValue;
- int nextNoisePositionIntegerValue;
- SkScalar noisePositionFractionValue;
- Noise(SkScalar component)
- {
- SkScalar position = component + kPerlinNoise;
- noisePositionIntegerValue = SkScalarFloorToInt(position);
- noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
- nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
- }
- };
- Noise noiseX(noiseVector.x());
- Noise noiseY(noiseVector.y());
- SkScalar u, v;
- const SkPerlinNoiseShaderImpl& perlinNoiseShader =
- static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
- // If stitching, adjust lattice points accordingly.
- if (perlinNoiseShader.fStitchTiles) {
- noiseX.noisePositionIntegerValue =
- checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
- noiseY.noisePositionIntegerValue =
- checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
- noiseX.nextNoisePositionIntegerValue =
- checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
- noiseY.nextNoisePositionIntegerValue =
- checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
- }
- noiseX.noisePositionIntegerValue &= kBlockMask;
- noiseY.noisePositionIntegerValue &= kBlockMask;
- noiseX.nextNoisePositionIntegerValue &= kBlockMask;
- noiseY.nextNoisePositionIntegerValue &= kBlockMask;
- int i =
- fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue];
- int j =
- fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
- int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
- int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
- int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
- int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
- SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
- SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
- if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
- return 0; // Check for pathological inputs.
- }
- // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
- SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
- noiseY.noisePositionFractionValue); // Offset (0,0)
- u = fPaintingData->fGradient[channel][b00].dot(fractionValue);
- fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
- v = fPaintingData->fGradient[channel][b10].dot(fractionValue);
- SkScalar a = SkScalarInterp(u, v, sx);
- fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
- v = fPaintingData->fGradient[channel][b11].dot(fractionValue);
- fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
- u = fPaintingData->fGradient[channel][b01].dot(fractionValue);
- SkScalar b = SkScalarInterp(u, v, sx);
- return SkScalarInterp(a, b, sy);
-}
-
-SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
- int channel, StitchData& stitchData, const SkPoint& point) const {
- const SkPerlinNoiseShaderImpl& perlinNoiseShader =
- static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
- if (perlinNoiseShader.fStitchTiles) {
- // Set up TurbulenceInitial stitch values.
- stitchData = fPaintingData->fStitchDataInit;
- }
- SkScalar turbulenceFunctionResult = 0;
- SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData->fBaseFrequency.fX,
- point.y() * fPaintingData->fBaseFrequency.fY));
- SkScalar ratio = SK_Scalar1;
- for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
- SkScalar noise = noise2D(channel, stitchData, noiseVector);
- SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
- noise : SkScalarAbs(noise);
- turbulenceFunctionResult += numer / ratio;
- noiseVector.fX *= 2;
- noiseVector.fY *= 2;
- ratio *= 2;
- if (perlinNoiseShader.fStitchTiles) {
- // Update stitch values
- stitchData.fWidth *= 2;
- stitchData.fWrapX = stitchData.fWidth + kPerlinNoise;
- stitchData.fHeight *= 2;
- stitchData.fWrapY = stitchData.fHeight + kPerlinNoise;
- }
- }
-
- // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
- // by fractalNoise and (turbulenceFunctionResult) by turbulence.
- if (perlinNoiseShader.fType == kFractalNoise_Type) {
- turbulenceFunctionResult = turbulenceFunctionResult * SK_ScalarHalf + SK_ScalarHalf;
- }
-
- if (channel == 3) { // Scale alpha by paint value
- turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
- }
-
- // Clamp result
- return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
-}
-
-SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
- const SkPoint& point, StitchData& stitchData) const {
- SkPoint newPoint;
- fMatrix.mapPoints(&newPoint, &point, 1);
- newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
- newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
-
- U8CPU rgba[4];
- for (int channel = 3; channel >= 0; --channel) {
- rgba[channel] = SkScalarFloorToInt(255 *
- calculateTurbulenceValueForPoint(channel, stitchData, newPoint));
- }
- return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
-}
-
-SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(
- const ContextRec& rec, SkArenaAlloc* alloc) const {
- return alloc->make<PerlinNoiseShaderContext>(*this, rec);
-}
-
-SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
- const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
- : INHERITED(shader, rec)
-{
- SkMatrix newMatrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
- if (rec.fLocalMatrix) {
- newMatrix.preConcat(*rec.fLocalMatrix);
- }
- // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
- // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
- fMatrix.setTranslate(-newMatrix.getTranslateX() + SK_Scalar1, -newMatrix.getTranslateY() + SK_Scalar1);
- fPaintingData = new PaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
- shader.fBaseFrequencyY, newMatrix);
-}
-
-SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::~PerlinNoiseShaderContext() { delete fPaintingData; }
-
-void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
- int x, int y, SkPMColor result[], int count) {
- SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
- StitchData stitchData;
- for (int i = 0; i < count; ++i) {
- result[i] = shade(point, stitchData);
- point.fX += SK_Scalar1;
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
-public:
- void emitCode(EmitArgs&) override;
-
- static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
-
-protected:
- void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
-private:
- GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
- GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
-
- typedef GrGLSLFragmentProcessor INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////
-
-class GrPerlinNoiseEffect : public GrFragmentProcessor {
-public:
- static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
- SkPerlinNoiseShaderImpl::Type type,
- int numOctaves, bool stitchTiles,
- SkPerlinNoiseShaderImpl::PaintingData* paintingData,
- sk_sp<GrTextureProxy> permutationsProxy,
- sk_sp<GrTextureProxy> noiseProxy,
- const SkMatrix& matrix) {
- return sk_sp<GrFragmentProcessor>(
- new GrPerlinNoiseEffect(resourceProvider, type, numOctaves, stitchTiles, paintingData,
- std::move(permutationsProxy), std::move(noiseProxy), matrix));
- }
-
- ~GrPerlinNoiseEffect() override { delete fPaintingData; }
-
- const char* name() const override { return "PerlinNoise"; }
-
- const SkPerlinNoiseShaderImpl::StitchData& stitchData() const {
- return fPaintingData->fStitchDataInit;
- }
-
- SkPerlinNoiseShaderImpl::Type type() const { return fType; }
- bool stitchTiles() const { return fStitchTiles; }
- const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
- int numOctaves() const { return fNumOctaves; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
- return new GrGLPerlinNoise;
- }
-
- virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const override {
- GrGLPerlinNoise::GenKey(*this, caps, b);
- }
-
- bool onIsEqual(const GrFragmentProcessor& sBase) const override {
- const GrPerlinNoiseEffect& s = sBase.cast<GrPerlinNoiseEffect>();
- return fType == s.fType &&
- fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
- fNumOctaves == s.fNumOctaves &&
- fStitchTiles == s.fStitchTiles &&
- fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
- }
-
- GrPerlinNoiseEffect(GrResourceProvider* resourceProvider,
- SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
- SkPerlinNoiseShaderImpl::PaintingData* paintingData,
- sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
- const SkMatrix& matrix)
- : INHERITED(kNone_OptimizationFlags)
- , fType(type)
- , fCoordTransform(matrix)
- , fNumOctaves(numOctaves)
- , fStitchTiles(stitchTiles)
- , fPermutationsSampler(resourceProvider, std::move(permutationsProxy))
- , fNoiseSampler(resourceProvider, std::move(noiseProxy))
- , fPaintingData(paintingData) {
- this->initClassID<GrPerlinNoiseEffect>();
- this->addTextureSampler(&fPermutationsSampler);
- this->addTextureSampler(&fNoiseSampler);
- this->addCoordTransform(&fCoordTransform);
- }
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
-
- SkPerlinNoiseShaderImpl::Type fType;
- GrCoordTransform fCoordTransform;
- int fNumOctaves;
- bool fStitchTiles;
- TextureSampler fPermutationsSampler;
- TextureSampler fNoiseSampler;
- SkPerlinNoiseShaderImpl::PaintingData *fPaintingData;
-
-private:
- typedef GrFragmentProcessor INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoiseEffect);
-
-#if GR_TEST_UTILS
-sk_sp<GrFragmentProcessor> GrPerlinNoiseEffect::TestCreate(GrProcessorTestData* d) {
- int numOctaves = d->fRandom->nextRangeU(2, 10);
- bool stitchTiles = d->fRandom->nextBool();
- SkScalar seed = SkIntToScalar(d->fRandom->nextU());
- SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
- d->fRandom->nextRangeU(4, 4096));
- SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
- 0.99f);
- SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
- 0.99f);
-
- sk_sp<SkShader> shader(d->fRandom->nextBool() ?
- SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
- stitchTiles ? &tileSize : nullptr) :
- SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
- stitchTiles ? &tileSize : nullptr));
-
- GrTest::TestAsFPArgs asFPArgs(d);
- return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
-}
-#endif
-
-void GrGLPerlinNoise::emitCode(EmitArgs& args) {
- const GrPerlinNoiseEffect& pne = args.fFp.cast<GrPerlinNoiseEffect>();
-
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
-
- fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec2f_GrSLType, kDefault_GrSLPrecision,
- "baseFrequency");
- const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
-
- const char* stitchDataUni = nullptr;
- if (pne.stitchTiles()) {
- fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec2f_GrSLType, kDefault_GrSLPrecision,
- "stitchData");
- stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
- }
-
- // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
- const char* chanCoordR = "0.125";
- const char* chanCoordG = "0.375";
- const char* chanCoordB = "0.625";
- const char* chanCoordA = "0.875";
- const char* chanCoord = "chanCoord";
- const char* stitchData = "stitchData";
- const char* ratio = "ratio";
- const char* noiseVec = "noiseVec";
- const char* noiseSmooth = "noiseSmooth";
- const char* floorVal = "floorVal";
- const char* fractVal = "fractVal";
- const char* uv = "uv";
- const char* ab = "ab";
- const char* latticeIdx = "latticeIdx";
- const char* bcoords = "bcoords";
- const char* lattice = "lattice";
- const char* inc8bit = "0.00390625"; // 1.0 / 256.0
- // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
- // [-1,1] vector and perform a dot product between that vector and the provided vector.
- const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);";
-
- // Add noise function
- static const GrShaderVar gPerlinNoiseArgs[] = {
- GrShaderVar(chanCoord, kFloat_GrSLType),
- GrShaderVar(noiseVec, kVec2f_GrSLType)
- };
-
- static const GrShaderVar gPerlinNoiseStitchArgs[] = {
- GrShaderVar(chanCoord, kFloat_GrSLType),
- GrShaderVar(noiseVec, kVec2f_GrSLType),
- GrShaderVar(stitchData, kVec2f_GrSLType)
- };
-
- SkString noiseCode;
-
- noiseCode.appendf("\tvec4 %s;\n", floorVal);
- noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
- noiseCode.appendf("\t%s.zw = %s.xy + vec2(1.0);\n", floorVal, floorVal);
- noiseCode.appendf("\tvec2 %s = fract(%s);\n", fractVal, noiseVec);
-
- // smooth curve : t * t * (3 - 2 * t)
- noiseCode.appendf("\n\tvec2 %s = %s * %s * (vec2(3.0) - vec2(2.0) * %s);",
- noiseSmooth, fractVal, fractVal, fractVal);
-
- // Adjust frequencies if we're stitching tiles
- if (pne.stitchTiles()) {
- noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
- floorVal, stitchData, floorVal, stitchData);
- noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
- floorVal, stitchData, floorVal, stitchData);
- noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
- floorVal, stitchData, floorVal, stitchData);
- noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
- floorVal, stitchData, floorVal, stitchData);
- }
-
- // Get texture coordinates and normalize
- noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / vec4(256.0));\n",
- floorVal, floorVal);
-
- // Get permutation for x
- {
- SkString xCoords("");
- xCoords.appendf("vec2(%s.x, 0.5)", floorVal);
-
- noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
- fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
- kVec2f_GrSLType);
- noiseCode.append(".r;");
- }
-
- // Get permutation for x + 1
- {
- SkString xCoords("");
- xCoords.appendf("vec2(%s.z, 0.5)", floorVal);
-
- noiseCode.appendf("\n\t%s.y = ", latticeIdx);
- fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
- kVec2f_GrSLType);
- noiseCode.append(".r;");
- }
-
-#if defined(SK_BUILD_FOR_ANDROID)
- // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
- // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
- // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
- // (or 0.484368 here). The following rounding operation prevents these precision issues from
- // affecting the result of the noise by making sure that we only have multiples of 1/255.
- // (Note that 1/255 is about 0.003921569, which is the value used here).
- noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);",
- latticeIdx, latticeIdx);
-#endif
-
- // Get (x,y) coordinates with the permutated x
- noiseCode.appendf("\n\tvec4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
-
- noiseCode.appendf("\n\n\tvec2 %s;", uv);
- // Compute u, at offset (0,0)
- {
- SkString latticeCoords("");
- latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord);
- noiseCode.appendf("\n\tvec4 %s = ", lattice);
- fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
- kVec2f_GrSLType);
- noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
- noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
- }
-
- noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
- // Compute v, at offset (-1,0)
- {
- SkString latticeCoords("");
- latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord);
- noiseCode.append("\n\tlattice = ");
- fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
- kVec2f_GrSLType);
- noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
- noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
- }
-
- // Compute 'a' as a linear interpolation of 'u' and 'v'
- noiseCode.appendf("\n\tvec2 %s;", ab);
- noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
-
- noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
- // Compute v, at offset (-1,-1)
- {
- SkString latticeCoords("");
- latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord);
- noiseCode.append("\n\tlattice = ");
- fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
- kVec2f_GrSLType);
- noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
- noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
- }
-
- noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
- // Compute u, at offset (0,-1)
- {
- SkString latticeCoords("");
- latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord);
- noiseCode.append("\n\tlattice = ");
- fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
- kVec2f_GrSLType);
- noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
- noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
- }
-
- // Compute 'b' as a linear interpolation of 'u' and 'v'
- noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
- // Compute the noise as a linear interpolation of 'a' and 'b'
- noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
-
- SkString noiseFuncName;
- if (pne.stitchTiles()) {
- fragBuilder->emitFunction(kFloat_GrSLType,
- "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
- gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
- } else {
- fragBuilder->emitFunction(kFloat_GrSLType,
- "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
- gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
- }
-
- // There are rounding errors if the floor operation is not performed here
- fragBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
- noiseVec, vCoords.c_str(), baseFrequencyUni);
-
- // Clear the color accumulator
- fragBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", args.fOutputColor);
-
- if (pne.stitchTiles()) {
- // Set up TurbulenceInitial stitch values.
- fragBuilder->codeAppendf("vec2 %s = %s;", stitchData, stitchDataUni);
- }
-
- fragBuilder->codeAppendf("float %s = 1.0;", ratio);
-
- // Loop over all octaves
- fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
-
- fragBuilder->codeAppendf("%s += ", args.fOutputColor);
- if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
- fragBuilder->codeAppend("abs(");
- }
- if (pne.stitchTiles()) {
- fragBuilder->codeAppendf(
- "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
- "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
- noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
- noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
- noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
- noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
- } else {
- fragBuilder->codeAppendf(
- "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
- "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
- noiseFuncName.c_str(), chanCoordR, noiseVec,
- noiseFuncName.c_str(), chanCoordG, noiseVec,
- noiseFuncName.c_str(), chanCoordB, noiseVec,
- noiseFuncName.c_str(), chanCoordA, noiseVec);
- }
- if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
- fragBuilder->codeAppendf(")"); // end of "abs("
- }
- fragBuilder->codeAppendf(" * %s;", ratio);
-
- fragBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
- fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
-
- if (pne.stitchTiles()) {
- fragBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
- }
- fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
-
- if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
- // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
- // by fractalNoise and (turbulenceFunctionResult) by turbulence.
- fragBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);",
- args.fOutputColor,args.fOutputColor);
- }
-
- // Clamp values
- fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
-
- // Pre-multiply the result
- fragBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
- args.fOutputColor, args.fOutputColor,
- args.fOutputColor, args.fOutputColor);
-}
-
-void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
- GrProcessorKeyBuilder* b) {
- const GrPerlinNoiseEffect& turbulence = processor.cast<GrPerlinNoiseEffect>();
-
- uint32_t key = turbulence.numOctaves();
-
- key = key << 3; // Make room for next 3 bits
-
- switch (turbulence.type()) {
- case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
- key |= 0x1;
- break;
- case SkPerlinNoiseShaderImpl::kTurbulence_Type:
- key |= 0x2;
- break;
- default:
- // leave key at 0
- break;
- }
-
- if (turbulence.stitchTiles()) {
- key |= 0x4; // Flip the 3rd bit if tile stitching is on
- }
-
- b->add32(key);
-}
-
-void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
- const GrFragmentProcessor& processor) {
- INHERITED::onSetData(pdman, processor);
-
- const GrPerlinNoiseEffect& turbulence = processor.cast<GrPerlinNoiseEffect>();
-
- const SkVector& baseFrequency = turbulence.baseFrequency();
- pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
-
- if (turbulence.stitchTiles()) {
- const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
- pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
- SkIntToScalar(stitchData.fHeight));
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-sk_sp<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
- const AsFPArgs& args) const {
- SkASSERT(args.fContext);
-
- SkMatrix localMatrix = this->getLocalMatrix();
- if (args.fLocalMatrix) {
- localMatrix.preConcat(*args.fLocalMatrix);
- }
-
- SkMatrix matrix = *args.fViewMatrix;
- matrix.preConcat(localMatrix);
-
- if (0 == fNumOctaves) {
- if (kFractalNoise_Type == fType) {
- // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
- // TODO: Either treat the output of this shader as sRGB or allow client to specify a
- // color space of the noise. Either way, this case (and the GLSL) need to convert to
- // the destination.
- sk_sp<GrFragmentProcessor> inner(
- GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
- GrConstColorProcessor::kModulateRGBA_InputMode));
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
- }
- // Emit zero.
- return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
- GrConstColorProcessor::kIgnore_InputMode);
- }
-
- // Either we don't stitch tiles, either we have a valid tile size
- SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
-
- SkPerlinNoiseShaderImpl::PaintingData* paintingData =
- new PaintingData(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix);
- sk_sp<GrTextureProxy> permutationsProxy(GrMakeCachedBitmapProxy(
- args.fContext->resourceProvider(),
- paintingData->getPermutationsBitmap()));
- sk_sp<GrTextureProxy> noiseProxy(GrMakeCachedBitmapProxy(args.fContext->resourceProvider(),
- paintingData->getNoiseBitmap()));
-
- SkMatrix m = *args.fViewMatrix;
- m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
- m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
- if (permutationsProxy && noiseProxy) {
- sk_sp<GrFragmentProcessor> inner(
- GrPerlinNoiseEffect::Make(args.fContext->resourceProvider(),
- fType,
- fNumOctaves,
- fStitchTiles,
- paintingData,
- std::move(permutationsProxy),
- std::move(noiseProxy),
- m));
- return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
- }
- delete paintingData;
- return nullptr;
-}
-
-#endif
-
-#ifndef SK_IGNORE_TO_STRING
-void SkPerlinNoiseShaderImpl::toString(SkString* str) const {
- str->append("SkPerlinNoiseShader: (");
-
- str->append("type: ");
- switch (fType) {
- case kFractalNoise_Type:
- str->append("\"fractal noise\"");
- break;
- case kTurbulence_Type:
- str->append("\"turbulence\"");
- break;
- default:
- str->append("\"unknown\"");
- break;
- }
- str->append(" base frequency: (");
- str->appendScalar(fBaseFrequencyX);
- str->append(", ");
- str->appendScalar(fBaseFrequencyY);
- str->append(") number of octaves: ");
- str->appendS32(fNumOctaves);
- str->append(" seed: ");
- str->appendScalar(fSeed);
- str->append(" stitch tiles: ");
- str->append(fStitchTiles ? "true " : "false ");
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
-
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/shaders/SkPictureShader.cpp b/src/shaders/SkPictureShader.cpp
deleted file mode 100644
index d6ee941251..0000000000
--- a/src/shaders/SkPictureShader.cpp
+++ /dev/null
@@ -1,364 +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 "SkPictureShader.h"
-
-#include "SkArenaAlloc.h"
-#include "SkBitmap.h"
-#include "SkBitmapProcShader.h"
-#include "SkCanvas.h"
-#include "SkColorSpaceXformCanvas.h"
-#include "SkImage.h"
-#include "SkImageShader.h"
-#include "SkMatrixUtils.h"
-#include "SkPicture.h"
-#include "SkPictureImageGenerator.h"
-#include "SkReadBuffer.h"
-#include "SkResourceCache.h"
-
-#if SK_SUPPORT_GPU
-#include "GrContext.h"
-#include "GrCaps.h"
-#include "GrFragmentProcessor.h"
-#endif
-
-namespace {
-static unsigned gBitmapSkaderKeyNamespaceLabel;
-
-struct BitmapShaderKey : public SkResourceCache::Key {
-public:
- BitmapShaderKey(sk_sp<SkColorSpace> colorSpace,
- uint32_t pictureID,
- const SkRect& tile,
- SkShader::TileMode tmx,
- SkShader::TileMode tmy,
- const SkSize& scale,
- const SkMatrix& localMatrix,
- SkTransferFunctionBehavior blendBehavior)
- : fColorSpace(std::move(colorSpace))
- , fPictureID(pictureID)
- , fTile(tile)
- , fTmx(tmx)
- , fTmy(tmy)
- , fScale(scale)
- , fBlendBehavior(blendBehavior) {
-
- for (int i = 0; i < 9; ++i) {
- fLocalMatrixStorage[i] = localMatrix[i];
- }
-
- static const size_t keySize = sizeof(fColorSpace) +
- sizeof(fPictureID) +
- sizeof(fTile) +
- sizeof(fTmx) + sizeof(fTmy) +
- sizeof(fScale) +
- sizeof(fLocalMatrixStorage) +
- sizeof(fBlendBehavior);
- // This better be packed.
- SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - (uint32_t*)&fColorSpace) == keySize);
- this->init(&gBitmapSkaderKeyNamespaceLabel, 0, keySize);
- }
-
-private:
- sk_sp<SkColorSpace> fColorSpace;
- uint32_t fPictureID;
- SkRect fTile;
- SkShader::TileMode fTmx, fTmy;
- SkSize fScale;
- SkScalar fLocalMatrixStorage[9];
- SkTransferFunctionBehavior fBlendBehavior;
-
- SkDEBUGCODE(uint32_t fEndOfStruct;)
-};
-
-struct BitmapShaderRec : public SkResourceCache::Rec {
- BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader)
- : fKey(key)
- , fShader(SkRef(tileShader)) {}
-
- BitmapShaderKey fKey;
- sk_sp<SkShader> fShader;
- size_t fBitmapBytes;
-
- const Key& getKey() const override { return fKey; }
- size_t bytesUsed() const override {
- // Just the record overhead -- the actual pixels are accounted by SkImageCacherator.
- return sizeof(fKey) + sizeof(SkImageShader);
- }
- const char* getCategory() const override { return "bitmap-shader"; }
- SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
-
- static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
- const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
- sk_sp<SkShader>* result = reinterpret_cast<sk_sp<SkShader>*>(contextShader);
-
- *result = rec.fShader;
-
- // The bitmap shader is backed by an image generator, thus it can always re-generate its
- // pixels if discarded.
- return true;
- }
-};
-
-} // namespace
-
-SkPictureShader::SkPictureShader(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
- const SkMatrix* localMatrix, const SkRect* tile,
- sk_sp<SkColorSpace> colorSpace)
- : INHERITED(localMatrix)
- , fPicture(std::move(picture))
- , fTile(tile ? *tile : fPicture->cullRect())
- , fTmx(tmx)
- , fTmy(tmy)
- , fColorSpace(std::move(colorSpace))
-{}
-
-sk_sp<SkShader> SkPictureShader::Make(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
- const SkMatrix* localMatrix, const SkRect* tile) {
- if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
- return SkShader::MakeEmptyShader();
- }
- return sk_sp<SkShader>(new SkPictureShader(std::move(picture), tmx, tmy, localMatrix, tile,
- nullptr));
-}
-
-sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
- SkMatrix lm;
- buffer.readMatrix(&lm);
- TileMode mx = (TileMode)buffer.read32();
- TileMode my = (TileMode)buffer.read32();
- SkRect tile;
- buffer.readRect(&tile);
-
- sk_sp<SkPicture> picture;
-
- if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
- if (buffer.isVersionLT(SkReadBuffer::kPictureShaderHasPictureBool_Version)) {
- // Older code blindly serialized pictures. We don't trust them.
- buffer.validate(false);
- return nullptr;
- }
- // Newer code won't serialize pictures in disallow-cross-process-picture mode.
- // Assert that they didn't serialize anything except a false here.
- buffer.validate(!buffer.readBool());
- } else {
- // Old code always serialized the picture. New code writes a 'true' first if it did.
- if (buffer.isVersionLT(SkReadBuffer::kPictureShaderHasPictureBool_Version) ||
- buffer.readBool()) {
- picture = SkPicture::MakeFromBuffer(buffer);
- }
- }
- return SkPictureShader::Make(picture, mx, my, &lm, &tile);
-}
-
-void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeMatrix(this->getLocalMatrix());
- buffer.write32(fTmx);
- buffer.write32(fTmy);
- buffer.writeRect(fTile);
-
- // The deserialization code won't trust that our serialized picture is safe to deserialize.
- // So write a 'false' telling it that we're not serializing a picture.
- if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
- buffer.writeBool(false);
- } else {
- buffer.writeBool(true);
- fPicture->flatten(buffer);
- }
-}
-
-sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, const SkMatrix* localM,
- SkColorSpace* dstColorSpace,
- const int maxTextureSize) const {
- SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
-
- SkMatrix m;
- m.setConcat(viewMatrix, this->getLocalMatrix());
- if (localM) {
- m.preConcat(*localM);
- }
-
- // Use a rotation-invariant scale
- SkPoint scale;
- //
- // TODO: replace this with decomposeScale() -- but beware LayoutTest rebaselines!
- //
- if (!SkDecomposeUpper2x2(m, nullptr, &scale, nullptr)) {
- // Decomposition failed, use an approximation.
- scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
- SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
- }
- SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * fTile.width()),
- SkScalarAbs(scale.y() * fTile.height()));
-
- // Clamp the tile size to about 4M pixels
- static const SkScalar kMaxTileArea = 2048 * 2048;
- SkScalar tileArea = scaledSize.width() * scaledSize.height();
- if (tileArea > kMaxTileArea) {
- SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
- scaledSize.set(scaledSize.width() * clampScale,
- scaledSize.height() * clampScale);
- }
-#if SK_SUPPORT_GPU
- // Scale down the tile size if larger than maxTextureSize for GPU Path or it should fail on create texture
- if (maxTextureSize) {
- if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
- SkScalar downScale = maxTextureSize / SkMaxScalar(scaledSize.width(), scaledSize.height());
- scaledSize.set(SkScalarFloorToScalar(scaledSize.width() * downScale),
- SkScalarFloorToScalar(scaledSize.height() * downScale));
- }
- }
-#endif
-
-#ifdef SK_SUPPORT_LEGACY_PICTURESHADER_ROUNDING
- const SkISize tileSize = scaledSize.toRound();
-#else
- const SkISize tileSize = scaledSize.toCeil();
-#endif
- if (tileSize.isEmpty()) {
- return SkShader::MakeEmptyShader();
- }
-
- // The actual scale, compensating for rounding & clamping.
- const SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
- SkIntToScalar(tileSize.height()) / fTile.height());
-
- // |fColorSpace| will only be set when using an SkColorSpaceXformCanvas to do pre-draw xforms.
- // This canvas is strictly for legacy mode. A non-null |dstColorSpace| indicates that we
- // should perform color correct rendering and xform at draw time.
- SkASSERT(!fColorSpace || !dstColorSpace);
- sk_sp<SkColorSpace> keyCS = dstColorSpace ? sk_ref_sp(dstColorSpace) : fColorSpace;
- SkTransferFunctionBehavior blendBehavior = dstColorSpace ? SkTransferFunctionBehavior::kRespect
- : SkTransferFunctionBehavior::kIgnore;
-
- sk_sp<SkShader> tileShader;
- BitmapShaderKey key(std::move(keyCS),
- fPicture->uniqueID(),
- fTile,
- fTmx,
- fTmy,
- tileScale,
- this->getLocalMatrix(),
- blendBehavior);
-
- if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) {
- SkMatrix tileMatrix;
- tileMatrix.setRectToRect(fTile, SkRect::MakeIWH(tileSize.width(), tileSize.height()),
- SkMatrix::kFill_ScaleToFit);
-
- sk_sp<SkImage> tileImage = SkImage::MakeFromGenerator(
- SkPictureImageGenerator::Make(tileSize, fPicture, &tileMatrix, nullptr,
- SkImage::BitDepth::kU8, sk_ref_sp(dstColorSpace)));
- if (!tileImage) {
- return nullptr;
- }
-
- if (fColorSpace) {
- tileImage = tileImage->makeColorSpace(fColorSpace, SkTransferFunctionBehavior::kIgnore);
- }
-
- SkMatrix shaderMatrix = this->getLocalMatrix();
- shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
- tileShader = tileImage->makeShader(fTmx, fTmy, &shaderMatrix);
-
- SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get()));
- }
-
- return tileShader;
-}
-
-bool SkPictureShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc,
- const SkMatrix& ctm, const SkPaint& paint,
- const SkMatrix* localMatrix) const {
- // Keep bitmapShader alive by using alloc instead of stack memory
- auto& bitmapShader = *alloc->make<sk_sp<SkShader>>();
- bitmapShader = this->refBitmapShader(ctm, localMatrix, cs);
- return bitmapShader && as_SB(bitmapShader)->appendStages(p, cs, alloc, ctm, paint);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
-const {
- sk_sp<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix,
- rec.fDstColorSpace));
- if (!bitmapShader) {
- return nullptr;
- }
-
- PictureShaderContext* ctx =
- alloc->make<PictureShaderContext>(*this, rec, std::move(bitmapShader), alloc);
- if (nullptr == ctx->fBitmapShaderContext) {
- ctx = nullptr;
- }
- return ctx;
-}
-
-sk_sp<SkShader> SkPictureShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- return sk_sp<SkPictureShader>(new SkPictureShader(fPicture, fTmx, fTmy, &this->getLocalMatrix(),
- &fTile, xformer->dst()));
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-SkPictureShader::PictureShaderContext::PictureShaderContext(
- const SkPictureShader& shader, const ContextRec& rec, sk_sp<SkShader> bitmapShader,
- SkArenaAlloc* alloc)
- : INHERITED(shader, rec)
- , fBitmapShader(std::move(bitmapShader))
-{
- fBitmapShaderContext = as_SB(fBitmapShader)->makeContext(rec, alloc);
- //if fBitmapShaderContext is null, we are invalid
-}
-
-uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
- SkASSERT(fBitmapShaderContext);
- return fBitmapShaderContext->getFlags();
-}
-
-SkShaderBase::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
- SkASSERT(fBitmapShaderContext);
- return fBitmapShaderContext->asAShadeProc(ctx);
-}
-
-void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- SkASSERT(fBitmapShaderContext);
- fBitmapShaderContext->shadeSpan(x, y, dstC, count);
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkPictureShader::toString(SkString* str) const {
- static const char* gTileModeName[SkShader::kTileModeCount] = {
- "clamp", "repeat", "mirror"
- };
-
- str->appendf("PictureShader: [%f:%f:%f:%f] ",
- fPicture->cullRect().fLeft,
- fPicture->cullRect().fTop,
- fPicture->cullRect().fRight,
- fPicture->cullRect().fBottom);
-
- str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]);
-
- this->INHERITED::toString(str);
-}
-#endif
-
-#if SK_SUPPORT_GPU
-sk_sp<GrFragmentProcessor> SkPictureShader::asFragmentProcessor(const AsFPArgs& args) const {
- int maxTextureSize = 0;
- if (args.fContext) {
- maxTextureSize = args.fContext->caps()->maxTextureSize();
- }
- sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, args.fLocalMatrix,
- args.fDstColorSpace, maxTextureSize));
- if (!bitmapShader) {
- return nullptr;
- }
- return as_SB(bitmapShader)->asFragmentProcessor(SkShaderBase::AsFPArgs(
- args.fContext, args.fViewMatrix, nullptr, args.fFilterQuality, args.fDstColorSpace));
-}
-#endif
diff --git a/src/shaders/SkPictureShader.h b/src/shaders/SkPictureShader.h
deleted file mode 100644
index f7a509f181..0000000000
--- a/src/shaders/SkPictureShader.h
+++ /dev/null
@@ -1,79 +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 SkPictureShader_DEFINED
-#define SkPictureShader_DEFINED
-
-#include "SkShaderBase.h"
-
-class SkArenaAlloc;
-class SkBitmap;
-class SkPicture;
-
-/*
- * An SkPictureShader can be used to draw SkPicture-based patterns.
- *
- * The SkPicture is first rendered into a tile, which is then used to shade the area according
- * to specified tiling rules.
- */
-class SkPictureShader : public SkShaderBase {
-public:
- static sk_sp<SkShader> Make(sk_sp<SkPicture>, TileMode, TileMode, const SkMatrix*,
- const SkRect*);
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureShader)
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
-#endif
-
-protected:
- SkPictureShader(SkReadBuffer&);
- void flatten(SkWriteBuffer&) const override;
- bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
- const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
- Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
- sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
-
-private:
- SkPictureShader(sk_sp<SkPicture>, TileMode, TileMode, const SkMatrix*, const SkRect*,
- sk_sp<SkColorSpace>);
-
- sk_sp<SkShader> refBitmapShader(const SkMatrix&, const SkMatrix* localMatrix,
- SkColorSpace* dstColorSpace,
- const int maxTextureSize = 0) const;
-
- sk_sp<SkPicture> fPicture;
- SkRect fTile;
- TileMode fTmx, fTmy;
-
- class PictureShaderContext : public Context {
- public:
- PictureShaderContext(
- const SkPictureShader&, const ContextRec&, sk_sp<SkShader> bitmapShader, SkArenaAlloc*);
-
- uint32_t getFlags() const override;
-
- ShadeProc asAShadeProc(void** ctx) override;
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
-
- sk_sp<SkShader> fBitmapShader;
- SkShaderBase::Context* fBitmapShaderContext;
- void* fBitmapShaderContextStorage;
-
- typedef Context INHERITED;
- };
-
- // Should never be set by a public constructor. This is only used when onMakeColorSpace()
- // forces a deferred color space xform.
- sk_sp<SkColorSpace> fColorSpace;
-
- typedef SkShaderBase INHERITED;
-};
-
-#endif // SkPictureShader_DEFINED
diff --git a/src/shaders/SkShader.cpp b/src/shaders/SkShader.cpp
deleted file mode 100644
index d04fbfe4df..0000000000
--- a/src/shaders/SkShader.cpp
+++ /dev/null
@@ -1,305 +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 "SkArenaAlloc.h"
-#include "SkAtomics.h"
-#include "SkBitmapProcShader.h"
-#include "SkColorShader.h"
-#include "SkEmptyShader.h"
-#include "SkMallocPixelRef.h"
-#include "SkPaint.h"
-#include "SkPicture.h"
-#include "SkPictureShader.h"
-#include "SkPM4fPriv.h"
-#include "SkRasterPipeline.h"
-#include "SkReadBuffer.h"
-#include "SkScalar.h"
-#include "SkShaderBase.h"
-#include "SkTLazy.h"
-#include "SkWriteBuffer.h"
-#include "../jumper/SkJumper.h"
-
-#if SK_SUPPORT_GPU
-#include "GrFragmentProcessor.h"
-#endif
-
-//#define SK_TRACK_SHADER_LIFETIME
-
-#ifdef SK_TRACK_SHADER_LIFETIME
- static int32_t gShaderCounter;
-#endif
-
-static inline void inc_shader_counter() {
-#ifdef SK_TRACK_SHADER_LIFETIME
- int32_t prev = sk_atomic_inc(&gShaderCounter);
- SkDebugf("+++ shader counter %d\n", prev + 1);
-#endif
-}
-static inline void dec_shader_counter() {
-#ifdef SK_TRACK_SHADER_LIFETIME
- int32_t prev = sk_atomic_dec(&gShaderCounter);
- SkDebugf("--- shader counter %d\n", prev - 1);
-#endif
-}
-
-SkShaderBase::SkShaderBase(const SkMatrix* localMatrix)
- : fLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()) {
- inc_shader_counter();
- // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe.
- (void)fLocalMatrix.getType();
-}
-
-SkShaderBase::~SkShaderBase() {
- dec_shader_counter();
-}
-
-void SkShaderBase::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- bool hasLocalM = !fLocalMatrix.isIdentity();
- buffer.writeBool(hasLocalM);
- if (hasLocalM) {
- buffer.writeMatrix(fLocalMatrix);
- }
-}
-
-bool SkShaderBase::computeTotalInverse(const SkMatrix& ctm,
- const SkMatrix* outerLocalMatrix,
- SkMatrix* totalInverse) const {
- SkMatrix total = SkMatrix::Concat(ctm, fLocalMatrix);
- if (outerLocalMatrix) {
- total.preConcat(*outerLocalMatrix);
- }
-
- return total.invert(totalInverse);
-}
-
-bool SkShaderBase::asLuminanceColor(SkColor* colorPtr) const {
- SkColor storage;
- if (nullptr == colorPtr) {
- colorPtr = &storage;
- }
- if (this->onAsLuminanceColor(colorPtr)) {
- *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque
- return true;
- }
- return false;
-}
-
-SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
- if (!this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr)) {
- return nullptr;
- }
- return this->onMakeContext(rec, alloc);
-}
-
-SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec)
- : fShader(shader), fCTM(*rec.fMatrix)
-{
- // We should never use a context for RP-only shaders.
- SkASSERT(!shader.isRasterPipelineOnly());
-
- // Because the context parameters must be valid at this point, we know that the matrix is
- // invertible.
- SkAssertResult(fShader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &fTotalInverse));
- fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
-
- fPaintAlpha = rec.fPaint->getAlpha();
-}
-
-SkShaderBase::Context::~Context() {}
-
-SkShaderBase::Context::ShadeProc SkShaderBase::Context::asAShadeProc(void** ctx) {
- return nullptr;
-}
-
-void SkShaderBase::Context::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
- const int N = 128;
- SkPMColor tmp[N];
- while (count > 0) {
- int n = SkTMin(count, N);
- this->shadeSpan(x, y, tmp, n);
- for (int i = 0; i < n; ++i) {
- dst[i] = SkPM4f::FromPMColor(tmp[i]);
- }
- dst += n;
- x += n;
- count -= n;
- }
-}
-
-#include "SkColorPriv.h"
-
-#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space
-#define kTempColorCount (kTempColorQuadCount << 2)
-
-#ifdef SK_CPU_BENDIAN
- #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3))
-#else
- #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
-#endif
-
-void SkShaderBase::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
- SkASSERT(count > 0);
-
- SkPMColor colors[kTempColorCount];
-
- while ((count -= kTempColorCount) >= 0) {
- this->shadeSpan(x, y, colors, kTempColorCount);
- x += kTempColorCount;
-
- const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
- int quads = kTempColorQuadCount;
- do {
- U8CPU a0 = srcA[0];
- U8CPU a1 = srcA[4];
- U8CPU a2 = srcA[8];
- U8CPU a3 = srcA[12];
- srcA += 4*4;
- *alpha++ = SkToU8(a0);
- *alpha++ = SkToU8(a1);
- *alpha++ = SkToU8(a2);
- *alpha++ = SkToU8(a3);
- } while (--quads != 0);
- }
- SkASSERT(count < 0);
- SkASSERT(count + kTempColorCount >= 0);
- if (count += kTempColorCount) {
- this->shadeSpan(x, y, colors, count);
-
- const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
- do {
- *alpha++ = *srcA;
- srcA += 4;
- } while (--count != 0);
- }
-#if 0
- do {
- int n = count;
- if (n > kTempColorCount)
- n = kTempColorCount;
- SkASSERT(n > 0);
-
- this->shadeSpan(x, y, colors, n);
- x += n;
- count -= n;
-
- const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
- do {
- *alpha++ = *srcA;
- srcA += 4;
- } while (--n != 0);
- } while (count > 0);
-#endif
-}
-
-SkShaderBase::Context::MatrixClass SkShaderBase::Context::ComputeMatrixClass(const SkMatrix& mat) {
- MatrixClass mc = kLinear_MatrixClass;
-
- if (mat.hasPerspective()) {
- if (mat.isFixedStepInX()) {
- mc = kFixedStepInX_MatrixClass;
- } else {
- mc = kPerspective_MatrixClass;
- }
- }
- return mc;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-const SkMatrix& SkShader::getLocalMatrix() const {
- return as_SB(this)->getLocalMatrix();
-}
-
-#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
-bool SkShader::isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const {
- return as_SB(this)->onIsABitmap(outTexture, outMatrix, xy);
-}
-#endif
-
-SkImage* SkShader::isAImage(SkMatrix* localMatrix, TileMode xy[2]) const {
- return as_SB(this)->onIsAImage(localMatrix, xy);
-}
-
-SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
- return kNone_GradientType;
-}
-
-#if SK_SUPPORT_GPU
-sk_sp<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const AsFPArgs&) const {
- return nullptr;
-}
-#endif
-
-sk_sp<SkShader> SkShader::makeAsALocalMatrixShader(SkMatrix*) const {
- return nullptr;
-}
-
-sk_sp<SkShader> SkShader::MakeEmptyShader() { return sk_make_sp<SkEmptyShader>(); }
-
-sk_sp<SkShader> SkShader::MakeColorShader(SkColor color) { return sk_make_sp<SkColorShader>(color); }
-
-sk_sp<SkShader> SkShader::MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
- const SkMatrix* localMatrix) {
- if (localMatrix && !localMatrix->invert(nullptr)) {
- return nullptr;
- }
- return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode);
-}
-
-sk_sp<SkShader> SkShader::MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy,
- const SkMatrix* localMatrix, const SkRect* tile) {
- if (localMatrix && !localMatrix->invert(nullptr)) {
- return nullptr;
- }
- return SkPictureShader::Make(std::move(src), tmx, tmy, localMatrix, tile);
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkShaderBase::toString(SkString* str) const {
- if (!fLocalMatrix.isIdentity()) {
- str->append(" ");
- fLocalMatrix.toString(str);
- }
-}
-#endif
-
-bool SkShaderBase::appendStages(SkRasterPipeline* p,
- SkColorSpace* dstCS,
- SkArenaAlloc* alloc,
- const SkMatrix& ctm,
- const SkPaint& paint,
- const SkMatrix* localM) const {
- return this->onAppendStages(p, dstCS, alloc, ctm, paint, localM);
-}
-
-bool SkShaderBase::onAppendStages(SkRasterPipeline* p,
- SkColorSpace* dstCS,
- SkArenaAlloc* alloc,
- const SkMatrix& ctm,
- const SkPaint& paint,
- const SkMatrix* localM) const {
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) {
- return SkShader::MakeEmptyShader();
-}
-
-#ifndef SK_IGNORE_TO_STRING
-#include "SkEmptyShader.h"
-
-void SkEmptyShader::toString(SkString* str) const {
- str->append("SkEmptyShader: (");
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
diff --git a/src/shaders/SkShaderBase.h b/src/shaders/SkShaderBase.h
deleted file mode 100644
index 895fc6cf05..0000000000
--- a/src/shaders/SkShaderBase.h
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkShaderBase_DEFINED
-#define SkShaderBase_DEFINED
-
-#include "SkFilterQuality.h"
-#include "SkMatrix.h"
-#include "SkShader.h"
-
-class GrContext;
-class GrFragmentProcessor;
-class SkArenaAlloc;
-class SkColorSpace;
-class SkColorSpaceXformer;
-class SkImage;
-struct SkImageInfo;
-class SkPaint;
-class SkRasterPipeline;
-
-class SkShaderBase : public SkShader {
-public:
- SkShaderBase(const SkMatrix* localMatrix = nullptr);
-
- ~SkShaderBase() override;
-
- /**
- * Returns true if the shader is guaranteed to produce only a single color.
- * Subclasses can override this to allow loop-hoisting optimization.
- */
- virtual bool isConstant() const { return false; }
-
- const SkMatrix& getLocalMatrix() const { return fLocalMatrix; }
-
- enum Flags {
- //!< set if all of the colors will be opaque
- kOpaqueAlpha_Flag = 1 << 0,
-
- /** set if the spans only vary in X (const in Y).
- e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
- that varies from left-to-right. This flag specifies this for
- shadeSpan().
- */
- kConstInY32_Flag = 1 << 1,
-
- /** hint for the blitter that 4f is the preferred shading mode.
- */
- kPrefers4f_Flag = 1 << 2,
- };
-
- /**
- * ContextRec acts as a parameter bundle for creating Contexts.
- */
- struct ContextRec {
- enum DstType {
- kPMColor_DstType, // clients prefer shading into PMColor dest
- kPM4f_DstType, // clients prefer shading into PM4f dest
- };
-
- ContextRec(const SkPaint& paint, const SkMatrix& matrix, const SkMatrix* localM,
- DstType dstType, SkColorSpace* dstColorSpace)
- : fPaint(&paint)
- , fMatrix(&matrix)
- , fLocalMatrix(localM)
- , fPreferredDstType(dstType)
- , fDstColorSpace(dstColorSpace) {}
-
- const SkPaint* fPaint; // the current paint associated with the draw
- const SkMatrix* fMatrix; // the current matrix in the canvas
- const SkMatrix* fLocalMatrix; // optional local matrix
- const DstType fPreferredDstType; // the "natural" client dest type
- SkColorSpace* fDstColorSpace; // the color space of the dest surface (if any)
- };
-
- class Context : public ::SkNoncopyable {
- public:
- Context(const SkShaderBase& shader, const ContextRec&);
-
- virtual ~Context();
-
- /**
- * Called sometimes before drawing with this shader. Return the type of
- * alpha your shader will return. The default implementation returns 0.
- * Your subclass should override if it can (even sometimes) report a
- * non-zero value, since that will enable various blitters to perform
- * faster.
- */
- virtual uint32_t getFlags() const { return 0; }
-
- /**
- * Called for each span of the object being drawn. Your subclass should
- * set the appropriate colors (with premultiplied alpha) that correspond
- * to the specified device coordinates.
- */
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
-
- virtual void shadeSpan4f(int x, int y, SkPM4f[], int count);
-
- struct BlitState;
- typedef void (*BlitBW)(BlitState*,
- int x, int y, const SkPixmap&, int count);
- typedef void (*BlitAA)(BlitState*,
- int x, int y, const SkPixmap&, int count, const SkAlpha[]);
-
- struct BlitState {
- // inputs
- Context* fCtx;
- SkBlendMode fMode;
-
- // outputs
- enum { N = 2 };
- void* fStorage[N];
- BlitBW fBlitBW;
- BlitAA fBlitAA;
- };
-
- // Returns true if one or more of the blitprocs are set in the BlitState
- bool chooseBlitProcs(const SkImageInfo& info, BlitState* state) {
- state->fBlitBW = nullptr;
- state->fBlitAA = nullptr;
- if (this->onChooseBlitProcs(info, state)) {
- SkASSERT(state->fBlitBW || state->fBlitAA);
- return true;
- }
- return false;
- }
-
- /**
- * The const void* ctx is only const because all the implementations are const.
- * This can be changed to non-const if a new shade proc needs to change the ctx.
- */
- typedef void (*ShadeProc)(const void* ctx, int x, int y, SkPMColor[], int count);
- virtual ShadeProc asAShadeProc(void** ctx);
-
- /**
- * Similar to shadeSpan, but only returns the alpha-channel for a span.
- * The default implementation calls shadeSpan() and then extracts the alpha
- * values from the returned colors.
- */
- virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
-
- // Notification from blitter::blitMask in case we need to see the non-alpha channels
- virtual void set3DMask(const SkMask*) {}
-
- protected:
- // Reference to shader, so we don't have to dupe information.
- const SkShaderBase& fShader;
-
- enum MatrixClass {
- kLinear_MatrixClass, // no perspective
- kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each
- // scanline
- kPerspective_MatrixClass // slow perspective, need to mappoints each pixel
- };
- static MatrixClass ComputeMatrixClass(const SkMatrix&);
-
- uint8_t getPaintAlpha() const { return fPaintAlpha; }
- const SkMatrix& getTotalInverse() const { return fTotalInverse; }
- MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
- const SkMatrix& getCTM() const { return fCTM; }
-
- virtual bool onChooseBlitProcs(const SkImageInfo&, BlitState*) { return false; }
-
- private:
- SkMatrix fCTM;
- SkMatrix fTotalInverse;
- uint8_t fPaintAlpha;
- uint8_t fTotalInverseClass;
-
- typedef SkNoncopyable INHERITED;
- };
-
- /**
- * Make a context using the memory provided by the arena.
- *
- * @return pointer to context or nullptr if can't be created
- */
- Context* makeContext(const ContextRec&, SkArenaAlloc*) const;
-
-#if SK_SUPPORT_GPU
- struct AsFPArgs {
- AsFPArgs() {}
- AsFPArgs(GrContext* context,
- const SkMatrix* viewMatrix,
- const SkMatrix* localMatrix,
- SkFilterQuality filterQuality,
- SkColorSpace* dstColorSpace)
- : fContext(context)
- , fViewMatrix(viewMatrix)
- , fLocalMatrix(localMatrix)
- , fFilterQuality(filterQuality)
- , fDstColorSpace(dstColorSpace) {}
-
- GrContext* fContext;
- const SkMatrix* fViewMatrix;
- const SkMatrix* fLocalMatrix;
- SkFilterQuality fFilterQuality;
- SkColorSpace* fDstColorSpace;
- };
-
- /**
- * Returns a GrFragmentProcessor that implements the shader for the GPU backend. NULL is
- * returned if there is no GPU implementation.
- *
- * The GPU device does not call SkShader::createContext(), instead we pass the view matrix,
- * local matrix, and filter quality directly.
- *
- * The GrContext may be used by the to create textures that are required by the returned
- * processor.
- *
- * The returned GrFragmentProcessor should expect an unpremultiplied input color and
- * produce a premultiplied output.
- */
- virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const;
-#endif
-
- /**
- * If the shader can represent its "average" luminance in a single color, return true and
- * if color is not NULL, return that color. If it cannot, return false and ignore the color
- * parameter.
- *
- * Note: if this returns true, the returned color will always be opaque, as only the RGB
- * components are used to compute luminance.
- */
- bool asLuminanceColor(SkColor*) const;
-
- /**
- * Returns a shader transformed into a new color space via the |xformer|.
- */
- sk_sp<SkShader> makeColorSpace(SkColorSpaceXformer* xformer) const {
- return this->onMakeColorSpace(xformer);
- }
-
- virtual bool isRasterPipelineOnly() const { return false; }
-
- bool appendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
- const SkMatrix& ctm, const SkPaint&, const SkMatrix* localM=nullptr) const;
-
- bool computeTotalInverse(const SkMatrix& ctm,
- const SkMatrix* outerLocalMatrix,
- SkMatrix* totalInverse) const;
-
-#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
- virtual bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode[2]) const {
- return false;
- }
-#endif
-
- virtual SkImage* onIsAImage(SkMatrix*, TileMode[2]) const {
- return nullptr;
- }
-
- SK_TO_STRING_VIRT()
-
- SK_DEFINE_FLATTENABLE_TYPE(SkShaderBase)
- SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
-
-protected:
- void flatten(SkWriteBuffer&) const override;
-
- /**
- * Specialize creating a SkShader context using the supplied allocator.
- * @return pointer to context owned by the arena allocator.
- */
- virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const {
- return nullptr;
- }
-
- virtual bool onAsLuminanceColor(SkColor*) const {
- return false;
- }
-
- virtual sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer*) const {
- return sk_ref_sp(const_cast<SkShaderBase*>(this));
- }
-
- virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
- const SkMatrix&, const SkPaint&, const SkMatrix* localM) const;
-
-private:
- // This is essentially const, but not officially so it can be modified in constructors.
- SkMatrix fLocalMatrix;
-
- typedef SkShader INHERITED;
-};
-
-inline SkShaderBase* as_SB(SkShader* shader) {
- return static_cast<SkShaderBase*>(shader);
-}
-
-inline const SkShaderBase* as_SB(const SkShader* shader) {
- return static_cast<const SkShaderBase*>(shader);
-}
-
-inline const SkShaderBase* as_SB(const sk_sp<SkShader>& shader) {
- return static_cast<SkShaderBase*>(shader.get());
-}
-
-#endif // SkShaderBase_DEFINED
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