blob: 873e0c05f5f15ba9048e94277333dc97753ad3cc [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/private/SkColorData.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040011#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/core/SkBlendModePriv.h"
13#include "src/core/SkRasterPipeline.h"
14#include "src/core/SkReadBuffer.h"
Mike Reed190b6e52020-03-14 16:42:56 -040015#include "src/core/SkVM.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkWriteBuffer.h"
17#include "src/shaders/SkColorShader.h"
18#include "src/shaders/SkComposeShader.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
Florin Malita9ab449a2019-07-09 13:22:50 -040020namespace {
21
Florin Malita9ab449a2019-07-09 13:22:50 -040022struct LocalMatrixStageRec final : public SkStageRec {
23 LocalMatrixStageRec(const SkStageRec& rec, const SkMatrix& lm)
24 : INHERITED(rec) {
25 if (!lm.isIdentity()) {
26 if (fLocalM) {
27 fStorage.setConcat(lm, *fLocalM);
28 fLocalM = fStorage.isIdentity() ? nullptr : &fStorage;
29 } else {
30 fLocalM = &lm;
31 }
32 }
33 }
34
35private:
36 SkMatrix fStorage;
37
38 using INHERITED = SkStageRec;
39};
40
41} // namespace
42
Kevin Lubick988ce042020-03-25 13:13:20 -040043sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
Florin Malita9ab449a2019-07-09 13:22:50 -040044 switch (mode) {
45 case SkBlendMode::kClear: return Color(0);
Kevin Lubick988ce042020-03-25 13:13:20 -040046 case SkBlendMode::kDst: return dst;
47 case SkBlendMode::kSrc: return src;
Florin Malita9ab449a2019-07-09 13:22:50 -040048 default: break;
49 }
Kevin Lubick988ce042020-03-25 13:13:20 -040050 return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src)));
Florin Malita9ab449a2019-07-09 13:22:50 -040051}
52
Kevin Lubick988ce042020-03-25 13:13:20 -040053sk_sp<SkShader> SkShaders::Lerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
Mike Reed9b2c4e92019-04-02 09:54:14 -040054 if (SkScalarIsNaN(weight)) {
Mike Reed7d954ad2016-10-28 15:42:34 -040055 return nullptr;
56 }
Florin Malita9ab449a2019-07-09 13:22:50 -040057 if (dst == src || weight <= 0) {
Kevin Lubick988ce042020-03-25 13:13:20 -040058 return dst;
Mike Reed7d954ad2016-10-28 15:42:34 -040059 }
Florin Malita9ab449a2019-07-09 13:22:50 -040060 if (weight >= 1) {
Kevin Lubick988ce042020-03-25 13:13:20 -040061 return src;
Mike Reed9b2c4e92019-04-02 09:54:14 -040062 }
Kevin Lubick988ce042020-03-25 13:13:20 -040063 return sk_sp<SkShader>(new SkShader_Lerp(weight, std::move(dst), std::move(src)));
Mike Reed7d954ad2016-10-28 15:42:34 -040064}
65
reed@google.com82065d62011-02-07 15:30:46 +000066///////////////////////////////////////////////////////////////////////////////
67
Mike Reed9b2c4e92019-04-02 09:54:14 -040068static bool append_shader_or_paint(const SkStageRec& rec, SkShader* shader) {
69 if (shader) {
70 if (!as_SB(shader)->appendStages(rec)) {
71 return false;
72 }
73 } else {
74 rec.fPipeline->append_constant_color(rec.fAlloc, rec.fPaint.getColor4f().premul().vec());
75 }
76 return true;
77}
78
79// Returns the output of e0, and leaves the output of e1 in r,g,b,a
80static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) {
81 struct Storage {
82 float fRes0[4 * SkRasterPipeline_kMaxStride];
83 };
84 auto storage = rec.fAlloc->make<Storage>();
85
86 if (!append_shader_or_paint(rec, s0)) {
87 return nullptr;
88 }
89 rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0);
90
91 if (!append_shader_or_paint(rec, s1)) {
92 return nullptr;
93 }
94 return storage->fRes0;
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
99sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) {
Mike Reed01b2b832017-06-09 10:51:52 -0400100 sk_sp<SkShader> dst(buffer.readShader());
101 sk_sp<SkShader> src(buffer.readShader());
102 unsigned mode = buffer.read32();
Mike Reed01b2b832017-06-09 10:51:52 -0400103
104 // check for valid mode before we cast to the enum type
Mike Reedc5166a92018-01-03 13:17:18 -0500105 if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700106 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700107 }
Mike Reedc8bea7d2019-04-09 13:55:36 -0400108 return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
reed9fa60da2014-08-21 07:59:51 -0700109}
110
Mike Reed9b2c4e92019-04-02 09:54:14 -0400111void SkShader_Blend::flatten(SkWriteBuffer& buffer) const {
Mike Reed01b2b832017-06-09 10:51:52 -0400112 buffer.writeFlattenable(fDst.get());
113 buffer.writeFlattenable(fSrc.get());
Mike Reed7d954ad2016-10-28 15:42:34 -0400114 buffer.write32((int)fMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115}
116
Florin Malita9ab449a2019-07-09 13:22:50 -0400117bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const {
118 const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix());
119
Mike Reed9b2c4e92019-04-02 09:54:14 -0400120 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
121 if (!res0) {
Mike Reed9959f722017-05-15 09:34:22 -0400122 return false;
123 }
Mike Reed5e398c22019-03-08 11:50:35 -0500124
Mike Reed9b2c4e92019-04-02 09:54:14 -0400125 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
126 SkBlendMode_AppendStages(fMode, rec.fPipeline);
127 return true;
128}
129
Mike Kleina68d9332020-06-30 15:17:28 -0500130static skvm::Color program_or_paint(const sk_sp<SkShader>& sh, skvm::Builder* p,
131 skvm::Coord device, skvm::Coord local, skvm::Color paint,
132 const SkMatrixProvider& mats, const SkMatrix* localM,
Mike Reed80468372021-03-19 14:05:19 -0400133 const SkColorInfo& dst,
Mike Kleina68d9332020-06-30 15:17:28 -0500134 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) {
Mike Reed80468372021-03-19 14:05:19 -0400135 return sh ? as_SB(sh)->program(p, device,local, paint, mats,localM, dst, uniforms,alloc)
Mike Kleina68d9332020-06-30 15:17:28 -0500136 : p->premul(paint);
137}
138
Brian Osman5aaaeea2020-06-22 14:26:03 -0400139skvm::Color SkShader_Blend::onProgram(skvm::Builder* p,
140 skvm::Coord device, skvm::Coord local, skvm::Color paint,
141 const SkMatrixProvider& mats, const SkMatrix* localM,
Mike Reed80468372021-03-19 14:05:19 -0400142 const SkColorInfo& dst,
Mike Klein276a7852020-03-15 08:46:09 -0500143 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
Mike Kleina434e0f2020-03-23 09:33:48 -0500144 skvm::Color d,s;
Mike Reed80468372021-03-19 14:05:19 -0400145 if ((d = program_or_paint(fDst, p, device,local, paint, mats,localM, dst, uniforms,alloc)) &&
146 (s = program_or_paint(fSrc, p, device,local, paint, mats,localM, dst, uniforms,alloc)))
Mike Reed6352f002020-03-14 23:30:10 -0400147 {
Mike Kleina434e0f2020-03-23 09:33:48 -0500148 return p->blend(fMode, s,d);
Mike Reed190b6e52020-03-14 16:42:56 -0400149 }
Mike Reed6352f002020-03-14 23:30:10 -0400150 return {};
Mike Reed190b6e52020-03-14 16:42:56 -0400151}
152
153
Mike Reed9b2c4e92019-04-02 09:54:14 -0400154sk_sp<SkFlattenable> SkShader_Lerp::CreateProc(SkReadBuffer& buffer) {
155 sk_sp<SkShader> dst(buffer.readShader());
156 sk_sp<SkShader> src(buffer.readShader());
157 float t = buffer.readScalar();
Mike Reedc8bea7d2019-04-09 13:55:36 -0400158 return buffer.isValid() ? SkShaders::Lerp(t, std::move(dst), std::move(src)) : nullptr;
Mike Reed9b2c4e92019-04-02 09:54:14 -0400159}
160
161void SkShader_Lerp::flatten(SkWriteBuffer& buffer) const {
162 buffer.writeFlattenable(fDst.get());
163 buffer.writeFlattenable(fSrc.get());
164 buffer.writeScalar(fWeight);
165}
166
Florin Malita9ab449a2019-07-09 13:22:50 -0400167bool SkShader_Lerp::onAppendStages(const SkStageRec& orig_rec) const {
168 const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix());
169
Mike Reed9b2c4e92019-04-02 09:54:14 -0400170 float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
171 if (!res0) {
Mike Reed5e398c22019-03-08 11:50:35 -0500172 return false;
173 }
Mike Reed9959f722017-05-15 09:34:22 -0400174
Mike Reed9b2c4e92019-04-02 09:54:14 -0400175 rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
176 rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fWeight);
Mike Reed9959f722017-05-15 09:34:22 -0400177 return true;
178}
commit-bot@chromium.org79590552014-05-13 18:14:45 +0000179
Brian Osman5aaaeea2020-06-22 14:26:03 -0400180skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p,
181 skvm::Coord device, skvm::Coord local, skvm::Color paint,
182 const SkMatrixProvider& mats, const SkMatrix* localM,
Mike Reed80468372021-03-19 14:05:19 -0400183 const SkColorInfo& dst,
Mike Klein276a7852020-03-15 08:46:09 -0500184 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
Mike Kleina434e0f2020-03-23 09:33:48 -0500185 skvm::Color d,s;
Mike Reed80468372021-03-19 14:05:19 -0400186 if ((d = program_or_paint(fDst, p, device,local, paint, mats,localM, dst, uniforms,alloc)) &&
187 (s = program_or_paint(fSrc, p, device,local, paint, mats,localM, dst, uniforms,alloc)))
Mike Reed6352f002020-03-14 23:30:10 -0400188 {
189 auto t = p->uniformF(uniforms->pushF(fWeight));
190 return {
Mike Kleina434e0f2020-03-23 09:33:48 -0500191 p->lerp(d.r, s.r, t),
192 p->lerp(d.g, s.g, t),
193 p->lerp(d.b, s.b, t),
194 p->lerp(d.a, s.a, t),
Mike Reed6352f002020-03-14 23:30:10 -0400195 };
Mike Reed190b6e52020-03-14 16:42:56 -0400196 }
Mike Reed6352f002020-03-14 23:30:10 -0400197 return {};
Mike Reed190b6e52020-03-14 16:42:56 -0400198}
199
wangyix73fa6162015-09-01 09:45:08 -0700200#if SK_SUPPORT_GPU
201
Robert Phillipsb7bfbc22020-07-01 12:55:01 -0400202#include "include/gpu/GrRecordingContext.h"
John Stilesf743d4e2020-07-23 11:35:08 -0400203#include "src/gpu/effects/GrBlendFragmentProcessor.h"
Brian Salomon5ca24f92021-03-23 17:04:41 -0400204#include "src/gpu/effects/GrSkSLFP.h"
Mike Reedc8bea7d2019-04-09 13:55:36 -0400205
206static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) {
Ethan Nicholasff4fb332019-04-09 16:28:19 -0400207 return shader ? as_SB(shader)->asFragmentProcessor(args) : nullptr;
Mike Reedc8bea7d2019-04-09 13:55:36 -0400208}
209
Florin Malita9ab449a2019-07-09 13:22:50 -0400210std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor(
211 const GrFPArgs& orig_args) const {
212 const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix());
Mike Reedc8bea7d2019-04-09 13:55:36 -0400213 auto fpA = as_fp(args, fDst.get());
214 auto fpB = as_fp(args, fSrc.get());
John Stilesf743d4e2020-07-23 11:35:08 -0400215 return GrBlendFragmentProcessor::Make(std::move(fpB), std::move(fpA), fMode);
wangyix73fa6162015-09-01 09:45:08 -0700216}
Mike Reed9b2c4e92019-04-02 09:54:14 -0400217
Florin Malita9ab449a2019-07-09 13:22:50 -0400218std::unique_ptr<GrFragmentProcessor> SkShader_Lerp::asFragmentProcessor(
219 const GrFPArgs& orig_args) const {
220 const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix());
Mike Reedc8bea7d2019-04-09 13:55:36 -0400221 auto fpA = as_fp(args, fDst.get());
222 auto fpB = as_fp(args, fSrc.get());
Brian Salomon5ca24f92021-03-23 17:04:41 -0400223
224 static constexpr char kCode[] = R"(
225 uniform shader a;
226 uniform shader b;
227 uniform half w;
228
229 half4 main() { return mix(sample(a), sample(b), w); }
230 )";
231
232 auto builder = GrRuntimeFPBuilder::Make<kCode>();
233 builder.uniform("w") = fWeight;
234 builder.child("a") = std::move(fpA);
235 builder.child("b") = std::move(fpB);
Brian Osman8ed80812021-04-13 15:09:14 -0400236 return builder.makeFP();
Mike Reedc8bea7d2019-04-09 13:55:36 -0400237}
wangyix73fa6162015-09-01 09:45:08 -0700238#endif