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/SkRasterPipeline.h"
14 #include "src/core/SkReadBuffer.h"
15 #include "src/core/SkRuntimeEffectPriv.h"
16 #include "src/core/SkVM.h"
17 #include "src/core/SkWriteBuffer.h"
18 #include "src/shaders/SkColorShader.h"
19 #include "src/shaders/SkComposeShader.h"
20
21 namespace {
22
23 struct LocalMatrixStageRec final : public SkStageRec {
LocalMatrixStageRec__anona974dc740111::LocalMatrixStageRec24 LocalMatrixStageRec(const SkStageRec& rec, const SkMatrix& lm)
25 : INHERITED(rec) {
26 if (!lm.isIdentity()) {
27 if (fLocalM) {
28 fStorage.setConcat(lm, *fLocalM);
29 fLocalM = fStorage.isIdentity() ? nullptr : &fStorage;
30 } else {
31 fLocalM = &lm;
32 }
33 }
34 }
35
36 private:
37 SkMatrix fStorage;
38
39 using INHERITED = SkStageRec;
40 };
41
42 } // namespace
43
Blend(SkBlendMode mode,sk_sp<SkShader> dst,sk_sp<SkShader> src)44 sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
45 switch (mode) {
46 case SkBlendMode::kClear: return Color(0);
47 case SkBlendMode::kDst: return dst;
48 case SkBlendMode::kSrc: return src;
49 default: break;
50 }
51 return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src)));
52 }
53
Lerp(float weight,sk_sp<SkShader> dst,sk_sp<SkShader> src)54 sk_sp<SkShader> SkShaders::Lerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
55 if (SkScalarIsNaN(weight)) {
56 return nullptr;
57 }
58 if (dst == src || weight <= 0) {
59 return dst;
60 }
61 if (weight >= 1) {
62 return src;
63 }
64
65 sk_sp<SkRuntimeEffect> effect = SkMakeCachedRuntimeEffect(
66 SkRuntimeEffect::MakeForShader,
67 "uniform shader a;"
68 "uniform shader b;"
69 "uniform half w;"
70 "half4 main(float2 xy) { return mix(sample(a, xy), sample(b, xy), w); }"
71 );
72 SkASSERT(effect);
73
74 sk_sp<SkShader> inputs[] = {dst, src};
75 return effect->makeShader(SkData::MakeWithCopy(&weight, sizeof(weight)),
76 inputs,
77 SK_ARRAY_COUNT(inputs),
78 nullptr,
79 false);
80 }
81
82 ///////////////////////////////////////////////////////////////////////////////
83
append_shader_or_paint(const SkStageRec & rec,SkShader * shader)84 static bool append_shader_or_paint(const SkStageRec& rec, SkShader* shader) {
85 if (shader) {
86 if (!as_SB(shader)->appendStages(rec)) {
87 return false;
88 }
89 } else {
90 rec.fPipeline->append_constant_color(rec.fAlloc, rec.fPaint.getColor4f().premul().vec());
91 }
92 return true;
93 }
94
95 // 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)96 static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) {
97 struct Storage {
98 float fRes0[4 * SkRasterPipeline_kMaxStride];
99 };
100 auto storage = rec.fAlloc->make<Storage>();
101
102 if (!append_shader_or_paint(rec, s0)) {
103 return nullptr;
104 }
105 rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0);
106
107 if (!append_shader_or_paint(rec, s1)) {
108 return nullptr;
109 }
110 return storage->fRes0;
111 }
112
113 ///////////////////////////////////////////////////////////////////////////////
114
CreateProc(SkReadBuffer & buffer)115 sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) {
116 sk_sp<SkShader> dst(buffer.readShader());
117 sk_sp<SkShader> src(buffer.readShader());
118 unsigned mode = buffer.read32();
119
120 // check for valid mode before we cast to the enum type
121 if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
122 return nullptr;
123 }
124 return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
125 }
126
flatten(SkWriteBuffer & buffer) const127 void SkShader_Blend::flatten(SkWriteBuffer& buffer) const {
128 buffer.writeFlattenable(fDst.get());
129 buffer.writeFlattenable(fSrc.get());
130 buffer.write32((int)fMode);
131 }
132
onAppendStages(const SkStageRec & orig_rec) const133 bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const {
134 const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix());
135
136 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
137 if (!res0) {
138 return false;
139 }
140
141 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
142 SkBlendMode_AppendStages(fMode, rec.fPipeline);
143 return true;
144 }
145
program_or_paint(const sk_sp<SkShader> & sh,skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const SkMatrixProvider & mats,const SkMatrix * localM,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc)146 static skvm::Color program_or_paint(const sk_sp<SkShader>& sh, skvm::Builder* p,
147 skvm::Coord device, skvm::Coord local, skvm::Color paint,
148 const SkMatrixProvider& mats, const SkMatrix* localM,
149 const SkColorInfo& dst,
150 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) {
151 return sh ? as_SB(sh)->program(p, device,local, paint, mats,localM, dst, uniforms,alloc)
152 : p->premul(paint);
153 }
154
onProgram(skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const SkMatrixProvider & mats,const SkMatrix * localM,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const155 skvm::Color SkShader_Blend::onProgram(skvm::Builder* p,
156 skvm::Coord device, skvm::Coord local, skvm::Color paint,
157 const SkMatrixProvider& mats, const SkMatrix* localM,
158 const SkColorInfo& dst,
159 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
160 skvm::Color d,s;
161 if ((d = program_or_paint(fDst, p, device,local, paint, mats,localM, dst, uniforms,alloc)) &&
162 (s = program_or_paint(fSrc, p, device,local, paint, mats,localM, dst, uniforms,alloc)))
163 {
164 return p->blend(fMode, s,d);
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
as_fp(const GrFPArgs & args,SkShader * shader)175 static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) {
176 return shader ? as_SB(shader)->asFragmentProcessor(args) : nullptr;
177 }
178
asFragmentProcessor(const GrFPArgs & orig_args) const179 std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor(
180 const GrFPArgs& orig_args) const {
181 const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix());
182 auto fpA = as_fp(args, fDst.get());
183 auto fpB = as_fp(args, fSrc.get());
184 return GrBlendFragmentProcessor::Make(std::move(fpB), std::move(fpA), fMode);
185 }
186 #endif
187