blob: 66ee52be696da0ecaa5dbe26003b9714a9f4b1f5 [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"
bungeman06ca8ec2016-06-09 08:01:03 -070015#endif
16
17#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -040018std::unique_ptr<GrFragmentProcessor> SkLocalMatrixShader::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -050019 const GrFPArgs& args) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -040020 return as_SB(fProxyShader)->asFragmentProcessor(
21 GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix()));
bungeman06ca8ec2016-06-09 08:01:03 -070022}
23#endif
24
reed60c9b582016-04-03 09:11:13 -070025sk_sp<SkFlattenable> SkLocalMatrixShader::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070026 SkMatrix lm;
27 buffer.readMatrix(&lm);
reed8a21c9f2016-03-08 18:50:00 -080028 auto baseShader(buffer.readShader());
reedf880e452015-12-30 13:39:41 -080029 if (!baseShader) {
halcanary96fcdcc2015-08-27 07:41:13 -070030 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070031 }
reed60c9b582016-04-03 09:11:13 -070032 return baseShader->makeWithLocalMatrix(lm);
reed9fa60da2014-08-21 07:59:51 -070033}
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000034
35void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const {
reed9fa60da2014-08-21 07:59:51 -070036 buffer.writeMatrix(this->getLocalMatrix());
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000037 buffer.writeFlattenable(fProxyShader.get());
38}
39
Mike Reede92aae62018-10-17 10:21:51 -040040#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Florin Malita4aed1382017-05-25 10:38:07 -040041SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
Herb Derby83e939b2017-02-07 14:25:11 -050042 const ContextRec& rec, SkArenaAlloc* alloc) const
43{
Florin Malita325ea322018-04-04 14:17:30 -040044 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000045 if (rec.fLocalMatrix) {
Florin Malita325ea322018-04-04 14:17:30 -040046 lm.writable()->preConcat(*rec.fLocalMatrix);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000047 }
Florin Malita325ea322018-04-04 14:17:30 -040048
49 ContextRec newRec(rec);
50 newRec.fLocalMatrix = lm;
51
Florin Malita4aed1382017-05-25 10:38:07 -040052 return as_SB(fProxyShader)->makeContext(newRec, alloc);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000053}
Mike Reede92aae62018-10-17 10:21:51 -040054#endif
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000055
Mike Reedfae8fce2019-04-03 10:27:45 -040056SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, SkTileMode* mode) const {
Matt Sarett547a7272017-04-12 11:52:47 -040057 SkMatrix imageMatrix;
58 SkImage* image = fProxyShader->isAImage(&imageMatrix, mode);
59 if (image && outMatrix) {
60 // Local matrix must be applied first so it is on the right side of the concat.
61 *outMatrix = SkMatrix::Concat(imageMatrix, this->getLocalMatrix());
62 }
63
64 return image;
65}
66
Mike Reed1386b2d2019-03-13 21:15:05 -040067bool SkLocalMatrixShader::onAppendStages(const SkStageRec& rec) const {
Florin Malita325ea322018-04-04 14:17:30 -040068 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
Mike Reed1d8c42e2017-08-29 14:58:19 -040069 if (rec.fLocalM) {
Florin Malita325ea322018-04-04 14:17:30 -040070 lm.writable()->preConcat(*rec.fLocalM);
Florin Malita882ccaf2017-01-27 10:51:58 -050071 }
Florin Malita325ea322018-04-04 14:17:30 -040072
Mike Reed1386b2d2019-03-13 21:15:05 -040073 SkStageRec newRec = rec;
Florin Malita325ea322018-04-04 14:17:30 -040074 newRec.fLocalM = lm;
Mike Reed1d8c42e2017-08-29 14:58:19 -040075 return as_SB(fProxyShader)->appendStages(newRec);
Florin Malita882ccaf2017-01-27 10:51:58 -050076}
77
Mike Kleinc376cb42020-03-10 15:40:23 -050078
Mike Kleina434e0f2020-03-23 09:33:48 -050079skvm::Color SkLocalMatrixShader::onProgram(skvm::Builder* p,
80 skvm::F32 x, skvm::F32 y, skvm::Color paint,
Mike Reed6352f002020-03-14 23:30:10 -040081 const SkMatrix& ctm, const SkMatrix* localM,
Mike Kleina434e0f2020-03-23 09:33:48 -050082 SkFilterQuality quality, const SkColorInfo& dst,
Mike Klein276a7852020-03-15 08:46:09 -050083 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
Mike Kleinc376cb42020-03-10 15:40:23 -050084 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
85 if (localM) {
86 lm.writable()->preConcat(*localM);
87 }
Mike Kleina434e0f2020-03-23 09:33:48 -050088 return as_SB(fProxyShader)->program(p, x,y, paint, ctm,lm.get(), quality,dst, uniforms,alloc);
Mike Kleinc376cb42020-03-10 15:40:23 -050089}
90
reed150835e2016-03-10 06:36:49 -080091sk_sp<SkShader> SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const {
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000092 if (localMatrix.isIdentity()) {
reed150835e2016-03-10 06:36:49 -080093 return sk_ref_sp(const_cast<SkShader*>(this));
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000094 }
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000095
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000096 const SkMatrix* lm = &localMatrix;
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000097
Ben Wagnera8834bb2016-10-24 11:36:21 -040098 sk_sp<SkShader> baseShader;
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000099 SkMatrix otherLocalMatrix;
Florin Malita4aed1382017-05-25 10:38:07 -0400100 sk_sp<SkShader> proxy(as_SB(this)->makeAsALocalMatrixShader(&otherLocalMatrix));
reedf880e452015-12-30 13:39:41 -0800101 if (proxy) {
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000102 otherLocalMatrix.preConcat(localMatrix);
103 lm = &otherLocalMatrix;
Ben Wagnera8834bb2016-10-24 11:36:21 -0400104 baseShader = proxy;
105 } else {
106 baseShader = sk_ref_sp(const_cast<SkShader*>(this));
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000107 }
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +0000108
Ben Wagnera8834bb2016-10-24 11:36:21 -0400109 return sk_make_sp<SkLocalMatrixShader>(std::move(baseShader), *lm);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000110}
Mike Reed121c2af2020-03-10 14:02:56 -0400111
112////////////////////////////////////////////////////////////////////
113
114/**
115 * Replaces the CTM when used. Created to support clipShaders, which have to be evaluated
116 * using the CTM that was present at the time they were specified (which may be different
117 * from the CTM at the time something is drawn through the clip.
118 */
119class SkCTMShader final : public SkShaderBase {
120public:
121 SkCTMShader(sk_sp<SkShader> proxy, const SkMatrix& ctm)
122 : fProxyShader(std::move(proxy))
123 , fCTM(ctm)
124 {}
125
126 GradientType asAGradient(GradientInfo* info) const override {
127 return fProxyShader->asAGradient(info);
128 }
129
130#if SK_SUPPORT_GPU
131 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
132#endif
133
134protected:
135 void flatten(SkWriteBuffer&) const override { SkASSERT(false); }
136
137#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
138 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override { return nullptr; }
139#endif
140
Mike Klein272c56b2020-03-10 14:24:35 -0500141 bool onAppendStages(const SkStageRec& rec) const override {
Brian Osman9aaec362020-05-08 14:54:37 -0400142 SkOverrideDeviceMatrixProvider matrixProvider(rec.fMatrixProvider, fCTM);
Mike Klein272c56b2020-03-10 14:24:35 -0500143 SkStageRec newRec = {
144 rec.fPipeline,
145 rec.fAlloc,
146 rec.fDstColorType,
147 rec.fDstCS,
148 rec.fPaint,
149 rec.fLocalM,
Brian Osman9aaec362020-05-08 14:54:37 -0400150 matrixProvider,
Mike Klein272c56b2020-03-10 14:24:35 -0500151 };
152 return as_SB(fProxyShader)->appendStages(newRec);
153 }
154
Mike Kleina434e0f2020-03-23 09:33:48 -0500155 skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
Mike Reed6352f002020-03-14 23:30:10 -0400156 const SkMatrix& ctm, const SkMatrix* localM,
Mike Kleina434e0f2020-03-23 09:33:48 -0500157 SkFilterQuality quality, const SkColorInfo& dst,
Mike Klein276a7852020-03-15 08:46:09 -0500158 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
Mike Kleina434e0f2020-03-23 09:33:48 -0500159 return as_SB(fProxyShader)->program(p, x,y,paint, fCTM,localM, quality,dst, uniforms,alloc);
Mike Klein272c56b2020-03-10 14:24:35 -0500160 }
Mike Reed121c2af2020-03-10 14:02:56 -0400161
162private:
163 SK_FLATTENABLE_HOOKS(SkCTMShader)
164
165 sk_sp<SkShader> fProxyShader;
166 SkMatrix fCTM;
167
168 typedef SkShaderBase INHERITED;
169};
170
171
172#if SK_SUPPORT_GPU
173std::unique_ptr<GrFragmentProcessor> SkCTMShader::asFragmentProcessor(
174 const GrFPArgs& args) const {
175 return as_SB(fProxyShader)->asFragmentProcessor(
176 GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix()));
177}
178#endif
179
180sk_sp<SkFlattenable> SkCTMShader::CreateProc(SkReadBuffer& buffer) {
181 SkASSERT(false);
182 return nullptr;
183}
184
Mike Reed121c2af2020-03-10 14:02:56 -0400185sk_sp<SkShader> SkShaderBase::makeWithCTM(const SkMatrix& postM) const {
186 return postM.isIdentity() ? sk_ref_sp(this)
187 : sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM));
188}