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/SkBlenderBase.h"
14 #include "src/core/SkRasterPipeline.h"
15 #include "src/core/SkReadBuffer.h"
16 #include "src/core/SkRuntimeEffectPriv.h"
17 #include "src/core/SkVM.h"
18 #include "src/core/SkWriteBuffer.h"
19 #include "src/shaders/SkColorShader.h"
20 #include "src/shaders/SkComposeShader.h"
21
22 namespace {
23
24 struct LocalMatrixStageRec final : public SkStageRec {
LocalMatrixStageRec__anon9c79db860111::LocalMatrixStageRec25 LocalMatrixStageRec(const SkStageRec& rec, const SkMatrix& lm)
26 : INHERITED(rec) {
27 if (!lm.isIdentity()) {
28 if (fLocalM) {
29 fStorage.setConcat(lm, *fLocalM);
30 fLocalM = fStorage.isIdentity() ? nullptr : &fStorage;
31 } else {
32 fLocalM = &lm;
33 }
34 }
35 }
36
37 private:
38 SkMatrix fStorage;
39
40 using INHERITED = SkStageRec;
41 };
42
43 } // namespace
44
Blend(SkBlendMode mode,sk_sp<SkShader> dst,sk_sp<SkShader> src)45 sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
46 if (!src || !dst) {
47 return nullptr;
48 }
49 switch (mode) {
50 case SkBlendMode::kClear: return Color(0);
51 case SkBlendMode::kDst: return dst;
52 case SkBlendMode::kSrc: return src;
53 default: break;
54 }
55 return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src)));
56 }
57
Blend(sk_sp<SkBlender> blender,sk_sp<SkShader> dst,sk_sp<SkShader> src)58 sk_sp<SkShader> SkShaders::Blend(sk_sp<SkBlender> blender, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
59 if (!src || !dst) {
60 return nullptr;
61 }
62 if (!blender) {
63 return SkShaders::Blend(SkBlendMode::kSrcOver, std::move(dst), std::move(src));
64 }
65 if (auto bm = as_BB(blender)->asBlendMode()) {
66 return SkShaders::Blend(bm.value(), std::move(dst), std::move(src));
67 }
68 return sk_sp<SkShader>(new SkShader_Blend(std::move(blender), std::move(dst), std::move(src)));
69 }
70
71 ///////////////////////////////////////////////////////////////////////////////
72
CreateProc(SkReadBuffer & buffer)73 sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) {
74 sk_sp<SkShader> dst(buffer.readShader());
75 sk_sp<SkShader> src(buffer.readShader());
76 if (!buffer.validate(dst && src)) {
77 return nullptr;
78 }
79
80 sk_sp<SkBlender> blender(nullptr);
81 unsigned mode = buffer.read32();
82
83 if (mode == kCustom_SkBlendMode) {
84 blender = buffer.readBlender();
85 if (buffer.validate(blender != nullptr)) {
86 return SkShaders::Blend(std::move(blender), std::move(dst), std::move(src));
87 }
88 } else {
89 if (buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
90 return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
91 }
92 }
93 return nullptr;
94 }
95
flatten(SkWriteBuffer & buffer) const96 void SkShader_Blend::flatten(SkWriteBuffer& buffer) const {
97 buffer.writeFlattenable(fDst.get());
98 buffer.writeFlattenable(fSrc.get());
99 if (fBlender) {
100 buffer.write32(kCustom_SkBlendMode);
101 buffer.writeFlattenable(fBlender.get());
102 } else {
103 buffer.write32((int)fMode);
104 }
105 }
106
107 // Returns the output of e0, and leaves the output of e1 in r,g,b,a
append_two_shaders(const SkStageRec & rec,SkShader * s0,SkShader * s1)108 static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) {
109 struct Storage {
110 float fRes0[4 * SkRasterPipeline_kMaxStride];
111 };
112 auto storage = rec.fAlloc->make<Storage>();
113
114 if (!as_SB(s0)->appendStages(rec)) {
115 return nullptr;
116 }
117 rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0);
118
119 if (!as_SB(s1)->appendStages(rec)) {
120 return nullptr;
121 }
122 return storage->fRes0;
123 }
124
onAppendStages(const SkStageRec & orig_rec) const125 bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const {
126 if (fBlender) {
127 return false;
128 }
129
130 const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix());
131
132 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
133 if (!res0) {
134 return false;
135 }
136
137 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
138 SkBlendMode_AppendStages(fMode, rec.fPipeline);
139 return true;
140 }
141
onProgram(skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const SkMatrixProvider & mats,const SkMatrix * localM,const SkColorInfo & cinfo,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const142 skvm::Color SkShader_Blend::onProgram(skvm::Builder* p,
143 skvm::Coord device, skvm::Coord local, skvm::Color paint,
144 const SkMatrixProvider& mats, const SkMatrix* localM,
145 const SkColorInfo& cinfo,
146 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
147 skvm::Color d,s;
148 if ((d = as_SB(fDst)->program(p, device,local, paint, mats,localM, cinfo, uniforms,alloc)) &&
149 (s = as_SB(fSrc)->program(p, device,local, paint, mats,localM, cinfo, uniforms,alloc)))
150 {
151 if (fBlender) {
152 return as_BB(fBlender)->program(p, s,d, cinfo, uniforms,alloc);
153 } else {
154 return p->blend(fMode, s,d);
155 }
156 }
157 return {};
158 }
159
160 #if SK_SUPPORT_GPU
161
162 #include "include/gpu/GrRecordingContext.h"
163 #include "src/gpu/GrFragmentProcessor.h"
164 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
165
asFragmentProcessor(const GrFPArgs & orig_args) const166 std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor(
167 const GrFPArgs& orig_args) const {
168 GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix());
169 auto fpA = as_SB(fDst)->asFragmentProcessor(args);
170 auto fpB = as_SB(fSrc)->asFragmentProcessor(args);
171 if (!fpA || !fpB) {
172 // This is unexpected. Both src and dst shaders should be valid. Just fail.
173 return nullptr;
174 }
175 if (fBlender) {
176 return as_BB(fBlender)->asFragmentProcessor(std::move(fpB), std::move(fpA), orig_args);
177 } else {
178 return GrBlendFragmentProcessor::Make(std::move(fpB), std::move(fpA), fMode);
179 }
180 }
181 #endif
182