1 | /* |
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 | |
8 | #include "include/core/SkColorFilter.h" |
9 | #include "include/core/SkString.h" |
10 | #include "include/private/SkColorData.h" |
11 | #include "src/core/SkArenaAlloc.h" |
12 | #include "src/core/SkBlendModePriv.h" |
13 | #include "src/core/SkRasterPipeline.h" |
14 | #include "src/core/SkReadBuffer.h" |
15 | #include "src/core/SkVM.h" |
16 | #include "src/core/SkWriteBuffer.h" |
17 | #include "src/shaders/SkColorShader.h" |
18 | #include "src/shaders/SkComposeShader.h" |
19 | |
20 | namespace { |
21 | |
22 | struct LocalMatrixStageRec final : public SkStageRec { |
23 | LocalMatrixStageRec(const SkStageRec& rec, const SkMatrix& lm) |
24 | : INHERITED(rec) { |
25 | if (!lm.isIdentity()) { |
26 | if (fLocalM) { |
27 | fStorage.setConcat(lm, *fLocalM); |
28 | fLocalM = fStorage.isIdentity() ? nullptr : &fStorage; |
29 | } else { |
30 | fLocalM = &lm; |
31 | } |
32 | } |
33 | } |
34 | |
35 | private: |
36 | SkMatrix fStorage; |
37 | |
38 | using INHERITED = SkStageRec; |
39 | }; |
40 | |
41 | } // namespace |
42 | |
43 | sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) { |
44 | switch (mode) { |
45 | case SkBlendMode::kClear: return Color(0); |
46 | case SkBlendMode::kDst: return dst; |
47 | case SkBlendMode::kSrc: return src; |
48 | default: break; |
49 | } |
50 | return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src))); |
51 | } |
52 | |
53 | sk_sp<SkShader> SkShaders::Lerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src) { |
54 | if (SkScalarIsNaN(weight)) { |
55 | return nullptr; |
56 | } |
57 | if (dst == src || weight <= 0) { |
58 | return dst; |
59 | } |
60 | if (weight >= 1) { |
61 | return src; |
62 | } |
63 | return sk_sp<SkShader>(new SkShader_Lerp(weight, std::move(dst), std::move(src))); |
64 | } |
65 | |
66 | /////////////////////////////////////////////////////////////////////////////// |
67 | |
68 | static bool append_shader_or_paint(const SkStageRec& rec, SkShader* shader) { |
69 | if (shader) { |
70 | if (!as_SB(shader)->appendStages(rec)) { |
71 | return false; |
72 | } |
73 | } else { |
74 | rec.fPipeline->append_constant_color(rec.fAlloc, rec.fPaint.getColor4f().premul().vec()); |
75 | } |
76 | return true; |
77 | } |
78 | |
79 | // Returns the output of e0, and leaves the output of e1 in r,g,b,a |
80 | static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) { |
81 | struct Storage { |
82 | float fRes0[4 * SkRasterPipeline_kMaxStride]; |
83 | }; |
84 | auto storage = rec.fAlloc->make<Storage>(); |
85 | |
86 | if (!append_shader_or_paint(rec, s0)) { |
87 | return nullptr; |
88 | } |
89 | rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0); |
90 | |
91 | if (!append_shader_or_paint(rec, s1)) { |
92 | return nullptr; |
93 | } |
94 | return storage->fRes0; |
95 | } |
96 | |
97 | /////////////////////////////////////////////////////////////////////////////// |
98 | |
99 | sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) { |
100 | sk_sp<SkShader> dst(buffer.readShader()); |
101 | sk_sp<SkShader> src(buffer.readShader()); |
102 | unsigned mode = buffer.read32(); |
103 | |
104 | // check for valid mode before we cast to the enum type |
105 | if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) { |
106 | return nullptr; |
107 | } |
108 | return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src)); |
109 | } |
110 | |
111 | void SkShader_Blend::flatten(SkWriteBuffer& buffer) const { |
112 | buffer.writeFlattenable(fDst.get()); |
113 | buffer.writeFlattenable(fSrc.get()); |
114 | buffer.write32((int)fMode); |
115 | } |
116 | |
117 | bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const { |
118 | const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix()); |
119 | |
120 | float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get()); |
121 | if (!res0) { |
122 | return false; |
123 | } |
124 | |
125 | rec.fPipeline->append(SkRasterPipeline::load_dst, res0); |
126 | SkBlendMode_AppendStages(fMode, rec.fPipeline); |
127 | return true; |
128 | } |
129 | |
130 | skvm::Color SkShader_Blend::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, |
131 | const SkMatrix& ctm, const SkMatrix* localM, |
132 | SkFilterQuality q, const SkColorInfo& dst, |
133 | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { |
134 | skvm::Color d,s; |
135 | if ((d = as_SB(fDst)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc)) && |
136 | (s = as_SB(fSrc)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc))) |
137 | { |
138 | return p->blend(fMode, s,d); |
139 | } |
140 | return {}; |
141 | } |
142 | |
143 | |
144 | sk_sp<SkFlattenable> SkShader_Lerp::CreateProc(SkReadBuffer& buffer) { |
145 | sk_sp<SkShader> dst(buffer.readShader()); |
146 | sk_sp<SkShader> src(buffer.readShader()); |
147 | float t = buffer.readScalar(); |
148 | return buffer.isValid() ? SkShaders::Lerp(t, std::move(dst), std::move(src)) : nullptr; |
149 | } |
150 | |
151 | void SkShader_Lerp::flatten(SkWriteBuffer& buffer) const { |
152 | buffer.writeFlattenable(fDst.get()); |
153 | buffer.writeFlattenable(fSrc.get()); |
154 | buffer.writeScalar(fWeight); |
155 | } |
156 | |
157 | bool SkShader_Lerp::onAppendStages(const SkStageRec& orig_rec) const { |
158 | const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix()); |
159 | |
160 | float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get()); |
161 | if (!res0) { |
162 | return false; |
163 | } |
164 | |
165 | rec.fPipeline->append(SkRasterPipeline::load_dst, res0); |
166 | rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fWeight); |
167 | return true; |
168 | } |
169 | |
170 | skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, |
171 | const SkMatrix& ctm, const SkMatrix* localM, |
172 | SkFilterQuality q, const SkColorInfo& dst, |
173 | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { |
174 | skvm::Color d,s; |
175 | if ((d = as_SB(fDst)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc)) && |
176 | (s = as_SB(fSrc)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc))) |
177 | { |
178 | auto t = p->uniformF(uniforms->pushF(fWeight)); |
179 | return { |
180 | p->lerp(d.r, s.r, t), |
181 | p->lerp(d.g, s.g, t), |
182 | p->lerp(d.b, s.b, t), |
183 | p->lerp(d.a, s.a, t), |
184 | }; |
185 | } |
186 | return {}; |
187 | } |
188 | |
189 | #if SK_SUPPORT_GPU |
190 | |
191 | #include "include/private/GrRecordingContext.h" |
192 | #include "src/gpu/effects/GrXfermodeFragmentProcessor.h" |
193 | #include "src/gpu/effects/generated/GrComposeLerpEffect.h" |
194 | #include "src/gpu/effects/generated/GrConstColorProcessor.h" |
195 | |
196 | static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) { |
197 | return shader ? as_SB(shader)->asFragmentProcessor(args) : nullptr; |
198 | } |
199 | |
200 | std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor( |
201 | const GrFPArgs& orig_args) const { |
202 | const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix()); |
203 | auto fpA = as_fp(args, fDst.get()); |
204 | auto fpB = as_fp(args, fSrc.get()); |
205 | if (!fpA) { |
206 | return GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(fpB), fMode); |
207 | } |
208 | if (!fpB) { |
209 | return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(fpA), fMode); |
210 | } |
211 | return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), |
212 | std::move(fpA), fMode); |
213 | } |
214 | |
215 | std::unique_ptr<GrFragmentProcessor> SkShader_Lerp::asFragmentProcessor( |
216 | const GrFPArgs& orig_args) const { |
217 | const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix()); |
218 | auto fpA = as_fp(args, fDst.get()); |
219 | auto fpB = as_fp(args, fSrc.get()); |
220 | return GrComposeLerpEffect::Make(std::move(fpA), std::move(fpB), fWeight); |
221 | } |
222 | #endif |
223 | |