blob: 1eae163c9740ed4bdb3ee1aaac322eac8f2c5379 [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
Herb Derby83e939b2017-02-07 14:25:11 -05008#include "SkArenaAlloc.h"
Mike Reed9959f722017-05-15 09:34:22 -04009#include "SkBlendModePriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkComposeShader.h"
11#include "SkColorFilter.h"
12#include "SkColorPriv.h"
reed@google.com573f22b2011-11-30 19:17:15 +000013#include "SkColorShader.h"
Mike Reed9959f722017-05-15 09:34:22 -040014#include "SkRasterPipeline.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000015#include "SkReadBuffer.h"
16#include "SkWriteBuffer.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +000017#include "SkString.h"
Mike Reed9959f722017-05-15 09:34:22 -040018#include "../jumper/SkJumper.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
Mike Reed01b2b832017-06-09 10:51:52 -040020sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
21 float lerpT) {
22 if (!src || !dst || SkScalarIsNaN(lerpT)) {
Mike Reed7d954ad2016-10-28 15:42:34 -040023 return nullptr;
24 }
Mike Reed01b2b832017-06-09 10:51:52 -040025 lerpT = SkScalarPin(lerpT, 0, 1);
26
27 if (lerpT == 0) {
Mike Reed7d954ad2016-10-28 15:42:34 -040028 return dst;
Mike Reed01b2b832017-06-09 10:51:52 -040029 } else if (lerpT == 1) {
30 if (mode == SkBlendMode::kSrc) {
31 return src;
32 }
33 if (mode == SkBlendMode::kDst) {
34 return dst;
35 }
Mike Reed7d954ad2016-10-28 15:42:34 -040036 }
Mike Reed01b2b832017-06-09 10:51:52 -040037 return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
Mike Reed7d954ad2016-10-28 15:42:34 -040038}
39
reed@google.com82065d62011-02-07 15:30:46 +000040///////////////////////////////////////////////////////////////////////////////
41
reed60c9b582016-04-03 09:11:13 -070042sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
Mike Reed01b2b832017-06-09 10:51:52 -040043 sk_sp<SkShader> dst(buffer.readShader());
44 sk_sp<SkShader> src(buffer.readShader());
45 unsigned mode = buffer.read32();
Mike Reed70bc94f2017-06-08 12:45:52 -040046
Mike Reed01b2b832017-06-09 10:51:52 -040047 float lerp = 1;
48 if (!buffer.isVersionLT(SkReadBuffer::kComposeShaderCanLerp_Version)) {
49 lerp = buffer.readScalar();
50 }
51
52 // check for valid mode before we cast to the enum type
53 if (mode > (unsigned)SkBlendMode::kLastMode) {
halcanary96fcdcc2015-08-27 07:41:13 -070054 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070055 }
Mike Reed01b2b832017-06-09 10:51:52 -040056
57 return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp);
reed9fa60da2014-08-21 07:59:51 -070058}
59
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000060void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
Mike Reed01b2b832017-06-09 10:51:52 -040061 buffer.writeFlattenable(fDst.get());
62 buffer.writeFlattenable(fSrc.get());
Mike Reed7d954ad2016-10-28 15:42:34 -040063 buffer.write32((int)fMode);
Mike Reed01b2b832017-06-09 10:51:52 -040064 buffer.writeScalar(fLerpT);
reed@android.com8a1c16f2008-12-17 15:59:43 +000065}
66
Mike Klein2814d912017-05-10 12:35:51 -040067sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
Mike Reed01b2b832017-06-09 10:51:52 -040068 return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()),
69 fMode, fLerpT);
Mike Klein2814d912017-05-10 12:35:51 -040070}
71
Mike Reeda6aaa302017-06-09 10:29:40 -040072#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
commit-bot@chromium.org79590552014-05-13 18:14:45 +000073bool SkComposeShader::asACompose(ComposeRec* rec) const {
Mike Reed01b2b832017-06-09 10:51:52 -040074 if (!this->isJustMode()) {
75 return false;
76 }
77
commit-bot@chromium.org79590552014-05-13 18:14:45 +000078 if (rec) {
Mike Reed01b2b832017-06-09 10:51:52 -040079 rec->fShaderA = fDst.get();
80 rec->fShaderB = fSrc.get();
Mike Reed7d954ad2016-10-28 15:42:34 -040081 rec->fBlendMode = fMode;
commit-bot@chromium.org79590552014-05-13 18:14:45 +000082 }
83 return true;
84}
Mike Reeda6aaa302017-06-09 10:29:40 -040085#endif
commit-bot@chromium.org79590552014-05-13 18:14:45 +000086
Mike Reed9959f722017-05-15 09:34:22 -040087bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS,
88 SkArenaAlloc* alloc, const SkMatrix& ctm,
89 const SkPaint& paint, const SkMatrix* localM) const {
90 struct Storage {
Mike Reed9959f722017-05-15 09:34:22 -040091 float fRGBA[4 * SkJumper_kMaxStride];
92 float fAlpha;
93 };
94 auto storage = alloc->make<Storage>();
95
Mike Reed01b2b832017-06-09 10:51:52 -040096 if (!as_SB(fSrc)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) {
Mike Reed9959f722017-05-15 09:34:22 -040097 return false;
98 }
99 // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
100 // since fShaderB will overwrite them.
101 pipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
Mike Klein5df94d52017-06-01 14:43:51 -0400102
Mike Reed01b2b832017-06-09 10:51:52 -0400103 if (!as_SB(fDst)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) {
Mike Reed9959f722017-05-15 09:34:22 -0400104 return false;
105 }
Mike Reed01b2b832017-06-09 10:51:52 -0400106 // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode/lerp
Mike Reed9959f722017-05-15 09:34:22 -0400107 // so we have to shuttle them. If we had a stage the would load_into_dst, then we could
108 // reverse the two shader invocations, and avoid this move...
109 pipeline->append(SkRasterPipeline::move_src_dst);
110 pipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
111
Mike Reed01b2b832017-06-09 10:51:52 -0400112 if (!this->isJustLerp()) {
113 // Idea: should time this, and see if it helps to have custom versions of the overflow modes
114 // that do their own clamping, avoiding the overhead of an extra stage.
115 SkBlendMode_AppendStages(fMode, pipeline);
116 if (SkBlendMode_CanOverflow(fMode)) {
117 pipeline->append(SkRasterPipeline::clamp_a);
118 }
119 }
120 if (!this->isJustMode()) {
121 pipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT);
Mike Reed9959f722017-05-15 09:34:22 -0400122 }
123 return true;
124}
commit-bot@chromium.org79590552014-05-13 18:14:45 +0000125
wangyix73fa6162015-09-01 09:45:08 -0700126#if SK_SUPPORT_GPU
127
wangyix036fd8e2015-09-08 15:23:34 -0700128#include "effects/GrConstColorProcessor.h"
wangyix809e5af2015-09-09 12:58:32 -0700129#include "effects/GrXfermodeFragmentProcessor.h"
wangyix73fa6162015-09-01 09:45:08 -0700130
131/////////////////////////////////////////////////////////////////////
132
brianosman839345d2016-07-22 11:04:53 -0700133sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
Mike Reed01b2b832017-06-09 10:51:52 -0400134 if (this->isJustMode()) {
135 SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
136 if (fMode == SkBlendMode::kClear) {
Brian Osman618d3042016-10-25 10:51:28 -0400137 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
bungeman06ca8ec2016-06-09 08:01:03 -0700138 GrConstColorProcessor::kIgnore_InputMode);
Mike Reed01b2b832017-06-09 10:51:52 -0400139 }
wangyix73fa6162015-09-01 09:45:08 -0700140 }
Mike Reed01b2b832017-06-09 10:51:52 -0400141
142 sk_sp<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
143 if (!fpA) {
144 return nullptr;
145 }
146 sk_sp<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
147 if (!fpB) {
148 return nullptr;
149 }
150 // TODO: account for fLerpT when it is < 1
151 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
152 std::move(fpA), fMode);
wangyix73fa6162015-09-01 09:45:08 -0700153}
154#endif
155
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000156#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000157void SkComposeShader::toString(SkString* str) const {
158 str->append("SkComposeShader: (");
159
Mike Reed01b2b832017-06-09 10:51:52 -0400160 str->append("dst: ");
161 as_SB(fDst)->toString(str);
162 str->append(" src: ");
163 as_SB(fSrc)->toString(str);
164 str->appendf(" mode: %s", SkBlendMode_Name(fMode));
165 str->appendf(" lerpT: %g", fLerpT);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000166
167 this->INHERITED::toString(str);
168
169 str->append(")");
170}
171#endif