• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "src/base/SkTLazy.h"
9 #include "src/core/SkMatrixProvider.h"
10 #include "src/core/SkVM.h"
11 #include "src/shaders/SkLocalMatrixShader.h"
12 
13 #if defined(SK_GANESH)
14 #include "src/gpu/ganesh/GrFPArgs.h"
15 #include "src/gpu/ganesh/GrFragmentProcessor.h"
16 #include "src/gpu/ganesh/effects/GrMatrixEffect.h"
17 #endif
18 
19 #if defined(SK_GRAPHITE)
20 #include "src/gpu/graphite/KeyContext.h"
21 #include "src/gpu/graphite/KeyHelpers.h"
22 #include "src/gpu/graphite/PaintParamsKey.h"
23 #endif
24 
asGradient(GradientInfo * info,SkMatrix * localMatrix) const25 SkShaderBase::GradientType SkLocalMatrixShader::asGradient(GradientInfo* info,
26                                                            SkMatrix* localMatrix) const {
27     GradientType type = as_SB(fWrappedShader)->asGradient(info, localMatrix);
28     if (type != SkShaderBase::GradientType::kNone && localMatrix) {
29         *localMatrix = ConcatLocalMatrices(fLocalMatrix, *localMatrix);
30     }
31     return type;
32 }
33 
34 #if defined(SK_GANESH)
asFragmentProcessor(const GrFPArgs & args,const MatrixRec & mRec) const35 std::unique_ptr<GrFragmentProcessor> SkLocalMatrixShader::asFragmentProcessor(
36         const GrFPArgs& args, const MatrixRec& mRec) const {
37     return as_SB(fWrappedShader)->asFragmentProcessor(args, mRec.concat(fLocalMatrix));
38 }
39 #endif
40 
41 #if defined(SK_GRAPHITE)
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const42 void SkLocalMatrixShader::addToKey(const skgpu::graphite::KeyContext& keyContext,
43                                    skgpu::graphite::PaintParamsKeyBuilder* builder,
44                                    skgpu::graphite::PipelineDataGatherer* gatherer) const {
45     using namespace skgpu::graphite;
46 
47     LocalMatrixShaderBlock::LMShaderData lmShaderData(fLocalMatrix);
48 
49     KeyContextWithLocalMatrix newContext(keyContext, fLocalMatrix);
50 
51     LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, &lmShaderData);
52 
53     as_SB(fWrappedShader)->addToKey(newContext, builder, gatherer);
54 
55     builder->endBlock();
56 }
57 #endif
58 
CreateProc(SkReadBuffer & buffer)59 sk_sp<SkFlattenable> SkLocalMatrixShader::CreateProc(SkReadBuffer& buffer) {
60     SkMatrix lm;
61     buffer.readMatrix(&lm);
62     auto baseShader(buffer.readShader());
63     if (!baseShader) {
64         return nullptr;
65     }
66     return baseShader->makeWithLocalMatrix(lm);
67 }
68 
flatten(SkWriteBuffer & buffer) const69 void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const {
70     buffer.writeMatrix(fLocalMatrix);
71     buffer.writeFlattenable(fWrappedShader.get());
72 }
73 
74 #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const75 SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
76     const ContextRec& rec, SkArenaAlloc* alloc) const
77 {
78     SkTCopyOnFirstWrite<SkMatrix> lm(fLocalMatrix);
79     if (rec.fLocalMatrix) {
80         *lm.writable() = ConcatLocalMatrices(*rec.fLocalMatrix, *lm);
81     }
82 
83     ContextRec newRec(rec);
84     newRec.fLocalMatrix = lm;
85 
86     return as_SB(fWrappedShader)->makeContext(newRec, alloc);
87 }
88 #endif
89 
onIsAImage(SkMatrix * outMatrix,SkTileMode * mode) const90 SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, SkTileMode* mode) const {
91     SkMatrix imageMatrix;
92     SkImage* image = fWrappedShader->isAImage(&imageMatrix, mode);
93     if (image && outMatrix) {
94         *outMatrix = ConcatLocalMatrices(fLocalMatrix, imageMatrix);
95     }
96 
97     return image;
98 }
99 
appendStages(const SkStageRec & rec,const MatrixRec & mRec) const100 bool SkLocalMatrixShader::appendStages(const SkStageRec& rec, const MatrixRec& mRec) const {
101     return as_SB(fWrappedShader)->appendStages(rec, mRec.concat(fLocalMatrix));
102 }
103 
program(skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const MatrixRec & mRec,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const104 skvm::Color SkLocalMatrixShader::program(skvm::Builder* p,
105                                          skvm::Coord device,
106                                          skvm::Coord local,
107                                          skvm::Color paint,
108                                          const MatrixRec& mRec,
109                                          const SkColorInfo& dst,
110                                          skvm::Uniforms* uniforms,
111                                          SkArenaAlloc* alloc) const {
112     return as_SB(fWrappedShader)->program(p,
113                                           device,
114                                           local,
115                                           paint,
116                                           mRec.concat(fLocalMatrix),
117                                           dst,
118                                           uniforms,
119                                           alloc);
120 }
121 
makeWithLocalMatrix(const SkMatrix & localMatrix) const122 sk_sp<SkShader> SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const {
123     if (localMatrix.isIdentity()) {
124         return sk_ref_sp(const_cast<SkShader*>(this));
125     }
126 
127     const SkMatrix* lm = &localMatrix;
128 
129     sk_sp<SkShader> baseShader;
130     SkMatrix otherLocalMatrix;
131     sk_sp<SkShader> proxy = as_SB(this)->makeAsALocalMatrixShader(&otherLocalMatrix);
132     if (proxy) {
133         otherLocalMatrix = SkShaderBase::ConcatLocalMatrices(localMatrix, otherLocalMatrix);
134         lm = &otherLocalMatrix;
135         baseShader = proxy;
136     } else {
137         baseShader = sk_ref_sp(const_cast<SkShader*>(this));
138     }
139 
140     return sk_make_sp<SkLocalMatrixShader>(std::move(baseShader), *lm);
141 }
142 
143 ////////////////////////////////////////////////////////////////////
144 
145 /**
146  *  Replaces the CTM when used. Created to support clipShaders, which have to be evaluated
147  *  using the CTM that was present at the time they were specified (which may be different
148  *  from the CTM at the time something is drawn through the clip.
149  */
150 class SkCTMShader final : public SkShaderBase {
151 public:
SkCTMShader(sk_sp<SkShader> proxy,const SkMatrix & ctm)152     SkCTMShader(sk_sp<SkShader> proxy, const SkMatrix& ctm)
153     : fProxyShader(std::move(proxy))
154     , fCTM(ctm)
155     {}
156 
asGradient(GradientInfo * info,SkMatrix * localMatrix) const157     GradientType asGradient(GradientInfo* info, SkMatrix* localMatrix) const override {
158         return as_SB(fProxyShader)->asGradient(info, localMatrix);
159     }
160 
161 #if defined(SK_GANESH)
162     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&,
163                                                              const MatrixRec&) const override;
164 #endif
165 
166 protected:
flatten(SkWriteBuffer &) const167     void flatten(SkWriteBuffer&) const override { SkASSERT(false); }
168 
appendStages(const SkStageRec & rec,const MatrixRec &) const169     bool appendStages(const SkStageRec& rec, const MatrixRec&) const override {
170         return as_SB(fProxyShader)->appendRootStages(rec, fCTM);
171     }
172 
program(skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const MatrixRec & mRec,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const173     skvm::Color program(skvm::Builder* p,
174                         skvm::Coord device,
175                         skvm::Coord local,
176                         skvm::Color paint,
177                         const MatrixRec& mRec,
178                         const SkColorInfo& dst,
179                         skvm::Uniforms* uniforms,
180                         SkArenaAlloc* alloc) const override {
181         return as_SB(fProxyShader)->rootProgram(p, device, paint, fCTM, dst, uniforms, alloc);
182     }
183 
184 private:
185     SK_FLATTENABLE_HOOKS(SkCTMShader)
186 
187     sk_sp<SkShader> fProxyShader;
188     SkMatrix        fCTM;
189 
190     using INHERITED = SkShaderBase;
191 };
192 
193 
194 #if defined(SK_GANESH)
asFragmentProcessor(const GrFPArgs & args,const MatrixRec & mRec) const195 std::unique_ptr<GrFragmentProcessor> SkCTMShader::asFragmentProcessor(const GrFPArgs& args,
196                                                                       const MatrixRec& mRec) const {
197     SkMatrix ctmInv;
198     if (!fCTM.invert(&ctmInv)) {
199         return nullptr;
200     }
201 
202     auto base = as_SB(fProxyShader)->asRootFragmentProcessor(args, fCTM);
203     if (!base) {
204         return nullptr;
205     }
206 
207     // In order for the shader to be evaluated with the original CTM, we explicitly evaluate it
208     // at sk_FragCoord, and pass that through the inverse of the original CTM. This avoids requiring
209     // local coords for the shader and mapping from the draw's local to device and then back.
210     return GrFragmentProcessor::DeviceSpace(GrMatrixEffect::Make(ctmInv, std::move(base)));
211 }
212 #endif
213 
CreateProc(SkReadBuffer & buffer)214 sk_sp<SkFlattenable> SkCTMShader::CreateProc(SkReadBuffer& buffer) {
215     SkASSERT(false);
216     return nullptr;
217 }
218 
makeWithCTM(const SkMatrix & postM) const219 sk_sp<SkShader> SkShaderBase::makeWithCTM(const SkMatrix& postM) const {
220     return sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM));
221 }
222