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