blob: 7455488115be59937dee97957462b0e6bc7020ae [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkMallocPixelRef.h"
9#include "include/core/SkPaint.h"
10#include "include/core/SkPicture.h"
11#include "include/core/SkScalar.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040012#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkColorSpacePriv.h"
14#include "src/core/SkColorSpaceXformSteps.h"
15#include "src/core/SkRasterPipeline.h"
16#include "src/core/SkReadBuffer.h"
17#include "src/core/SkTLazy.h"
18#include "src/core/SkWriteBuffer.h"
19#include "src/shaders/SkBitmapProcShader.h"
20#include "src/shaders/SkColorShader.h"
21#include "src/shaders/SkEmptyShader.h"
22#include "src/shaders/SkPictureShader.h"
23#include "src/shaders/SkShaderBase.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
bungeman06ca8ec2016-06-09 08:01:03 -070025#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/GrFragmentProcessor.h"
bungeman06ca8ec2016-06-09 08:01:03 -070027#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 Kleina7bb87e2019-12-03 11:04:54 -0600114 // In legacy pipelines, shaders always produce premul (or opaque) and the destination is also
115 // always premul (or opaque). (And those "or opaque" caveats won't make any difference here.)
116 SkAlphaType shaderAT = kPremul_SkAlphaType,
117 dstAT = kPremul_SkAlphaType;
118 return 0 == SkColorSpaceXformSteps{shaderColorSpace, shaderAT,
119 fDstColorSpace, dstAT}.flags.mask();
Mike Reed011d1662019-02-28 17:19:25 -0500120}
121
Mike Reedfae8fce2019-04-03 10:27:45 -0400122SkImage* SkShader::isAImage(SkMatrix* localMatrix, SkTileMode xy[2]) const {
Florin Malita4aed1382017-05-25 10:38:07 -0400123 return as_SB(this)->onIsAImage(localMatrix, xy);
124}
125
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000126SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
127 return kNone_GradientType;
128}
129
bungeman06ca8ec2016-06-09 08:01:03 -0700130#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500131std::unique_ptr<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const GrFPArgs&) const {
bsalomonc21b09e2015-08-28 18:46:56 -0700132 return nullptr;
rileya@google.com03c1c352012-07-20 20:02:43 +0000133}
bungeman06ca8ec2016-06-09 08:01:03 -0700134#endif
rileya@google.com03c1c352012-07-20 20:02:43 +0000135
Mike Reed7656b2c2019-04-08 11:48:20 -0400136sk_sp<SkShader> SkShaderBase::makeAsALocalMatrixShader(SkMatrix*) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700137 return nullptr;
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000138}
139
Mike Reedc8bea7d2019-04-09 13:55:36 -0400140sk_sp<SkShader> SkShaders::Empty() { return sk_make_sp<SkEmptyShader>(); }
141sk_sp<SkShader> SkShaders::Color(SkColor color) { return sk_make_sp<SkColorShader>(color); }
reed8367b8c2014-08-22 08:30:20 -0700142
Mike Reed50acf8f2019-04-08 13:20:23 -0400143sk_sp<SkShader> SkBitmap::makeShader(SkTileMode tmx, SkTileMode tmy, const SkMatrix* lm) const {
144 if (lm && !lm->invert(nullptr)) {
145 return nullptr;
146 }
147 return SkMakeBitmapShader(*this, tmx, tmy, lm, kIfMutable_SkCopyPixelsMode);
148}
149
150sk_sp<SkShader> SkBitmap::makeShader(const SkMatrix* lm) const {
151 return this->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, lm);
152}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153
Mike Reed1386b2d2019-03-13 21:15:05 -0400154bool SkShaderBase::appendStages(const SkStageRec& rec) const {
Mike Reed1d8c42e2017-08-29 14:58:19 -0400155 return this->onAppendStages(rec);
Florin Malita9206c762017-01-30 12:08:05 -0500156}
157
Mike Reed1386b2d2019-03-13 21:15:05 -0400158bool SkShaderBase::onAppendStages(const SkStageRec& rec) const {
Mike Klein541cbd42019-01-30 13:11:33 -0500159 // SkShader::Context::shadeSpan() handles the paint opacity internally,
Mike Reed6867eee2017-06-02 13:25:15 -0400160 // but SkRasterPipelineBlitter applies it as a separate stage.
Mike Klein541cbd42019-01-30 13:11:33 -0500161 // We skip the internal shadeSpan() step by forcing the paint opaque.
Mike Reed1d8c42e2017-08-29 14:58:19 -0400162 SkTCopyOnFirstWrite<SkPaint> opaquePaint(rec.fPaint);
163 if (rec.fPaint.getAlpha() != SK_AlphaOPAQUE) {
Mike Reed6867eee2017-06-02 13:25:15 -0400164 opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE);
165 }
166
Mike Klein894328d2019-03-21 10:06:38 -0500167 ContextRec cr(*opaquePaint, rec.fCTM, rec.fLocalM, rec.fDstColorType, sk_srgb_singleton());
Mike Reed6867eee2017-06-02 13:25:15 -0400168
Mike Kleinb11ab572018-10-24 06:42:14 -0400169 struct CallbackCtx : SkRasterPipeline_CallbackCtx {
Mike Kleinb0b2c962019-03-21 10:33:51 -0500170 sk_sp<const SkShader> shader;
171 Context* ctx;
Mike Reed6867eee2017-06-02 13:25:15 -0400172 };
Mike Reed1d8c42e2017-08-29 14:58:19 -0400173 auto cb = rec.fAlloc->make<CallbackCtx>();
Mike Kleinb0b2c962019-03-21 10:33:51 -0500174 cb->shader = sk_ref_sp(this);
175 cb->ctx = as_SB(this)->makeContext(cr, rec.fAlloc);
Mike Kleinb11ab572018-10-24 06:42:14 -0400176 cb->fn = [](SkRasterPipeline_CallbackCtx* self, int active_pixels) {
Mike Reed6867eee2017-06-02 13:25:15 -0400177 auto c = (CallbackCtx*)self;
178 int x = (int)c->rgba[0],
Mike Klein541cbd42019-01-30 13:11:33 -0500179 y = (int)c->rgba[1];
180 SkPMColor tmp[SkRasterPipeline_kMaxStride];
181 c->ctx->shadeSpan(x,y, tmp, active_pixels);
182
183 for (int i = 0; i < active_pixels; i++) {
184 auto rgba_4f = SkPMColor4f::FromPMColor(tmp[i]);
185 memcpy(c->rgba + 4*i, rgba_4f.vec(), 4*sizeof(float));
186 }
Mike Reed6867eee2017-06-02 13:25:15 -0400187 };
188
189 if (cb->ctx) {
Mike Kleine8de0242018-03-10 12:37:11 -0500190 rec.fPipeline->append(SkRasterPipeline::seed_shader);
Mike Reed1d8c42e2017-08-29 14:58:19 -0400191 rec.fPipeline->append(SkRasterPipeline::callback, cb);
Mike Klein894328d2019-03-21 10:06:38 -0500192 rec.fAlloc->make<SkColorSpaceXformSteps>(sk_srgb_singleton(), kPremul_SkAlphaType,
193 rec.fDstCS, kPremul_SkAlphaType)
194 ->apply(rec.fPipeline, true);
Mike Reed6867eee2017-06-02 13:25:15 -0400195 return true;
196 }
Mike Klein44d32792017-05-10 12:29:38 -0400197 return false;
198}
199
Mike Klein03935052019-11-01 11:36:55 -0500200bool SkShaderBase::program(skvm::Builder* p,
201 SkColorSpace* dstCS,
Mike Klein1cc60672019-11-05 14:19:58 -0600202 skvm::Uniforms* uniforms,
Mike Kleinf3d41092019-11-04 13:22:02 -0600203 skvm::F32 x, skvm::F32 y,
Mike Kleinb9f20882019-11-08 12:14:15 -0600204 skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) const {
Mike Klein03935052019-11-01 11:36:55 -0500205 // Force opaque alpha for all opaque shaders.
206 //
Mike Kleinb9f20882019-11-08 12:14:15 -0600207 // This is primarily nice in that we usually have a 1.0f constant splat
Mike Klein03935052019-11-01 11:36:55 -0500208 // somewhere in the program anyway, and this will let us drop the work the
209 // shader notionally does to produce alpha, p->extract(...), etc. in favor
210 // of that simple hoistable splat.
211 //
212 // More subtly, it makes isOpaque() a parameter to all shader program
213 // generation, guaranteeing that is-opaque bit is mixed into the overall
214 // shader program hash and blitter Key. This makes it safe for us to use
215 // that bit to make decisions when constructing an SkVMBlitter, like doing
216 // SrcOver -> Src strength reduction.
Mike Klein1cc60672019-11-05 14:19:58 -0600217 if (this->onProgram(p, dstCS, uniforms, x,y, r,g,b,a)) {
Mike Kleinfb9146f2019-11-05 05:49:34 -0600218 if (this->isOpaque()) {
Mike Kleinb9f20882019-11-08 12:14:15 -0600219 *a = p->splat(1.0f);
Mike Klein03935052019-11-01 11:36:55 -0500220 }
221 return true;
222 }
223 return false;
224}
225
reed0ccc62d2016-05-04 13:09:39 -0700226///////////////////////////////////////////////////////////////////////////////////////////////////
reed830dfd82016-03-16 12:29:01 -0700227
reed60c9b582016-04-03 09:11:13 -0700228sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) {
Mike Reedc8bea7d2019-04-09 13:55:36 -0400229 return SkShaders::Empty();
reed9fa60da2014-08-21 07:59:51 -0700230}