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