blob: 135f91d36255f551786b1a2bc080ba02d90a052f [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 Reed7d954ad2016-10-28 15:42:34 -040020sk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
21 SkBlendMode mode) {
22 if (!src || !dst) {
23 return nullptr;
24 }
25 if (SkBlendMode::kSrc == mode) {
26 return src;
27 }
28 if (SkBlendMode::kDst == mode) {
29 return dst;
30 }
31 return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode));
32}
33
reed@google.com82065d62011-02-07 15:30:46 +000034///////////////////////////////////////////////////////////////////////////////
35
reed60c9b582016-04-03 09:11:13 -070036sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
reed8a21c9f2016-03-08 18:50:00 -080037 sk_sp<SkShader> shaderA(buffer.readShader());
38 sk_sp<SkShader> shaderB(buffer.readShader());
Mike Reed7d954ad2016-10-28 15:42:34 -040039 SkBlendMode mode;
40 if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) {
41 sk_sp<SkXfermode> xfer = buffer.readXfermode();
42 mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver;
43 } else {
44 mode = (SkBlendMode)buffer.read32();
45 }
reed8a21c9f2016-03-08 18:50:00 -080046 if (!shaderA || !shaderB) {
halcanary96fcdcc2015-08-27 07:41:13 -070047 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070048 }
Mike Reed7d954ad2016-10-28 15:42:34 -040049 return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode);
reed9fa60da2014-08-21 07:59:51 -070050}
51
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000052void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
reed8a21c9f2016-03-08 18:50:00 -080053 buffer.writeFlattenable(fShaderA.get());
54 buffer.writeFlattenable(fShaderB.get());
Mike Reed7d954ad2016-10-28 15:42:34 -040055 buffer.write32((int)fMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000056}
57
Mike Klein2814d912017-05-10 12:35:51 -040058sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
59 return SkShader::MakeComposeShader(xformer->apply(fShaderA.get()),
60 xformer->apply(fShaderB.get()), fMode);
61}
62
commit-bot@chromium.org79590552014-05-13 18:14:45 +000063bool SkComposeShader::asACompose(ComposeRec* rec) const {
64 if (rec) {
Mike Reedfaba3712016-11-03 14:45:31 -040065 rec->fShaderA = fShaderA.get();
66 rec->fShaderB = fShaderB.get();
Mike Reed7d954ad2016-10-28 15:42:34 -040067 rec->fBlendMode = fMode;
commit-bot@chromium.org79590552014-05-13 18:14:45 +000068 }
69 return true;
70}
71
Florin Malita7d022e02017-05-15 15:06:39 -040072bool SkComposeShader::isRasterPipelineOnly() const {
Mike Reed3f511882017-06-02 22:18:38 -040073 return true;
Florin Malita7d022e02017-05-15 15:06:39 -040074}
75
Mike Reed9959f722017-05-15 09:34:22 -040076bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS,
77 SkArenaAlloc* alloc, const SkMatrix& ctm,
78 const SkPaint& paint, const SkMatrix* localM) const {
79 struct Storage {
Mike Reed9959f722017-05-15 09:34:22 -040080 float fRGBA[4 * SkJumper_kMaxStride];
81 float fAlpha;
82 };
83 auto storage = alloc->make<Storage>();
84
Florin Malita4aed1382017-05-25 10:38:07 -040085 if (!as_SB(fShaderB)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // SRC
Mike Reed9959f722017-05-15 09:34:22 -040086 return false;
87 }
88 // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
89 // since fShaderB will overwrite them.
90 pipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
Mike Klein5df94d52017-06-01 14:43:51 -040091
Florin Malita4aed1382017-05-25 10:38:07 -040092 if (!as_SB(fShaderA)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // DST
Mike Reed9959f722017-05-15 09:34:22 -040093 return false;
94 }
95 // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode
96 // so we have to shuttle them. If we had a stage the would load_into_dst, then we could
97 // reverse the two shader invocations, and avoid this move...
98 pipeline->append(SkRasterPipeline::move_src_dst);
99 pipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
100
101 // Idea: should time this, and see if it helps to have custom versions of the overflow modes
102 // that do their own clamping, avoiding the overhead of an extra stage.
103 SkBlendMode_AppendStages(fMode, pipeline);
104 if (SkBlendMode_CanOverflow(fMode)) {
105 pipeline->append(SkRasterPipeline::clamp_a);
106 }
107 return true;
108}
commit-bot@chromium.org79590552014-05-13 18:14:45 +0000109
wangyix73fa6162015-09-01 09:45:08 -0700110#if SK_SUPPORT_GPU
111
wangyix036fd8e2015-09-08 15:23:34 -0700112#include "effects/GrConstColorProcessor.h"
wangyix809e5af2015-09-09 12:58:32 -0700113#include "effects/GrXfermodeFragmentProcessor.h"
wangyix73fa6162015-09-01 09:45:08 -0700114
115/////////////////////////////////////////////////////////////////////
116
brianosman839345d2016-07-22 11:04:53 -0700117sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
Mike Reed7d954ad2016-10-28 15:42:34 -0400118 switch (fMode) {
119 case SkBlendMode::kClear:
Brian Osman618d3042016-10-25 10:51:28 -0400120 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
bungeman06ca8ec2016-06-09 08:01:03 -0700121 GrConstColorProcessor::kIgnore_InputMode);
wangyix73fa6162015-09-01 09:45:08 -0700122 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400123 case SkBlendMode::kSrc:
Florin Malita4aed1382017-05-25 10:38:07 -0400124 return as_SB(fShaderB)->asFragmentProcessor(args);
wangyix73fa6162015-09-01 09:45:08 -0700125 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400126 case SkBlendMode::kDst:
Florin Malita4aed1382017-05-25 10:38:07 -0400127 return as_SB(fShaderA)->asFragmentProcessor(args);
wangyix73fa6162015-09-01 09:45:08 -0700128 break;
129 default:
Florin Malita4aed1382017-05-25 10:38:07 -0400130 sk_sp<GrFragmentProcessor> fpA(as_SB(fShaderA)->asFragmentProcessor(args));
bungeman06ca8ec2016-06-09 08:01:03 -0700131 if (!fpA) {
wangyix73fa6162015-09-01 09:45:08 -0700132 return nullptr;
133 }
Florin Malita4aed1382017-05-25 10:38:07 -0400134 sk_sp<GrFragmentProcessor> fpB(as_SB(fShaderB)->asFragmentProcessor(args));
bungeman06ca8ec2016-06-09 08:01:03 -0700135 if (!fpB) {
wangyix73fa6162015-09-01 09:45:08 -0700136 return nullptr;
137 }
bungeman06ca8ec2016-06-09 08:01:03 -0700138 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
Mike Reed7d954ad2016-10-28 15:42:34 -0400139 std::move(fpA), fMode);
wangyix73fa6162015-09-01 09:45:08 -0700140 }
141}
142#endif
143
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000144#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000145void SkComposeShader::toString(SkString* str) const {
146 str->append("SkComposeShader: (");
147
148 str->append("ShaderA: ");
Florin Malita4aed1382017-05-25 10:38:07 -0400149 as_SB(fShaderA)->toString(str);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000150 str->append(" ShaderB: ");
Florin Malita4aed1382017-05-25 10:38:07 -0400151 as_SB(fShaderB)->toString(str);
Mike Reed7d954ad2016-10-28 15:42:34 -0400152 if (SkBlendMode::kSrcOver != fMode) {
Mike Reedcde90312017-06-07 23:05:45 -0400153 str->appendf(" Xfermode: %s", SkBlendMode_Name(fMode));
halcanary8464a962015-06-16 11:53:26 -0700154 }
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000155
156 this->INHERITED::toString(str);
157
158 str->append(")");
159}
160#endif