blob: 1d3bba625eaeb5b85d54b43c8602ea987d533ee3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkColorFilter.h"
9#include "include/core/SkString.h"
10#include "include/private/SkArenaAlloc.h"
11#include "include/private/SkColorData.h"
12#include "src/core/SkBlendModePriv.h"
13#include "src/core/SkRasterPipeline.h"
14#include "src/core/SkReadBuffer.h"
15#include "src/core/SkWriteBuffer.h"
16#include "src/shaders/SkColorShader.h"
17#include "src/shaders/SkComposeShader.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
Mike Reedc8bea7d2019-04-09 13:55:36 -040019sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
Mike Reed9b2c4e92019-04-02 09:54:14 -040020 switch (mode) {
Mike Reedc8bea7d2019-04-09 13:55:36 -040021 case SkBlendMode::kClear: return Color(0);
Mike Reed9b2c4e92019-04-02 09:54:14 -040022 case SkBlendMode::kDst: return dst;
23 case SkBlendMode::kSrc: return src;
24 default: break;
25 }
26 return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src)));
27}
28
Mike Reedc8bea7d2019-04-09 13:55:36 -040029sk_sp<SkShader> SkShaders::Lerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
Mike Reed9b2c4e92019-04-02 09:54:14 -040030 if (SkScalarIsNaN(weight)) {
Mike Reed7d954ad2016-10-28 15:42:34 -040031 return nullptr;
32 }
Mike Reed9b2c4e92019-04-02 09:54:14 -040033 if (dst == src) {
Mike Reed7d954ad2016-10-28 15:42:34 -040034 return dst;
35 }
Mike Reed9b2c4e92019-04-02 09:54:14 -040036 if (weight <= 0) {
37 return dst;
38 } else if (weight >= 1) {
39 return src;
40 }
41 return sk_sp<SkShader>(new SkShader_Lerp(weight, std::move(dst), std::move(src)));
Mike Reed7d954ad2016-10-28 15:42:34 -040042}
43
Mike Reedc8bea7d2019-04-09 13:55:36 -040044sk_sp<SkShader> SkShaders::Lerp(sk_sp<SkShader> red, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
45 if (!red) {
46 return nullptr;
47 }
48 if (dst == src) {
49 return dst;
50 }
51 return sk_sp<SkShader>(new SkShader_LerpRed(std::move(red), std::move(dst), std::move(src)));
52}
53
reed@google.com82065d62011-02-07 15:30:46 +000054///////////////////////////////////////////////////////////////////////////////
55
Mike Reed9b2c4e92019-04-02 09:54:14 -040056static bool append_shader_or_paint(const SkStageRec& rec, SkShader* shader) {
57 if (shader) {
58 if (!as_SB(shader)->appendStages(rec)) {
59 return false;
60 }
61 } else {
62 rec.fPipeline->append_constant_color(rec.fAlloc, rec.fPaint.getColor4f().premul().vec());
63 }
64 return true;
65}
66
67// Returns the output of e0, and leaves the output of e1 in r,g,b,a
68static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) {
69 struct Storage {
70 float fRes0[4 * SkRasterPipeline_kMaxStride];
71 };
72 auto storage = rec.fAlloc->make<Storage>();
73
74 if (!append_shader_or_paint(rec, s0)) {
75 return nullptr;
76 }
77 rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0);
78
79 if (!append_shader_or_paint(rec, s1)) {
80 return nullptr;
81 }
82 return storage->fRes0;
83}
84
85///////////////////////////////////////////////////////////////////////////////
86
87sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) {
Mike Reed01b2b832017-06-09 10:51:52 -040088 sk_sp<SkShader> dst(buffer.readShader());
89 sk_sp<SkShader> src(buffer.readShader());
90 unsigned mode = buffer.read32();
Mike Reed01b2b832017-06-09 10:51:52 -040091
92 // check for valid mode before we cast to the enum type
Mike Reedc5166a92018-01-03 13:17:18 -050093 if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
halcanary96fcdcc2015-08-27 07:41:13 -070094 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070095 }
Mike Reedc8bea7d2019-04-09 13:55:36 -040096 return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
reed9fa60da2014-08-21 07:59:51 -070097}
98
Mike Reed9b2c4e92019-04-02 09:54:14 -040099void SkShader_Blend::flatten(SkWriteBuffer& buffer) const {
Mike Reed01b2b832017-06-09 10:51:52 -0400100 buffer.writeFlattenable(fDst.get());
101 buffer.writeFlattenable(fSrc.get());
Mike Reed7d954ad2016-10-28 15:42:34 -0400102 buffer.write32((int)fMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103}
104
Mike Reed9b2c4e92019-04-02 09:54:14 -0400105bool SkShader_Blend::onAppendStages(const SkStageRec& rec) const {
106 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
107 if (!res0) {
Mike Reed9959f722017-05-15 09:34:22 -0400108 return false;
109 }
Mike Reed5e398c22019-03-08 11:50:35 -0500110
Mike Reed9b2c4e92019-04-02 09:54:14 -0400111 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
112 SkBlendMode_AppendStages(fMode, rec.fPipeline);
113 return true;
114}
115
116sk_sp<SkFlattenable> SkShader_Lerp::CreateProc(SkReadBuffer& buffer) {
117 sk_sp<SkShader> dst(buffer.readShader());
118 sk_sp<SkShader> src(buffer.readShader());
119 float t = buffer.readScalar();
Mike Reedc8bea7d2019-04-09 13:55:36 -0400120 return buffer.isValid() ? SkShaders::Lerp(t, std::move(dst), std::move(src)) : nullptr;
Mike Reed9b2c4e92019-04-02 09:54:14 -0400121}
122
123void SkShader_Lerp::flatten(SkWriteBuffer& buffer) const {
124 buffer.writeFlattenable(fDst.get());
125 buffer.writeFlattenable(fSrc.get());
126 buffer.writeScalar(fWeight);
127}
128
129bool SkShader_Lerp::onAppendStages(const SkStageRec& rec) const {
130 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
131 if (!res0) {
Mike Reed5e398c22019-03-08 11:50:35 -0500132 return false;
133 }
Mike Reed9959f722017-05-15 09:34:22 -0400134
Mike Reed9b2c4e92019-04-02 09:54:14 -0400135 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
136 rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fWeight);
Mike Reed9959f722017-05-15 09:34:22 -0400137 return true;
138}
commit-bot@chromium.org79590552014-05-13 18:14:45 +0000139
Mike Reedc8bea7d2019-04-09 13:55:36 -0400140sk_sp<SkFlattenable> SkShader_LerpRed::CreateProc(SkReadBuffer& buffer) {
141 sk_sp<SkShader> dst(buffer.readShader());
142 sk_sp<SkShader> src(buffer.readShader());
143 sk_sp<SkShader> red(buffer.readShader());
144 return buffer.isValid() ?
145 SkShaders::Lerp(std::move(red), std::move(dst), std::move(src)) : nullptr;
146}
147
148void SkShader_LerpRed::flatten(SkWriteBuffer& buffer) const {
149 buffer.writeFlattenable(fDst.get());
150 buffer.writeFlattenable(fSrc.get());
151 buffer.writeFlattenable(fRed.get());
152}
153
154bool SkShader_LerpRed::onAppendStages(const SkStageRec& rec) const {
155 struct Storage {
156 float fRed[4 * SkRasterPipeline_kMaxStride];
157 };
158 auto storage = rec.fAlloc->make<Storage>();
159 if (!as_SB(fRed)->appendStages(rec)) {
160 return false;
161 }
162 // actually, we just need the first (red) channel, but for now we store rgba
163 rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRed);
164
165 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
166 if (!res0) {
167 return false;
168 }
169
170 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
171 rec.fPipeline->append(SkRasterPipeline::lerp_native, &storage->fRed[0]);
172 return true;
173}
174
wangyix73fa6162015-09-01 09:45:08 -0700175#if SK_SUPPORT_GPU
176
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500177#include "include/private/GrRecordingContext.h"
178#include "src/gpu/effects/GrXfermodeFragmentProcessor.h"
179#include "src/gpu/effects/generated/GrComposeLerpEffect.h"
180#include "src/gpu/effects/generated/GrComposeLerpRedEffect.h"
181#include "src/gpu/effects/generated/GrConstColorProcessor.h"
Mike Reedc8bea7d2019-04-09 13:55:36 -0400182
183static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) {
Ethan Nicholasff4fb332019-04-09 16:28:19 -0400184 return shader ? as_SB(shader)->asFragmentProcessor(args) : nullptr;
Mike Reedc8bea7d2019-04-09 13:55:36 -0400185}
186
187std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor(const GrFPArgs& args) const {
188 auto fpA = as_fp(args, fDst.get());
189 auto fpB = as_fp(args, fSrc.get());
190 if (!fpA || !fpB) {
Mike Reed01b2b832017-06-09 10:51:52 -0400191 return nullptr;
192 }
Mike Reed01b2b832017-06-09 10:51:52 -0400193 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
194 std::move(fpA), fMode);
wangyix73fa6162015-09-01 09:45:08 -0700195}
Mike Reed9b2c4e92019-04-02 09:54:14 -0400196
197std::unique_ptr<GrFragmentProcessor> SkShader_Lerp::asFragmentProcessor(const GrFPArgs& args) const {
Mike Reedc8bea7d2019-04-09 13:55:36 -0400198 auto fpA = as_fp(args, fDst.get());
199 auto fpB = as_fp(args, fSrc.get());
Ethan Nicholasff4fb332019-04-09 16:28:19 -0400200 return GrComposeLerpEffect::Make(std::move(fpA), std::move(fpB), fWeight);
Mike Reedc8bea7d2019-04-09 13:55:36 -0400201}
202
203std::unique_ptr<GrFragmentProcessor> SkShader_LerpRed::asFragmentProcessor(const GrFPArgs& args) const {
204 auto fpA = as_fp(args, fDst.get());
205 auto fpB = as_fp(args, fSrc.get());
206 auto red = as_SB(fRed)->asFragmentProcessor(args);
Ethan Nicholasff4fb332019-04-09 16:28:19 -0400207 if (!red) {
Mike Reed9b2c4e92019-04-02 09:54:14 -0400208 return nullptr;
209 }
Ethan Nicholasff4fb332019-04-09 16:28:19 -0400210 return GrComposeLerpRedEffect::Make(std::move(fpA), std::move(fpB), std::move(red));
Mike Reed9b2c4e92019-04-02 09:54:14 -0400211}
wangyix73fa6162015-09-01 09:45:08 -0700212#endif