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/SkFlattenable.h"
10 #include "include/core/SkString.h"
11 #include "include/effects/SkRuntimeEffect.h"
12 #include "include/private/SkColorData.h"
13 #include "src/base/SkArenaAlloc.h"
14 #include "src/core/SkBlendModePriv.h"
15 #include "src/core/SkBlenderBase.h"
16 #include "src/core/SkRasterPipeline.h"
17 #include "src/core/SkReadBuffer.h"
18 #include "src/core/SkRuntimeEffectPriv.h"
19 #include "src/core/SkVM.h"
20 #include "src/core/SkWriteBuffer.h"
21 #include "src/shaders/SkShaderBase.h"
22
23 #if defined(SK_GRAPHITE)
24 #include "src/gpu/Blend.h"
25 #include "src/gpu/graphite/KeyHelpers.h"
26 #include "src/gpu/graphite/PaintParamsKey.h"
27 #endif
28
29 class SkShader_Blend final : public SkShaderBase {
30 public:
SkShader_Blend(SkBlendMode mode,sk_sp<SkShader> dst,sk_sp<SkShader> src)31 SkShader_Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src)
32 : fDst(std::move(dst))
33 , fSrc(std::move(src))
34 , fMode(mode) {}
35
36 #if defined(SK_GANESH)
37 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&,
38 const MatrixRec&) const override;
39 #endif
40
41 #if defined(SK_GRAPHITE)
42 void addToKey(const skgpu::graphite::KeyContext&,
43 skgpu::graphite::PaintParamsKeyBuilder*,
44 skgpu::graphite::PipelineDataGatherer*) const override;
45 #endif
46
47 protected:
48 SkShader_Blend(SkReadBuffer&);
49 void flatten(SkWriteBuffer&) const override;
50 bool appendStages(const SkStageRec&, const MatrixRec&) const override;
51 skvm::Color program(skvm::Builder*,
52 skvm::Coord device,
53 skvm::Coord local,
54 skvm::Color paint,
55 const MatrixRec& mRec,
56 const SkColorInfo& dst,
57 skvm::Uniforms*,
58 SkArenaAlloc*) const override;
59
60 private:
61 friend void ::SkRegisterComposeShaderFlattenable();
62 SK_FLATTENABLE_HOOKS(SkShader_Blend)
63
64 sk_sp<SkShader> fDst;
65 sk_sp<SkShader> fSrc;
66 SkBlendMode fMode;
67
68 using INHERITED = SkShaderBase;
69 };
70
CreateProc(SkReadBuffer & buffer)71 sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) {
72 sk_sp<SkShader> dst(buffer.readShader());
73 sk_sp<SkShader> src(buffer.readShader());
74 if (!buffer.validate(dst && src)) {
75 return nullptr;
76 }
77
78 unsigned mode = buffer.read32();
79
80 if (mode == kCustom_SkBlendMode) {
81 sk_sp<SkBlender> blender = buffer.readBlender();
82 if (buffer.validate(blender != nullptr)) {
83 return SkShaders::Blend(std::move(blender), std::move(dst), std::move(src));
84 }
85 } else {
86 if (buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
87 return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
88 }
89 }
90 return nullptr;
91 }
92
flatten(SkWriteBuffer & buffer) const93 void SkShader_Blend::flatten(SkWriteBuffer& buffer) const {
94 buffer.writeFlattenable(fDst.get());
95 buffer.writeFlattenable(fSrc.get());
96 buffer.write32((int)fMode);
97 }
98
99 // Returns the output of e0, and leaves the output of e1 in r,g,b,a
append_two_shaders(const SkStageRec & rec,const SkShaderBase::MatrixRec & mRec,SkShader * s0,SkShader * s1)100 static float* append_two_shaders(const SkStageRec& rec,
101 const SkShaderBase::MatrixRec& mRec,
102 SkShader* s0,
103 SkShader* s1) {
104 struct Storage {
105 float fCoords[2 * SkRasterPipeline_kMaxStride];
106 float fRes0 [4 * SkRasterPipeline_kMaxStride];
107 };
108 auto storage = rec.fAlloc->make<Storage>();
109
110 // Note we cannot simply apply mRec here and then unconditionally store the coordinates. When
111 // building for Android Framework it would interrupt the backwards local matrix concatenation if
112 // mRec had a pending local matrix and either of the children also had a local matrix.
113 // b/256873449
114 if (mRec.rasterPipelineCoordsAreSeeded()) {
115 rec.fPipeline->append(SkRasterPipelineOp::store_src_rg, storage->fCoords);
116 }
117 if (!as_SB(s0)->appendStages(rec, mRec)) {
118 return nullptr;
119 }
120 rec.fPipeline->append(SkRasterPipelineOp::store_src, storage->fRes0);
121
122 if (mRec.rasterPipelineCoordsAreSeeded()) {
123 rec.fPipeline->append(SkRasterPipelineOp::load_src_rg, storage->fCoords);
124 }
125 if (!as_SB(s1)->appendStages(rec, mRec)) {
126 return nullptr;
127 }
128 return storage->fRes0;
129 }
130
appendStages(const SkStageRec & rec,const MatrixRec & mRec) const131 bool SkShader_Blend::appendStages(const SkStageRec& rec, const MatrixRec& mRec) const {
132 float* res0 = append_two_shaders(rec, mRec, fDst.get(), fSrc.get());
133 if (!res0) {
134 return false;
135 }
136
137 rec.fPipeline->append(SkRasterPipelineOp::load_dst, res0);
138 SkBlendMode_AppendStages(fMode, rec.fPipeline);
139 return true;
140 }
141
program(skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const MatrixRec & mRec,const SkColorInfo & cinfo,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const142 skvm::Color SkShader_Blend::program(skvm::Builder* p,
143 skvm::Coord device,
144 skvm::Coord local,
145 skvm::Color paint,
146 const MatrixRec& mRec,
147 const SkColorInfo& cinfo,
148 skvm::Uniforms* uniforms,
149 SkArenaAlloc* alloc) const {
150 skvm::Color d,s;
151 if ((d = as_SB(fDst)->program(p, device, local, paint, mRec, cinfo, uniforms, alloc)) &&
152 (s = as_SB(fSrc)->program(p, device, local, paint, mRec, cinfo, uniforms, alloc))) {
153 return p->blend(fMode, s,d);
154 }
155 return {};
156 }
157
158 #if defined(SK_GANESH)
159
160 #include "include/gpu/GrRecordingContext.h"
161 #include "src/gpu/ganesh/GrFPArgs.h"
162 #include "src/gpu/ganesh/GrFragmentProcessor.h"
163 #include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
164
165 std::unique_ptr<GrFragmentProcessor>
asFragmentProcessor(const GrFPArgs & args,const MatrixRec & mRec) const166 SkShader_Blend::asFragmentProcessor(const GrFPArgs& args, const MatrixRec& mRec) const {
167 auto fpA = as_SB(fDst)->asFragmentProcessor(args, mRec);
168 auto fpB = as_SB(fSrc)->asFragmentProcessor(args, mRec);
169 if (!fpA || !fpB) {
170 // This is unexpected. Both src and dst shaders should be valid. Just fail.
171 return nullptr;
172 }
173 return GrBlendFragmentProcessor::Make(std::move(fpB), std::move(fpA), fMode);
174 }
175 #endif
176
177 #if defined(SK_GRAPHITE)
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const178 void SkShader_Blend::addToKey(const skgpu::graphite::KeyContext& keyContext,
179 skgpu::graphite::PaintParamsKeyBuilder* builder,
180 skgpu::graphite::PipelineDataGatherer* gatherer) const {
181 using namespace skgpu::graphite;
182
183 SkSpan<const float> porterDuffConstants = skgpu::GetPorterDuffBlendConstants(fMode);
184 if (!porterDuffConstants.empty()) {
185 PorterDuffBlendShaderBlock::BeginBlock(keyContext, builder, gatherer,
186 {porterDuffConstants});
187 } else {
188 BlendShaderBlock::BeginBlock(keyContext, builder, gatherer, {fMode});
189 }
190
191 as_SB(fDst)->addToKey(keyContext, builder, gatherer);
192 as_SB(fSrc)->addToKey(keyContext, builder, gatherer);
193
194 builder->endBlock();
195 }
196 #endif
197
Blend(SkBlendMode mode,sk_sp<SkShader> dst,sk_sp<SkShader> src)198 sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
199 if (!src || !dst) {
200 return nullptr;
201 }
202 switch (mode) {
203 case SkBlendMode::kClear: return Color(0);
204 case SkBlendMode::kDst: return dst;
205 case SkBlendMode::kSrc: return src;
206 default: break;
207 }
208 return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src)));
209 }
210
Blend(sk_sp<SkBlender> blender,sk_sp<SkShader> dst,sk_sp<SkShader> src)211 sk_sp<SkShader> SkShaders::Blend(sk_sp<SkBlender> blender,
212 sk_sp<SkShader> dst,
213 sk_sp<SkShader> src) {
214 if (!src || !dst) {
215 return nullptr;
216 }
217 if (!blender) {
218 return SkShaders::Blend(SkBlendMode::kSrcOver, std::move(dst), std::move(src));
219 }
220 if (std::optional<SkBlendMode> mode = as_BB(blender)->asBlendMode()) {
221 return sk_make_sp<SkShader_Blend>(mode.value(), std::move(dst), std::move(src));
222 }
223
224 #ifdef SK_ENABLE_SKSL
225 // This isn't a built-in blend mode; we might as well use a runtime effect to evaluate it.
226 static SkRuntimeEffect* sBlendEffect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
227 "uniform blender b;"
228 "uniform shader d, s;"
229 "half4 main(float2 xy) {"
230 "return b.eval(s.eval(xy), d.eval(xy));"
231 "}"
232 );
233 SkRuntimeEffect::ChildPtr children[] = {std::move(blender), std::move(dst), std::move(src)};
234 return sBlendEffect->makeShader(/*uniforms=*/{}, children);
235 #else
236 // We need SkSL to render this blend.
237 return nullptr;
238 #endif
239 }
240
SkRegisterComposeShaderFlattenable()241 void SkRegisterComposeShaderFlattenable() {
242 SK_REGISTER_FLATTENABLE(SkShader_Blend);
243 }
244