blob: cc95a30ef328a4b130e2559590e91de5c00ba8de [file] [log] [blame]
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +00001/*
2 * Copyright 2014 Google Inc.
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
Brian Osman9aaec362020-05-08 14:54:37 -04008#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "src/core/SkTLazy.h"
Mike Kleinc376cb42020-03-10 15:40:23 -050010#include "src/core/SkVM.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/shaders/SkLocalMatrixShader.h"
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000012
bungeman06ca8ec2016-06-09 08:01:03 -070013#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrFragmentProcessor.h"
Michael Ludwig4e221bd2020-06-05 11:29:36 -040015#include "src/gpu/effects/generated/GrDeviceSpaceEffect.h"
bungeman06ca8ec2016-06-09 08:01:03 -070016#endif
17
18#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -040019std::unique_ptr<GrFragmentProcessor> SkLocalMatrixShader::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -050020 const GrFPArgs& args) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -040021 return as_SB(fProxyShader)->asFragmentProcessor(
22 GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix()));
bungeman06ca8ec2016-06-09 08:01:03 -070023}
24#endif
25
reed60c9b582016-04-03 09:11:13 -070026sk_sp<SkFlattenable> SkLocalMatrixShader::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070027 SkMatrix lm;
28 buffer.readMatrix(&lm);
reed8a21c9f2016-03-08 18:50:00 -080029 auto baseShader(buffer.readShader());
reedf880e452015-12-30 13:39:41 -080030 if (!baseShader) {
halcanary96fcdcc2015-08-27 07:41:13 -070031 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070032 }
reed60c9b582016-04-03 09:11:13 -070033 return baseShader->makeWithLocalMatrix(lm);
reed9fa60da2014-08-21 07:59:51 -070034}
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000035
36void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const {
reed9fa60da2014-08-21 07:59:51 -070037 buffer.writeMatrix(this->getLocalMatrix());
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000038 buffer.writeFlattenable(fProxyShader.get());
39}
40
Mike Reede92aae62018-10-17 10:21:51 -040041#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Florin Malita4aed1382017-05-25 10:38:07 -040042SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
Herb Derby83e939b2017-02-07 14:25:11 -050043 const ContextRec& rec, SkArenaAlloc* alloc) const
44{
Florin Malita325ea322018-04-04 14:17:30 -040045 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000046 if (rec.fLocalMatrix) {
Florin Malita325ea322018-04-04 14:17:30 -040047 lm.writable()->preConcat(*rec.fLocalMatrix);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000048 }
Florin Malita325ea322018-04-04 14:17:30 -040049
50 ContextRec newRec(rec);
51 newRec.fLocalMatrix = lm;
52
Florin Malita4aed1382017-05-25 10:38:07 -040053 return as_SB(fProxyShader)->makeContext(newRec, alloc);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000054}
Mike Reede92aae62018-10-17 10:21:51 -040055#endif
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000056
Mike Reedfae8fce2019-04-03 10:27:45 -040057SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, SkTileMode* mode) const {
Matt Sarett547a7272017-04-12 11:52:47 -040058 SkMatrix imageMatrix;
59 SkImage* image = fProxyShader->isAImage(&imageMatrix, mode);
60 if (image && outMatrix) {
61 // Local matrix must be applied first so it is on the right side of the concat.
62 *outMatrix = SkMatrix::Concat(imageMatrix, this->getLocalMatrix());
63 }
64
65 return image;
66}
67
Mike Reed1386b2d2019-03-13 21:15:05 -040068bool SkLocalMatrixShader::onAppendStages(const SkStageRec& rec) const {
Florin Malita325ea322018-04-04 14:17:30 -040069 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
Mike Reed1d8c42e2017-08-29 14:58:19 -040070 if (rec.fLocalM) {
Florin Malita325ea322018-04-04 14:17:30 -040071 lm.writable()->preConcat(*rec.fLocalM);
Florin Malita882ccaf2017-01-27 10:51:58 -050072 }
Florin Malita325ea322018-04-04 14:17:30 -040073
Mike Reed1386b2d2019-03-13 21:15:05 -040074 SkStageRec newRec = rec;
Florin Malita325ea322018-04-04 14:17:30 -040075 newRec.fLocalM = lm;
Mike Reed1d8c42e2017-08-29 14:58:19 -040076 return as_SB(fProxyShader)->appendStages(newRec);
Florin Malita882ccaf2017-01-27 10:51:58 -050077}
78
Mike Kleinc376cb42020-03-10 15:40:23 -050079
Mike Kleina434e0f2020-03-23 09:33:48 -050080skvm::Color SkLocalMatrixShader::onProgram(skvm::Builder* p,
81 skvm::F32 x, skvm::F32 y, skvm::Color paint,
Mike Reed6352f002020-03-14 23:30:10 -040082 const SkMatrix& ctm, const SkMatrix* localM,
Mike Kleina434e0f2020-03-23 09:33:48 -050083 SkFilterQuality quality, const SkColorInfo& dst,
Mike Klein276a7852020-03-15 08:46:09 -050084 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
Mike Kleinc376cb42020-03-10 15:40:23 -050085 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
86 if (localM) {
87 lm.writable()->preConcat(*localM);
88 }
Mike Kleina434e0f2020-03-23 09:33:48 -050089 return as_SB(fProxyShader)->program(p, x,y, paint, ctm,lm.get(), quality,dst, uniforms,alloc);
Mike Kleinc376cb42020-03-10 15:40:23 -050090}
91
reed150835e2016-03-10 06:36:49 -080092sk_sp<SkShader> SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const {
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000093 if (localMatrix.isIdentity()) {
reed150835e2016-03-10 06:36:49 -080094 return sk_ref_sp(const_cast<SkShader*>(this));
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000095 }
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000096
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000097 const SkMatrix* lm = &localMatrix;
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000098
Ben Wagnera8834bb2016-10-24 11:36:21 -040099 sk_sp<SkShader> baseShader;
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000100 SkMatrix otherLocalMatrix;
Florin Malita4aed1382017-05-25 10:38:07 -0400101 sk_sp<SkShader> proxy(as_SB(this)->makeAsALocalMatrixShader(&otherLocalMatrix));
reedf880e452015-12-30 13:39:41 -0800102 if (proxy) {
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000103 otherLocalMatrix.preConcat(localMatrix);
104 lm = &otherLocalMatrix;
Ben Wagnera8834bb2016-10-24 11:36:21 -0400105 baseShader = proxy;
106 } else {
107 baseShader = sk_ref_sp(const_cast<SkShader*>(this));
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000108 }
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +0000109
Ben Wagnera8834bb2016-10-24 11:36:21 -0400110 return sk_make_sp<SkLocalMatrixShader>(std::move(baseShader), *lm);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000111}
Mike Reed121c2af2020-03-10 14:02:56 -0400112
113////////////////////////////////////////////////////////////////////
114
115/**
116 * Replaces the CTM when used. Created to support clipShaders, which have to be evaluated
117 * using the CTM that was present at the time they were specified (which may be different
118 * from the CTM at the time something is drawn through the clip.
119 */
120class SkCTMShader final : public SkShaderBase {
121public:
122 SkCTMShader(sk_sp<SkShader> proxy, const SkMatrix& ctm)
123 : fProxyShader(std::move(proxy))
124 , fCTM(ctm)
125 {}
126
127 GradientType asAGradient(GradientInfo* info) const override {
128 return fProxyShader->asAGradient(info);
129 }
130
131#if SK_SUPPORT_GPU
132 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
133#endif
134
135protected:
136 void flatten(SkWriteBuffer&) const override { SkASSERT(false); }
137
138#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
139 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override { return nullptr; }
140#endif
141
Mike Klein272c56b2020-03-10 14:24:35 -0500142 bool onAppendStages(const SkStageRec& rec) const override {
Brian Osman9aaec362020-05-08 14:54:37 -0400143 SkOverrideDeviceMatrixProvider matrixProvider(rec.fMatrixProvider, fCTM);
Mike Klein272c56b2020-03-10 14:24:35 -0500144 SkStageRec newRec = {
145 rec.fPipeline,
146 rec.fAlloc,
147 rec.fDstColorType,
148 rec.fDstCS,
149 rec.fPaint,
150 rec.fLocalM,
Brian Osman9aaec362020-05-08 14:54:37 -0400151 matrixProvider,
Mike Klein272c56b2020-03-10 14:24:35 -0500152 };
153 return as_SB(fProxyShader)->appendStages(newRec);
154 }
155
Mike Kleina434e0f2020-03-23 09:33:48 -0500156 skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
Mike Reed6352f002020-03-14 23:30:10 -0400157 const SkMatrix& ctm, const SkMatrix* localM,
Mike Kleina434e0f2020-03-23 09:33:48 -0500158 SkFilterQuality quality, const SkColorInfo& dst,
Mike Klein276a7852020-03-15 08:46:09 -0500159 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
Mike Kleina434e0f2020-03-23 09:33:48 -0500160 return as_SB(fProxyShader)->program(p, x,y,paint, fCTM,localM, quality,dst, uniforms,alloc);
Mike Klein272c56b2020-03-10 14:24:35 -0500161 }
Mike Reed121c2af2020-03-10 14:02:56 -0400162
163private:
164 SK_FLATTENABLE_HOOKS(SkCTMShader)
165
166 sk_sp<SkShader> fProxyShader;
167 SkMatrix fCTM;
168
169 typedef SkShaderBase INHERITED;
170};
171
172
173#if SK_SUPPORT_GPU
174std::unique_ptr<GrFragmentProcessor> SkCTMShader::asFragmentProcessor(
175 const GrFPArgs& args) const {
Michael Ludwig4e221bd2020-06-05 11:29:36 -0400176 SkMatrix ctmInv;
177 if (!fCTM.invert(&ctmInv)) {
178 return nullptr;
179 }
180
181 auto ctmProvider = SkOverrideDeviceMatrixProvider(args.fMatrixProvider, fCTM);
182 auto base = as_SB(fProxyShader)->asFragmentProcessor(
183 GrFPArgs::WithPreLocalMatrix(args.withNewMatrixProvider(ctmProvider),
184 this->getLocalMatrix()));
185 if (!base) {
186 return nullptr;
187 }
188
189 // In order for the shader to be evaluated with the original CTM, we explicitly evaluate it
190 // at sk_FragCoord, and pass that through the inverse of the original CTM. This avoids requiring
191 // local coords for the shader and mapping from the draw's local to device and then back.
192 return GrDeviceSpaceEffect::Make(std::move(base), ctmInv);
Mike Reed121c2af2020-03-10 14:02:56 -0400193}
194#endif
195
196sk_sp<SkFlattenable> SkCTMShader::CreateProc(SkReadBuffer& buffer) {
197 SkASSERT(false);
198 return nullptr;
199}
200
Mike Reed121c2af2020-03-10 14:02:56 -0400201sk_sp<SkShader> SkShaderBase::makeWithCTM(const SkMatrix& postM) const {
Michael Ludwig4e221bd2020-06-05 11:29:36 -0400202 return sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM));
Mike Reed121c2af2020-03-10 14:02:56 -0400203}