• 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/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