blob: 1f4114e16369334bd38d49a5e66306ab5fcc6afd [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Florin Malita9206c762017-01-30 12:08:05 -05008#include "SkArenaAlloc.h"
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +00009#include "SkBitmapProcShader.h"
reed8367b8c2014-08-22 08:30:20 -070010#include "SkColorShader.h"
Mike Reed5800f2e2019-03-03 22:12:51 +000011#include "SkColorSpacePriv.h"
Florin Malita47e55a52017-06-06 12:26:54 -040012#include "SkColorSpaceXformer.h"
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +000013#include "SkEmptyShader.h"
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +000014#include "SkMallocPixelRef.h"
15#include "SkPaint.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000016#include "SkPicture.h"
17#include "SkPictureShader.h"
Florin Malita9206c762017-01-30 12:08:05 -050018#include "SkRasterPipeline.h"
mtklein1b249332015-07-07 12:21:21 -070019#include "SkReadBuffer.h"
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +000020#include "SkScalar.h"
Florin Malita4aed1382017-05-25 10:38:07 -040021#include "SkShaderBase.h"
Florin Malita9206c762017-01-30 12:08:05 -050022#include "SkTLazy.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000023#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
bungeman06ca8ec2016-06-09 08:01:03 -070025#if SK_SUPPORT_GPU
26#include "GrFragmentProcessor.h"
27#endif
28
Florin Malita4aed1382017-05-25 10:38:07 -040029SkShaderBase::SkShaderBase(const SkMatrix* localMatrix)
30 : fLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()) {
mtklein435eba72014-12-01 12:06:24 -080031 // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe.
32 (void)fLocalMatrix.getType();
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
Mike Kleinde2244c2018-12-04 11:16:08 -050035SkShaderBase::~SkShaderBase() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000036
Florin Malita4aed1382017-05-25 10:38:07 -040037void SkShaderBase::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 this->INHERITED::flatten(buffer);
commit-bot@chromium.org5970f622014-05-12 20:42:21 +000039 bool hasLocalM = !fLocalMatrix.isIdentity();
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000040 buffer.writeBool(hasLocalM);
41 if (hasLocalM) {
42 buffer.writeMatrix(fLocalMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 }
44}
45
Florin Malitac6c5ead2018-04-11 15:33:40 -040046SkTCopyOnFirstWrite<SkMatrix>
47SkShaderBase::totalLocalMatrix(const SkMatrix* preLocalMatrix,
48 const SkMatrix* postLocalMatrix) const {
49 SkTCopyOnFirstWrite<SkMatrix> m(fLocalMatrix);
50
51 if (preLocalMatrix) {
52 m.writable()->preConcat(*preLocalMatrix);
53 }
54
55 if (postLocalMatrix) {
56 m.writable()->postConcat(*postLocalMatrix);
57 }
58
59 return m;
60}
61
Florin Malita4aed1382017-05-25 10:38:07 -040062bool SkShaderBase::computeTotalInverse(const SkMatrix& ctm,
63 const SkMatrix* outerLocalMatrix,
64 SkMatrix* totalInverse) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -040065 return SkMatrix::Concat(ctm, *this->totalLocalMatrix(outerLocalMatrix)).invert(totalInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +000066}
67
Florin Malita4aed1382017-05-25 10:38:07 -040068bool SkShaderBase::asLuminanceColor(SkColor* colorPtr) const {
reed8367b8c2014-08-22 08:30:20 -070069 SkColor storage;
halcanary96fcdcc2015-08-27 07:41:13 -070070 if (nullptr == colorPtr) {
reed8367b8c2014-08-22 08:30:20 -070071 colorPtr = &storage;
72 }
73 if (this->onAsLuminanceColor(colorPtr)) {
74 *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque
75 return true;
76 }
77 return false;
78}
79
Florin Malita4aed1382017-05-25 10:38:07 -040080SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
Mike Reede92aae62018-10-17 10:21:51 -040081#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Florin Malitaaf2769d2018-04-04 13:46:35 -040082 // We always fall back to raster pipeline when perspective is present.
83 if (rec.fMatrix->hasPerspective() ||
84 fLocalMatrix.hasPerspective() ||
85 (rec.fLocalMatrix && rec.fLocalMatrix->hasPerspective()) ||
86 !this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr)) {
87 return nullptr;
88 }
89
90 return this->onMakeContext(rec, alloc);
Mike Reede92aae62018-10-17 10:21:51 -040091#else
92 return nullptr;
93#endif
commit-bot@chromium.orgf3e50592014-04-30 23:29:02 +000094}
95
Florin Malita4aed1382017-05-25 10:38:07 -040096SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec)
commit-bot@chromium.org80116dc2014-05-06 17:16:03 +000097 : fShader(shader), fCTM(*rec.fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000098{
Florin Malitaaf2769d2018-04-04 13:46:35 -040099 // We should never use a context with perspective.
Florin Malita5769dd22017-07-12 13:31:25 -0400100 SkASSERT(!rec.fMatrix->hasPerspective());
101 SkASSERT(!rec.fLocalMatrix || !rec.fLocalMatrix->hasPerspective());
Florin Malitaaf2769d2018-04-04 13:46:35 -0400102 SkASSERT(!shader.getLocalMatrix().hasPerspective());
Florin Malita7d022e02017-05-15 15:06:39 -0400103
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000104 // Because the context parameters must be valid at this point, we know that the matrix is
105 // invertible.
Florin Malita26368c32017-05-08 13:03:24 -0400106 SkAssertResult(fShader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &fTotalInverse));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000107
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000108 fPaintAlpha = rec.fPaint->getAlpha();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000109}
110
Florin Malita4aed1382017-05-25 10:38:07 -0400111SkShaderBase::Context::~Context() {}
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000112
Mike Reed011d1662019-02-28 17:19:25 -0500113bool SkShaderBase::ContextRec::isLegacyCompatible(SkColorSpace* shaderColorSpace) const {
Mike Reed5800f2e2019-03-03 22:12:51 +0000114 return sk_can_use_legacy_blits(shaderColorSpace, fDstColorSpace);
Mike Reed011d1662019-02-28 17:19:25 -0500115}
116
Florin Malita4aed1382017-05-25 10:38:07 -0400117const SkMatrix& SkShader::getLocalMatrix() const {
118 return as_SB(this)->getLocalMatrix();
119}
120
Florin Malita4aed1382017-05-25 10:38:07 -0400121SkImage* SkShader::isAImage(SkMatrix* localMatrix, TileMode xy[2]) const {
122 return as_SB(this)->onIsAImage(localMatrix, xy);
123}
124
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000125SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
126 return kNone_GradientType;
127}
128
bungeman06ca8ec2016-06-09 08:01:03 -0700129#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500130std::unique_ptr<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const GrFPArgs&) const {
bsalomonc21b09e2015-08-28 18:46:56 -0700131 return nullptr;
rileya@google.com03c1c352012-07-20 20:02:43 +0000132}
bungeman06ca8ec2016-06-09 08:01:03 -0700133#endif
rileya@google.com03c1c352012-07-20 20:02:43 +0000134
Florin Malitad93e11c2017-05-24 21:15:46 +0000135sk_sp<SkShader> SkShader::makeAsALocalMatrixShader(SkMatrix*) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700136 return nullptr;
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000137}
138
reed8a21c9f2016-03-08 18:50:00 -0800139sk_sp<SkShader> SkShader::MakeEmptyShader() { return sk_make_sp<SkEmptyShader>(); }
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000140
reed8a21c9f2016-03-08 18:50:00 -0800141sk_sp<SkShader> SkShader::MakeColorShader(SkColor color) { return sk_make_sp<SkColorShader>(color); }
reed8367b8c2014-08-22 08:30:20 -0700142
reed8a21c9f2016-03-08 18:50:00 -0800143sk_sp<SkShader> SkShader::MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
144 const SkMatrix* localMatrix) {
Florin Malita8d3ffad2017-02-03 18:21:17 +0000145 if (localMatrix && !localMatrix->invert(nullptr)) {
146 return nullptr;
147 }
Herb Derbybfdc87a2017-02-14 15:06:23 +0000148 return SkMakeBitmapShader(src, tmx, tmy, localMatrix, kIfMutable_SkCopyPixelsMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149}
150
reed7fb4f8b2016-03-11 04:33:52 -0800151sk_sp<SkShader> SkShader::MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy,
reed8a21c9f2016-03-08 18:50:00 -0800152 const SkMatrix* localMatrix, const SkRect* tile) {
Florin Malita8d3ffad2017-02-03 18:21:17 +0000153 if (localMatrix && !localMatrix->invert(nullptr)) {
154 return nullptr;
155 }
reed8a21c9f2016-03-08 18:50:00 -0800156 return SkPictureShader::Make(std::move(src), tmx, tmy, localMatrix, tile);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000157}
158
Mike Reed1d8c42e2017-08-29 14:58:19 -0400159bool SkShaderBase::appendStages(const StageRec& rec) const {
160 return this->onAppendStages(rec);
Florin Malita9206c762017-01-30 12:08:05 -0500161}
162
Mike Reed1d8c42e2017-08-29 14:58:19 -0400163bool SkShaderBase::onAppendStages(const StageRec& rec) const {
Mike Klein541cbd42019-01-30 13:11:33 -0500164 // SkShader::Context::shadeSpan() handles the paint opacity internally,
Mike Reed6867eee2017-06-02 13:25:15 -0400165 // but SkRasterPipelineBlitter applies it as a separate stage.
Mike Klein541cbd42019-01-30 13:11:33 -0500166 // We skip the internal shadeSpan() step by forcing the paint opaque.
Mike Reed1d8c42e2017-08-29 14:58:19 -0400167 SkTCopyOnFirstWrite<SkPaint> opaquePaint(rec.fPaint);
168 if (rec.fPaint.getAlpha() != SK_AlphaOPAQUE) {
Mike Reed6867eee2017-06-02 13:25:15 -0400169 opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE);
170 }
171
Brian Osman2e8f48e2018-10-19 13:50:48 -0400172 ContextRec cr(*opaquePaint, rec.fCTM, rec.fLocalM, rec.fDstColorType, rec.fDstCS);
Mike Reed6867eee2017-06-02 13:25:15 -0400173
Mike Kleinb11ab572018-10-24 06:42:14 -0400174 struct CallbackCtx : SkRasterPipeline_CallbackCtx {
Mike Reed6867eee2017-06-02 13:25:15 -0400175 sk_sp<SkShader> shader;
176 Context* ctx;
177 };
Mike Reed1d8c42e2017-08-29 14:58:19 -0400178 auto cb = rec.fAlloc->make<CallbackCtx>();
179 cb->shader = rec.fDstCS ? SkColorSpaceXformer::Make(sk_ref_sp(rec.fDstCS))->apply(this)
180 : sk_ref_sp((SkShader*)this);
181 cb->ctx = as_SB(cb->shader)->makeContext(cr, rec.fAlloc);
Mike Kleinb11ab572018-10-24 06:42:14 -0400182 cb->fn = [](SkRasterPipeline_CallbackCtx* self, int active_pixels) {
Mike Reed6867eee2017-06-02 13:25:15 -0400183 auto c = (CallbackCtx*)self;
184 int x = (int)c->rgba[0],
Mike Klein541cbd42019-01-30 13:11:33 -0500185 y = (int)c->rgba[1];
186 SkPMColor tmp[SkRasterPipeline_kMaxStride];
187 c->ctx->shadeSpan(x,y, tmp, active_pixels);
188
189 for (int i = 0; i < active_pixels; i++) {
190 auto rgba_4f = SkPMColor4f::FromPMColor(tmp[i]);
191 memcpy(c->rgba + 4*i, rgba_4f.vec(), 4*sizeof(float));
192 }
Mike Reed6867eee2017-06-02 13:25:15 -0400193 };
194
195 if (cb->ctx) {
Mike Kleine8de0242018-03-10 12:37:11 -0500196 rec.fPipeline->append(SkRasterPipeline::seed_shader);
Mike Reed1d8c42e2017-08-29 14:58:19 -0400197 rec.fPipeline->append(SkRasterPipeline::callback, cb);
Mike Reed6867eee2017-06-02 13:25:15 -0400198 return true;
199 }
Mike Klein44d32792017-05-10 12:29:38 -0400200 return false;
201}
202
reed0ccc62d2016-05-04 13:09:39 -0700203///////////////////////////////////////////////////////////////////////////////////////////////////
reed830dfd82016-03-16 12:29:01 -0700204
reed60c9b582016-04-03 09:11:13 -0700205sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) {
206 return SkShader::MakeEmptyShader();
reed9fa60da2014-08-21 07:59:51 -0700207}